本文介绍如何创建和使用 Python 模块,模块是一个包含 Python 代码的文件,Python 模块具有.py
扩展名。
可以使用以下方法管理 Python 代码:
- 职能
- 类
- 模组
- 包装
Python 模块用于组织 Python 代码。 例如,与数据库相关的代码位于数据库模块内部,安全代码位于安全模块中,等等。较小的 Python 脚本可以具有一个模块。 但是较大的程序分为几个模块。 模块组合在一起形成包装。
Python 模块名称
模块名称是带有.py
扩展名的文件名。 当我们有一个名为empty.py
的文件时,模块名称为空。 __name__
是一个变量,其中包含要引用的模块的名称。 当前模块,正在执行的模块(也称为主模块)有一个特殊名称:'__main__'
。 使用此名称,可以从 Python 代码中引用它。
当前工作目录中有两个文件:empty.py
和test_empty.py
。 第二个模块是执行的主模块。 导入第一个模块。 使用import
关键字导入模块。
empty.py
"""
An empty module
"""
这是empty.py
模块。
test_empty.py
#!/usr/bin/env python
import empty
import sys
print(__name__)
print(empty.__name__)
print(sys.__name__)
在此代码示例中,我们导入两个模块:内置模块sys
和一个自定义模块empty
。 我们将模块的名称打印到控制台。
$ ./test_empty.py
__main__
empty
sys
正在执行的模块的名称始终为'__main__'
。 其他模块以文件名命名。 可以使用import
关键字将模块导入其他模块。
Python 定位模块
导入模块时,解释器首先搜索具有该名称的内置模块。 如果找不到,它将在变量sys.path
给定的目录列表中搜索。 sys.path
是一个字符串列表,用于指定模块的搜索路径。 它由当前工作目录,在PYTHONPATH
环境变量中指定的目录名称以及一些其他与安装有关的目录组成。 如果找不到该模块,则会引发ImportError
。
locating_modules.py
#!/usr/bin/env python
import sys
import textwrap
sp = sorted(sys.path)
dnames = ', '.join(sp)
print(textwrap.fill(dnames))
该脚本从sys.path
变量打印所有目录。
import textwrap
textwrap
模块用于轻松设置段落格式。
sp = sorted(sys.path)
我们从sys.path
变量中检索目录列表并对它们进行排序。
dnames = ', '.join(sp)
我们从列表中取出一个字符串。
$ ./locating_modules.py
/home/janbodnar/.local/lib/python3.5/site-packages,
/home/janbodnar/PycharmProjects/Simple,
/home/janbodnar/PycharmProjects/Simple, /usr/lib/python3.5,
/usr/lib/python3.5/lib-dynload, /usr/lib/python3.5/plat-x86_64-linux-
gnu, /usr/lib/python3/dist-packages, /usr/lib/python35.zip,
/usr/local/lib/python3.5/dist-packages
Python 导入关键字
import
关键字可以以多种方式使用。
from module import *
此构造会将所有 Python 定义导入另一个模块的名称空间。 有一个例外。 不导入以下划线字符_
开头的对象。 预期它们只能由导入的模块在内部使用。 不建议使用这种方式导入模块。
everything.py
#!/usr/bin/python
from math import *
print(cos(3))
print(pi)
此导入构造已从内置math
模块导入了所有定义。 我们可以直接调用数学函数,而无需引用math
模块。
$ ./everything.py
-0.9899924966004454
3.141592653589793
使用此导入构造可能会导致名称空间污染。 我们可能有多个同名的对象,并且它们的定义可以被覆盖。
pollution.py
#!/usr/bin/env python
from math import *
pi = 3.14
print(cos(3))
print(pi)
该示例将在控制台上打印 3.14。 这可能不是我们想要的。 在大型项目中,命名空间污染可能变得至关重要。
未导入的 Python 对象
以下示例显示了未使用此import
构造导入的定义。
names.py
#!/usr/bin/env python
"""
names is a test module
"""
_version = 1.0
names = ["Paul", "Frank", "Jessica", "Thomas", "Katherine"]
def show_names():
for i in names:
print(i)
def _show_version():
print(_version)
这是names.py
模块。
test_names.py
#!/usr/bin/env python
from names import *
print(locals())
show_names()
_version
变量和_show_version()
功能未导入到test_names
模块中。 我们在命名空间中看不到它们。 locals()
函数为我们提供了模块中所有可用的定义。
导入特定对象
使用from
和import
关键字,可以仅导入某些对象。
from module import fun, var
此导入构造仅从模块导入特定对象。 这样,我们仅导入我们需要的定义。
import_specific.py
#!/usr/bin/python
from math import sin, pi
print(sin(3))
print(pi)
我们从math
模块导入两个对象。 我们无法引用其他定义(例如 cos 函数)。
imnames.py
#!/usr/bin/python
from names import _version, _show_version
print(_version)
_show_version()
我们也可以导入下划线开头的定义。 但这是一个不好的做法。
$ ./imnames.py
1.0
1.0
Python 导入模块
最后一种构造使用最广泛。
import module
它防止名称空间污染,并允许从模块访问所有定义。
impmod.py
#!/usr/bin/env python
import math
pi = 3.14
print(math.cos(3))
print(math.pi)
print(math.sin(3))
print(pi)
在这种情况下,我们通过模块名称引用定义。 如我们所见,我们可以使用两个 pi 变量。 我们的定义来自math
模块。
$ ./impmod.py
-0.9899924966004454
3.141592653589793
0.1411200080598672
3.14
Python 别名模块
我们可以使用as
关键字为模块创建别名。
importas.py
#!/usr/bin/python
# importas.py
import math as m
print(m.pi)
print(m.cos(3))
我们可以更改引用模块的名称。 为此,我们使用as
关键字。
$ ./importas.py
3.14159265359
-0.9899924966
ImportError
如果无法导入模块,则会引发ImportError
。
importerror.py
#!/usr/bin/env python
try:
import empty2
except ImportError as e:
print('Failed to import:', e)
我们尚未创建empty2
模块。 因此引发了异常。
$ ./importerror.py
Failed to import: No module named empty2
执行 Python 模块
模块可以导入其他模块,也可以执行。 模块作者经常创建测试套件来测试模块。 仅当模块作为脚本执行时,__name__
属性等于'__main__'
。
我们将在斐波那契模块上对此进行演示。 斐波那契数是一个数字序列,其中每个数字都是其两个直接前辈的总和。
fibonacci.py
#!/usr/bin/env python
"""
A module containing the fibonacci
function.
"""
def fib(n):
a, b = 0, 1
while b < n:
print(b, end=" ")
(a, b) = (b, a + b)
# testing
if __name__ == '__main__':
fib(500)
通常可以照常导入该模块。 该模块也可以执行。
$ ./fibonacci.py
1 1 2 3 5 8 13 21 34 55 89 144 233 377
如果确实导入了 fibonacci 模块,则不会自动执行测试。
>>> import fibonacci as fib
>>> fib.fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
导入了 fibonacci 模块,并执行了fib()
功能。
Python dir 函数
内置的dir()
函数提供了包含模块定义名称的字符串排序列表。
dirfun.py
#!/usr/bin/env python
"""
This is dirfun module
"""
import math, sys
version = 1.0
names = ["Paul", "Frank", "Jessica", "Thomas", "Katherine"]
def show_names():
for i in names:
print(i)
print(dir())
在此模块中,我们导入两个系统模块。 我们定义一个变量,一个列表和一个函数。
print(dir())
dir()
函数返回模块当前名称空间中所有可用的名称。
$ ./dirfun.py
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__',
'__package__', '__spec__', 'math', 'names', 'show_names', 'sys', 'version']
我们可以看到一些内置名称,例如'__file__'
或'__name__'
,以及我们定义和导入的所有其他名称。
Python 全局函数
globals()
函数返回代表当前全局名称空间的字典。 它是全局名称及其值的字典。 它是当前模块的字典。
globalsfun.py
#!/usr/bin/env python
import textwrap
version = 1.0
def myfun():
pass
gl = globals()
gnames = ', '.join(gl)
print(textwrap.fill(gnames))
我们使用globals()
功能来打印当前模块的所有全局名称。
$ ./globalsfun.py
textwrap, __package__, version, __builtins__, __name__, __spec__,
__doc__, gl, __cached__, myfun, __loader__, __file__
这些是当前模块的全局名称。
Python __module__
属性
__module__
类属性具有定义该类的模块的名称。
animals.py
"""
module animals
"""
class Cat:
pass
class Dog:
pass
这是animals.py
文件的内容,我们有两节课。
mclass.py
#!/usr/bin/env python
from animals import Cat
class Being:
pass
b = Being()
print(b.__module__)
c = Cat()
print(c.__module__)
在此代码中,我们使用__module__
属性。
from animals import Cat
从animals
模块,我们导入Cat
类。
class Being:
pass
在当前模块中,我们定义一个类Being
。
b = Being()
print(b.__module__)
创建Being
类的实例。 我们打印其模块的名称。
c = Cat()
print(c.__module__)
我们从Cat
类创建一个对象。 我们还将在定义模块的位置打印。
$ ./mclass.py
__main__
animals
当前模块的名称为'__main__'
,Cat's
模块的名称是动物。