Python模块和包

目录

导入模块,Python import用法

import 模块名 as 别名

from  模块名 import 成员名 as 别名

不推荐使用 from import 导入模块所有成员

自定义模块

自定义模块编写说明文档

导入模块的3种方式

导入模块方式一:临时添加模块完整路径

导入模块方式二:将模块保存到指定位置

导入模块方式三:设置环境变量

__all__变量用法

包(存放多个模块的文件夹)

创建包,导入包

包的导入

查看模块(变量、函数、类)方法

查看模块成员:dir()函数

查看模块成员:__all__变量

__doc__属性:查看文档

__file__属性:查看模块的源文件路径


可以使用很多模块(如 string、sys、os 等),通过向程序中导入这些模块,我们可以使用很多“现成”的函数实现想要的功能。

Python 提供了强大的模块支持,主要体现在,不仅 Python 标准库中包含了大量的模块(称为标准模块),还有大量的第三方模块,开发者自己也可以开发自定义模块。通过这些强大的模块可以极大地提高开发者的开发效率。

在同目录下(桌面也可以)创建一个名为 hello.py 文件,其包含的代码如下:

def say ():
    print("Hello,World!")

在同一目录下,再创建一个 say.py 文件,其包含的代码如下:

#通过 import 关键字,将 hello.py 模块引入此文件
import hello
hello.say()

结果:
Hello,World!

可以注意到,say.py 文件中使用了原本在 hello.py 文件中才有的 say() 函数,相对于 day.py 来说,hello.py 就是一个自定义的模块(有关自定义模块,后续章节会做详细讲解),我们只需要将 hellp.py 模块导入到 say.py 文件中,就可以直接在 say.py 文件中使用模块中的资源。

导入模块,Python import用法

有些功能没必须自己实现,可以借助 Python 现有的标准库或者其他人提供的第三方库。

import 更多详细的用法,主要有以下两种:

  1. import 模块名1 [as 别名1], 模块名2 [as 别名2],…:使用这种语法格式的 import 语句,会导入指定模块中的所有成员(包括变量、函数、类等)。不仅如此,当需要使用模块中的成员时,需用该模块名(或别名)作为前缀,否则 Python 解释器会报错。
  2. from 模块名 import 成员名1 [as 别名1],成员名2 [as 别名2],…:使用这种语法格式的 import 语句,只会导入模块中指定的成员,而不是全部成员。同时,当程序中使用该成员时,无需附加任何前缀,直接使用成员名(或别名)即可。

注意,用 [] 括起来的部分,可以使用,也可以省略。

其中,第二种 import 语句也可以导入指定模块中的所有成员,即使用 form 模块名 import *,但此方式不推荐使用,具体原因本节后续会做详细说明。

import 模块名 as 别名

下面程序使用导入整个模块的最简单语法来导入指定模块:

# 导入sys整个模块
import sys

# 使用sys模块名作为前缀来访问模块中的成员
print(sys.argv[0])

结果:
D:/PycharmProjects/pythonProject/main.py

上面第 2 行代码使用最简单的方式导入了 sys 模块,因此在程序中使用 sys 模块内的成员时,必须添加模块名作为前缀。

运行上面程序,可以看到如下输出结果(sys 模块下的 argv 变量用于获取运行 Python 程序的命令行参数,其中 argv[0] 用于获取当前 Python 程序的存储路径):

导入整个模块时,也可以为模块指定别名。例如如下程序:

# 导入sys整个模块,并指定别名为s
import sys as s

# 使用s模块别名作为前缀来访问模块中的成员
print(s.argv[0])

结果:
D:/PycharmProjects/pythonProject/main.py

也可以一次导入多个模块,多个模块之间用逗号隔开。例如如下程序:

# 导入sys、os两个模块
import sys,os

# 使用模块名作为前缀来访问模块中的成员
print(sys.argv[0])

# os模块的sep变量代表平台上的路径分隔符
print(os.sep)

结果:
D:\PycharmProjects\pythonProject\venv\Scripts\python.exe D:/PycharmProjects/pythonProject/main.py
D:/PycharmProjects/pythonProject/main.py
\

上面第 2 行代码一次导入了 sys 和 os 两个模块,因此程序要使用 sys、os 两个模块内的成员,只要分别使用 sys、os 模块名作为前缀即可。

from  模块名 import 成员名 as 别名

下面程序使用了 from...import 最简单的语法来导入指定成员:

# 导入sys模块的argv成员
from sys import argv

# 使用导入成员的语法,直接使用成员名访问
print(argv[0])

结果:
D:\PycharmProjects\pythonProject\venv\Scripts\python.exe D:/PycharmProjects/pythonProject/main.py
D:/PycharmProjects/pythonProject/main.py

form...import 导入模块成员时,支持一次导入多个成员,例如如下程序:

# 导入sys模块的argv,winver成员
from sys import argv, winver

# 使用导入成员的语法,直接使用成员名访问
print(argv[0])
print(winver)

结果:
D:\PycharmProjects\pythonProject\venv\Scripts\python.exe D:/PycharmProjects/pythonProject/main.py
D:/PycharmProjects/pythonProject/main.py
3.7

一次导入多个模块成员时,也可指定别名,同样使用 as 关键字为成员指定别名,例如如下程序:

# 导入sys模块的argv,winver成员,并为其指定别名v、wv
from sys import argv as v, winver as wv

# 使用导入成员(并指定别名)的语法,直接使用成员的别名访问
print(v[0])
print(wv)

结果:
D:\PycharmProjects\pythonProject\venv\Scripts\python.exe D:/PycharmProjects/pythonProject/main.py
D:/PycharmProjects/pythonProject/main.py
3.7

上面第 2 行代码导入了 sys 模块中的 argv、winver 成员,并分别为它们指定了别名 v、wv,这样即可在程序中通过 v 和 wv 两个别名使用 argv、winver 成员,无须使用任何前缀。

不推荐使用 from import 导入模块所有成员

在使用 from...import 语法时,可以一次导入指定模块内的所有成员(此方式不推荐),例如如下程序:

#导入sys 棋块内的所有成员
from sys import *

#使用导入成员的语法,直接使用成员的别名访问
print(argv[0])
print(winver)

结果:
D:\PycharmProjects\pythonProject\venv\Scripts\python.exe D:/PycharmProjects/pythonProject/main.py
D:/PycharmProjects/pythonProject/main.py
3.7

上面代码一次导入了 sys 模块中的所有成员,这样程序即可通过成员名来使用该模块内的所有成员。该程序的输出结果和前面程序的输出结果完全相同。

需要说明的是,一般不推荐使用“from 模块 import”这种语法导入指定模块内的所有成员,因为它存在潜在的风险。比如同时导入 module1 和 module2 内的所有成员,假如这两个模块内都有一个 foo() 函数,调用的这个 foo() 函数到底是 module1 模块中的还是 module2 模块中的?因此,这种导入指定模块内所有成员的用法是有风险的。

但如果换成如下两种导入方式:

import module1
import module2 as m2

或者使用 from...import 语句也是可以的:

#导入module1 中的foo 成员,并指定其别名为foo1
from module1 import foo as fool

#导入module2 中的foo 成员,并指定其别名为foo2
from module2 import foo as foo2

自定义模块

Python 模块就是 Python 程序,换句话说,只要是 Python 程序,都可以作为模块导入。

自定义模块编写说明文档

在定义函数或者类时,可以为其添加说明文档,以方便用户清楚的知道该函数或者类的功能。自定义模块也不例外。

为自定义模块添加说明文档,和函数或类的添加方法相同,即只需在模块开头的位置定义一个字符串即可。

"""
name 为名字
age 为年龄

"""
name = "Mr.Hu"
age = "18"
print(name,age)
def say():
    print("你好呀!")
class Test:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def say(self):
        print(self.name,self.age)

if __name__ == '__main__':
    say()
    t = Test("Hello","My World")
    t.say()

在此基础上,我们可以通过模板的 __doc__ 属性,来访问模板的说明文档。

import demo
print(demo.__doc__)

导入模块的3种方式

通常情况下,当使用 import 语句导入模块后,Python 会按照以下顺序查找指定的模块文件:

  • 在当前目录,即当前执行的程序文件所在目录下查找;
  • 到 PYTHONPATH(环境变量)下的每个目录中查找;
  • 到 Python 默认的安装目录下查找。

以上所有涉及到的目录,都保存在标准模块 sys 的 sys.path 变量中,通过此变量我们可以看到指定程序文件支持查找的所有目录。

换句话说,如果要导入的模块没有存储在 sys.path 显示的目录中,那么导入该模块并运行程序时,Python 解释器就会抛出 ModuleNotFoundError(未找到模块)异常。

解决“Python找不到指定模块”的方法有 3 种,分别是:

  1. 向 sys.path 中临时添加模块文件存储位置的完整路径;
  2. 将模块放在 sys.path 变量中已包含的模块加载路径中;
  3. 设置 path 系统环境变量。

导入模块方式一:临时添加模块完整路径

模块文件的存储位置,可以临时添加到 sys.path 变量中,即向 sys.path 中添加模块地址: D:\python_module(hello.py 所在目录),在 应用模块的文件中:say.py 中的开头位置添加如下代码:

import sys
sys.path.append('D:\\python_module')

注意:在添加完整路径中,路径中的 '\' 需要使用 \ 进行转义,否则会导致语法错误。再次运行 say.py 文件,运行结果如下:

需要注意的是,通过该方法添加的目录,只能在执行当前文件的窗口中有效,窗口关闭后即失效。

导入模块方式二:将模块保存到指定位置

如果要安装某些通用性模块,比如复数功能支持的模块、矩阵计算支持的模块、图形界面支持的模块等,这些都属于对 Python 本身进行扩展的模块,这种模块应该直接安装在 Python 内部,以便被所有程序共享,此时就可借助于 Python 默认的模块加载路径。

import sys

print(sys.path)

结果:
D:\PycharmProjects\pythonProject\venv\Scripts\python.exe D:/PycharmProjects/pythonProject/main.py
['D:\\PycharmProjects\\pythonProject', 'D:\\PycharmProjects\\pythonProject', 'D:\\JetBrains\\Toolbox\\apps\\PyCharm-P\\ch-0\\203.6682.179\\plugins\\python\\helpers\\pycharm_display', 'C:\\Users\\HuYoo\\AppData\\Local\\Programs\\Python\\Python37\\python37.zip', 'C:\\Users\\HuYoo\\AppData\\Local\\Programs\\Python\\Python37\\DLLs', 'C:\\Users\\HuYoo\\AppData\\Local\\Programs\\Python\\Python37\\lib', 'C:\\Users\\HuYoo\\AppData\\Local\\Programs\\Python\\Python37', 'D:\\PycharmProjects\\pythonProject\\venv', 'D:\\PycharmProjects\\pythonProject\\venv\\lib\\site-packages', 'D:\\JetBrains\\Toolbox\\apps\\PyCharm-P\\ch-0\\203.6682.179\\plugins\\python\\helpers\\pycharm_matplotlib_backend']

上面的运行结果中,列出的所有路径都是 Python 默认的模块加载路径,但通常来说,我们默认将 Python 的扩展模块添加在 lib\site-packages 路径下,它专门用于存放 Python 的扩展模块和包。

所以,我们可以直接将我们已编写好的 hello.py 文件添加到 lib\site-packages 路径下,就相当于为 Python 扩展了一个 hello 模块,这样任何 Python 程序都可使用该模块。

导入模块方式三:设置环境变量

PYTHONPATH 环境变量(简称 path 变量)的值是很多路径组成的集合,Python 解释器会按照 path 包含的路径进行一次搜索,直到找到指定要加载的模块。当然,如果最终依旧没有找到,则 Python 就报 ModuleNotFoundError 异常。

首先,找到桌面上的“计算机”(或者我的电脑),并点击鼠标右键,单击“属性”。此时会显示“控制面板\所有控制面板项\系统”窗口,单击该窗口左边栏中的“高级系统设置”菜单,出现“系统属性”对话框,

点击“环境变量”按钮,这里我们选择设置当前用户的 path 变量。单击用户变量中的“新建”按钮。

其中,在“变量名”文本框内输入 PYTHONPATH,表明将要建立名为 PYTHONPATH 的环境变量;在“变量值”文本框内输入 .;d:\python_ module。注意,这里其实包含了两条路径(以分号 ;作为分隔符):

  • 第一条路径为一个点(.),表示当前路径,当运行 Python 程序时,Python 将可以从当前路径加载模块;
  • 第二条路径为 d:\python_ module,当运行 Python 程序时,Python 将可以从 d:\python_ module 中加载模块。

然后点击“确定”,即成功设置 path 环境变量。此时,我们只需要将模块文件移动到和引入该模块的文件相同的目录,或者移动到 d:\python_ module 路径下,该模块就能被成功加载。

__all__变量用法

事实上,当我们向文件导入某个模块时,导入的其实是该模块中那些名称不以下划线(单下划线“_”或者双下划线“__”)开头的变量、函数和类。

因此,如果我们不想模块文件中的某个成员被引入到其它文件中使用,可以在其名称前添加下划线。

_xxxxx() 或者 __xxxxx()

除此之外,还可以借助模块提供的 __all__ 变量,该变量的值是一个列表,存储的是当前模块中一些成员(变量、函数或者类)的名称。通过在模块文件中设置 __all__ 变量,当其它文件以“from 模块名 import *”的形式导入该模块时,该文件中只能使用 __all__ 列表中指定的成员。

也就是说,只有以“from 模块名 import *”形式导入的模块,当该模块设有 __all__ 变量时,只能导入该变量指定的成员,未指定的成员是无法导入的。

def say():
    print("Hello!")
def name():
    print("My name XiaoMing")
def display():
    print("你好")
__all__ = ["say","name"]

可见,__all__ 变量只包含 say() 和 name() 的函数名,不包含 display() 函数的名称。此时直接执行  test.py 文件,其执行结果为:

Hello!
My name XiaoMing
Traceback (most recent call last):
  File "C:/Users/mengma/Desktop/2.py", line 4, in 
    display()
NameError: name 'display' is not defined

对于 test.py 文件来说,demo.py 模块中的 disPython() 函数是未引入,这样调用是非法的。
再次声明,__all__ 变量仅限于在其它文件中以“from 模块名 import *”的方式引入。也就是说,如果使用以下 2 种方式引入模块,则 __all__ 变量的设置是无效的。

1) 以“import 模块名”的形式导入模块。通过该方式导入模块后,总可以通过模块名前缀(如果为模块指定了别名,则可以使用模快的别名作为前缀)来调用模块内的所有成员(除了以下划线开头命名的成员)。

2) 以“from 模块名 import 成员”的形式直接导入指定成员。使用此方式导入的模块,__all__ 变量即便设置,也形同虚设。

包(存放多个模块的文件夹)

一个大型的项目往往需要使用成百上千的 Python 模块,如果将这些模块都堆放在一起,势必不好管理。Python提出了包(Package)的概念。

包就是文件夹,只不过在该文件夹下存在一个名为“__init__.py” 的文件。

注意,这是 Python 2.x 的规定,而在 Python 3.x 中,__init__.py 对包来说,并不是必须的。

每个包的目录下都建立一个 __init__.py 的模块,可以是一个空模块,可以写一些初始化代码,其作用就是告诉 Python 要将该目录当成包来处理。

注意,__init__.py 不同于其他模块文件,此模块的模块名不是 __init__,而是它所在的包名。例如,在 settings 包中的 __init__.py 文件,其模块名就是 settings。

包是一个包含多个模块的文件夹,它的本质依然是模块,因此包中也可以包含包。例如,在前面章节中,我们安装了 numpy 模块之后可以在 Lib\site-packages 安装目录下找到名为 numpy 的文件夹,它就是安装的 numpy 模块(其实就是一个包),它所包含的内容如图 1 所示。



图 1 numpy包(模块)


从图 1 可以看出,在 numpy 包(模块)中,有必须包含的 __init__.py 文件,还有 matlib.py 等模块源文件以及 core 等子包(也是模块)。这正印证了我们刚刚讲过的,包的本质依然是模块,包可以包含包。

Python 库:相比模块和包,库是一个更大的概念,例如在 Python 标准库中的每个库都有好多个包,而每个包中都有若干个模块。

创建包,导入包

想手动创建一个包,只需进行以下 2 步操作:

  1. 新建一个文件夹,文件夹的名称就是新建包的包名;
  2. 在该文件夹中,创建一个 __init__.py 文件(前后各有 2 个下划线‘_’),该文件中可以不编写任何代码。当然,也可以编写一些 Python 初始化代码,则当有其它程序文件导入包时,会自动执行该文件中的代码(本节后续会有实例)。

例如,现在我们创建一个非常简单的包,该包的名称为 my_package,可以仿照以上 2 步进行:

  1. 创建一个文件夹,其名称设置为 my_package;
  2. 在该文件夹中添加一个 __init__.py 文件,此文件中可以不编写任何代码。不过,这里向该文件编写如下代码:
'''
创建第一个 Python 包
'''
print('Hello World!')

可以看到,__init__.py 文件中,包含了 2 部分信息,分别是此包的说明信息和一条 print 输出语句。

由此,我们就成功创建好了一个 Python 包。

创建好包之后,我们就可以向包中添加模块(也可以添加包)。这里给 my_package 包添加 2 个模块,分别是 module1.py、module2.py,各自包含的代码分别如下所示:

#module1.py模块文件
def display(arc):
    print(arc)

#module2.py 模块文件
class Test:
    def display(self):
        print("display")

现在,我们就创建好了一个具有如下文件结构的包:

my_package
     ┠── __init__.py
     ┠── module1.py
     ┗━━  module2.py

当然,包中还有容纳其它的包。

包的导入

通过前面的学习我们知道,包其实本质上还是模块,因此导入模块的语法同样也适用于导入包。无论导入我们自定义的包,还是导入从他处下载的第三方包,导入方法可归结为以下 3 种:

  1. import 包名[.模块名 [as 别名]]
  2. from 包名 import 模块名 [as 别名]
  3. from 包名.模块名 import 成员名 [as 别名]

用 [] 括起来的部分,是可选部分,即可以使用,也可以直接忽略。

注意,导入包的同时,会在包目录下生成一个含有 __init__.cpython-36.pyc 文件的 __pycache__ 文件夹。

1) import 包名[.模块名 [as 别名]]

以前面创建好的 my_package 包为例,导入 module1 模块并使用该模块中成员可以使用如下代码:

import page.module1 as mo1
import page.module2

mo1.display("Hello")
t = page.module2.Test()
t.display()

结果:
Hello World!
Hello
display

另外,当直接导入指定包时,程序会自动执行该包所对应文件夹下的 __init__.py 文件中的代码。例如:

import page

page.module1.display("Hello")

结果:
Traceback (most recent call last):
  File "D:/PycharmProjects/pythonProject/main.py", line 3, in 
    page.module1.display("Hello")
AttributeError: module 'page' has no attribute 'module1'
Hello World!

直接导入包名,并不会将包中所有模块全部导入到程序中,它的作用仅仅是导入并执行包下的 __init__.py 文件,因此,运行该程序,在执行 __init__.py 文件中代码的同时,还会抛出 AttributeError 异常(访问的对象不存在)

我们知道,包的本质就是模块,导入模块时,当前程序中会包含一个和模块名同名且类型为 module 的变量,导入包也是如此:

import page

print(page)
print(page.__doc__)
print(type(page))

结果:
Hello World!


创建第一个 Python 包

2) from 包名 import 模块名 [as 别名]

from page import module1 as m1

m1.display("Hello")

结果:
Hello World!
Hello

3) from 包名.模块名 import 成员名 [as 别名]

from page.module1 import display

display("Hello")

结果:
Hello World!
Hello

另外,在使用此种语法格式加载指定包的指定模块时,可以使用 * 代替成员名,表示加载该模块下的所有成员。例如:

from page.module1 import *
display("Hello")

结果:
Hello World!
Hello

查看模块(变量、函数、类)方法

查看模块成员:dir()函数

通过 dir() 函数,我们可以查看某指定模块包含的全部成员(包括变量、函数和类)。

注意这里所指的全部成员,不仅包含可供我们调用的模块成员,还包含所有名称以双下划线“__”开头和结尾的成员,

而这些“特殊”命名的成员,是为了在本模块中使用的,并不希望被其它文件调用。

这里以导入 string 模块为例,string 模块包含操作字符串相关的大量方法,下面通过 dir() 函数查看该模块中包含哪些成员:

import string
print(dir(string))

结果:
['Formatter', 'Template', '_ChainMap', '_TemplateMetaclass', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_re', '_string', 'ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'capwords', 'digits', 'hexdigits', 'octdigits', 'printable', 'punctuation', 'whitespace']

这里推荐一种可以忽略显示 dir() 函数输出的特殊成员的方法。仍以 string 模块为例:

import string
print([e for e in dir(string) if not e.startswith('_')])

结果:
['Formatter', 'Template', 'ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'capwords', 'digits', 'hexdigits', 'octdigits', 'printable', 'punctuation', 'whitespace']

显然通过列表推导式,可在 dir() 函数输出结果的基础上,筛选出对我们有用的成员并显示出来。

查看模块成员:__all__变量

除了使用 dir() 函数之外,还可以使用 __all__ 变量,借助该变量也可以查看模块(包)内包含的所有成员。

import string
print(string.__all__)

结果:
['ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'capwords', 'digits', 'hexdigits', 'octdigits', 'printable', 'punctuation', 'whitespace', 'Formatter', 'Template']

显然,和 dir() 函数相比,__all__ 变量在查看指定模块成员时,它不会显示模块中的特殊成员,同时还会根据成员的名称进行排序显示。

不过需要注意的是,并非所有的模块都支持使用 __all__ 变量,因此对于获取有些模块的成员,就只能使用 dir() 函数。

__doc__属性:查看文档

我们使用 help() 函数来查看这些成员的具体含义。

import page
help(page.module1)

如果使用 help() 函数或者 __doc__ 属性,仍然无法满足我们的需求,还可以使用以下 2 种方法:

  1. 调用 __file__ 属性,查看该模块或者包文件的具体存储位置,直接查看其源代码(后续章节或详细介绍);
  2. 对于非自定义的模块或者包.

__file__属性:查看模块的源文件路径

当指定模块(或包)没有说明文档时,仅通过 help() 函数或者 __doc__ 属性,无法有效帮助我们理解该模块(包)的具体功能。在这种情况下,我们可以通过 __file__ 属性查找该模块(或包)文件所在的具体存储位置,直接查看其源代码。

import page
print(page.__file__)

结果:
Hello World!
D:\PycharmProjects\pythonProject\page\__init__.py

由此,通过调用 __file__ 属性输出的绝对路径,我们可以很轻易地找到该模块(或包)的源文件。

注意,并不是所有模块都提供 __file__ 属性,因为并不是所有模块的实现都采用 Python 语言,有些模块采用的是其它编程语言(如 C 语言)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(◍',Python,'◍,python,编程语言)