ZetCode

Python 模块

最后修改于 2024 年 1 月 29 日

本文介绍如何在 Python 中使用模块。通过几个示例展示了如何创建和使用 Python 模块。

模块是包含 Python 代码的文件。Python 模块的文件扩展名为 .py

Python 代码可以通过以下方式进行管理:

Python 模块用于组织 Python 代码。例如,与数据库相关的代码放在数据库模块中,安全代码放在安全模块中,依此类推。较小的 Python 脚本可以有一个模块。但较大的程序会拆分成几个模块。模块被分组在一起形成包。

.pyc 文件

Python 会将模块的编译内容缓存到 .pyc 文件中,以加快加载模块的速度。Python 将程序源代码编译成字节码。为了提高性能,它会在源代码文件发生更改时将字节码缓存到文件系统中。

这种缓存机制可以绕过编译阶段,从而大大加快 Python 模块的加载速度。Python 将每个模块的编译版本缓存到 __pycache__ 目录中,文件名为 module.version.pyc

Python 会检查源文件与编译版本之间的修改日期,以确定是否过时需要重新编译。

main.py
#!/usr/bin/python

import compileall

compileall.compile_dir('lib/', force=True)

compileall 模块可用于以编程方式编译 Python 模块。

Python 模块名称

模块名称是文件名加上 .py 扩展名。当我们有一个名为 empty.py 的文件时,empty 就是模块名。__name__ 是一个变量,它保存着被引用的模块的名称。当前模块,即正在执行的模块(也称为主模块)有一个特殊名称:'__main__'。通过这个名称,它可以在 Python 代码中被引用。

在当前工作目录中有两个文件:empty.pytest_empty.py。第二个模块是正在执行的主模块。它导入了第一个模块。模块使用 import 关键字进行导入。

empty.py
"""
An empty module
"""

这是 empty.py 模块。

test_empty.py
#!/usr/bin/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/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/jano/.local/lib/python3.10/site-packages, /home/jano/tmp/py,
/usr/lib/python3.10, /usr/lib/python3.10/lib-dynload,
/usr/lib/python3/dist-packages, /usr/lib/python310.zip,
/usr/local/lib/python3.10/dist-packages

Python import 关键字

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/python

from math import *

pi = 3.14

print(cos(3))
print(pi)

示例将在控制台打印 3.14。这可能不是我们想要的。在较大的项目中,命名空间污染可能会变得很关键。

未导入的 Python 对象

下面的示例显示了使用此 import 构造不会导入的定义。

names.py
#!/usr/bin/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)
test_names.py
#!/usr/bin/python

from names import *

print(locals())

show_names()

_version 变量和 _show_version 函数未导入到 test_names 模块中。我们在命名空间中看不到它们。locals 函数为我们提供了模块中所有可用的定义。

导入特定对象

使用 fromimport 关键字,可以仅导入某些对象。

from module import fun, var

此导入构造仅从模块导入特定对象。这样我们只导入我们需要的定义。

import_specific.py
#!/usr/bin/python

from math import sin, pi

print(sin(3))
print(pi)

我们从 math 模块导入了两个对象。我们无法引用余弦函数等其他定义。

imnames.py
#!/usr/bin/python

from names import _version, _show_version

print(_version)
_show_version()

我们也可以导入以划线开头的定义。但这是一种不良的做法。

$ ./imnames.py
1.0
1.0

Python import 模块

最后一种构造最为常用。

import module

它避免了命名空间污染,并允许访问模块中的所有定义。

impmod.py
#!/usr/bin/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/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/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

如果我们导入了斐波那契模块,测试不会自动执行。

>>> import fibonacci as fib
>>> fib.fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

斐波那契模块已导入,并且 fib 函数已执行。

Python dir 函数

内置的 dir 函数返回一个排序的字符串列表,其中包含模块定义的名称。

dirfun.py
#!/usr/bin/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 函数

globals 函数返回一个字典,表示当前的全局命名空间。它是一个全局名称及其值的字典。它是当前模块的字典。

globalsfun.py
#!/usr/bin/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/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 的模块名称是 animals。

来源

Python 模块 - 语言参考

本文介绍了 Python 模块。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直撰写编程文章。至今,我已发表了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Python 教程