跳至主要内容

Python 模块教程:导入、编写与使用

学习如何创建和导入 Python 模块。了解编写可复用、结构清晰且高效的 Python 代码的最佳实践、示例与技巧!
· 8分钟 阅读

使用 AI 探索

当您刚开始学习 Python 时,通常会把所有代码写在一个文件里。对于小脚本来说这没问题,但随着程序规模扩大,单文件会变得难读、难维护,也无法在不同项目间复用。Python 提供的解决方案就是模块。

在本教程中,您将了解什么是模块、如何导入模块、如何编写自己的模块,以及将入门脚本提升为生产级代码的最佳实践。在开始编写自己的模块之前,建议先学习我们的数据科学 Python 入门课程。

什么是 Python 模块?

模块本质上就是一个 Python 文件。任何带有 .py 扩展名且包含 Python 代码(函数、类、变量或可运行逻辑)的文件,都是一个模块。当您保存一个名为 calculation.py 的文件时,您就创建了一个名为 calculation 的模块。

模块的强大之处在于可以将其导入到其他程序中使用。与其把同一个函数复制粘贴到多个脚本里,不如在一个模块中定义一次,随后在需要时导入。这正是 Python 标准库的工作方式:它提供了许多预构建模块,如 math、os 和 random,您只需一行代码即可在任意程序中使用。

更具体地说,在 Python 中您会遇到三类模块:

  • 内置模块:随 Python 一起提供,例如我刚提到的 math 和 os。

  • 第三方模块:通过 pip 安装,如 numpy 或 pandas。

  • 您自己的模块:任何您自己编写的 .py 文件。

在 Python 中导入模块

要使用任意模块中的功能,您需要先在当前程序中导入它。您需要使用 import 关键字并跟上目标模块名。当解释器遇到 import 语句时,就会将该模块导入到当前程序中。

您可以通过在模块名后使用点号(.)运算符来调用模块中的函数。

先来看如何使用标准库模块。下面的示例中,将 math 模块导入程序,以便使用 sqrt() 函数。

import math  # Import the math module
num = 4
print(math.sqrt(num))  # Call the sqrt() function from the math module

出于效率考虑,每个模块在一次解释器会话中只会被导入一次。因此,如果您修改了模块,必须重启解释器。

如果您想重新加载已导入的模块(例如编辑之后),请使用 importlib.reload()。

请注意,旧的内置函数 reload() 在 Python 3 中已不存在——在 Python 3.4+ 中,importlib.reload() 是当前且官方推荐的模块重载方式。

import importlib
importlib.reload(module_name)

注意:不建议重载 sys、__main__、builtins 等关键模块。许多扩展模块并未设计为可多次初始化,重载时可能以不可预期的方式失败。开发阶段请仅重载您自己的模块。

即将推出:Python 正在引入“延迟导入”(lazy imports)。它会将模块的加载推迟到首次使用时,从而加快启动速度。这很有用,尤其在大型项目中,通常会在文件顶部导入许多模块,但并不立即需要它们。

如何编写您自己的 Python 模块

现在您已经学会了如何在程序中导入模块,是时候编写自己的模块并在另一个程序中使用它了。编写模块与编写其他 Python 文件并无二致。让我们先在文件 calculation.py 中编写一个用于加减两个数的函数。

def add(x,y):
    return (x+y)
def sub(x,y):
    return (x-y)

如果您尝试在命令行直接执行该脚本,不会有任何输出,因为您并未指示程序执行某个操作。请在同一目录下创建另一个名为 module_test.py 的 Python 脚本,并写入以下代码。

import calculation            #Importing calculation module
print(calculation.add(1,2))   #Calling function defined in the calculation module 

如果您执行 module_test.py,将会看到输出为 "3"。当解释器遇到 import 语句时,它将 calculation 模块导入到您的代码中,随后通过点号运算符,您得以访问 add() 函数。

使用 if __name__ == "main" 保护可运行代码

在编写模块时有一个重要习惯:将只希望在直接运行(而非被导入时)执行的代码,放入 if __name__ == "__main__" 保护块中。

# calculation.py
def add(x, y):
    return x + y

def sub(x, y):
    return x - y

if __name__ == "__main__":
    # This only runs when you execute calculation.py directly
    # It will NOT run when another script imports this module
    print(add(1, 2))
 
当模块被直接运行时,Python 会将其 __name__ 设为 "__main__"。当它被另一个脚本导入时,__name__ 会被设为模块的文件名。因此,上面的 print 语句在他人将 calculation 导入到其程序时不会意外执行。

在 Python 中导入模块的其他方式

还有更多导入模块的方法:

  • from .. import 语句

  • from .. import * 语句

  • 为导入的模块重命名

使用 from module import name

from..import 语句允许您仅从模块中导入特定的函数/变量,而不是导入全部。在前面的示例中,当您将 calculation 导入到 module_test.py 时,add() 和 sub() 两个函数都会被导入。但如果您只需要 add() 函数呢?下面的示例演示了 from..import 的用法。

from calculation import add
print(add(1,2))

在上面的示例中,只导入并使用了 add() 函数。注意这里直接使用了 add()?您现在无需再写模块名即可直接访问它。您也可以在导入语句中用逗号分隔导入多个属性。请看下面的示例:

from calculation import add,sub

使用 from module import *

使用该语句可以导入模块的所有属性。这样,被导入模块的所有名称都会在您的代码中可见。

下面的示例演示了 from .. import * 的用法:

from calculation import *
print(add(1,2))
print(sub(3,2))

注意,在专业开发中应尽量避免使用 from..import 和 from..import*。它会用该模块中的所有名称污染您的命名空间,使得阅读代码时难以判断函数来自何处,并且可能悄然覆盖您已定义的名称。请改用显式导入。

在 Python 中为模块重命名

您可以为要导入的模块重命名:当您希望给模块一个更有意义的名称,或模块名过长不便重复书写时,这很有用。您可以使用 as 关键字为其起别名。以下示例展示了如何在程序中使用它。

import calculation as cal
print(cal.add(1,2))

将 calculation 重命名为 cal 能为您省下一些输入工作。

注意,此时您将不能再使用 calculation.add(1,2),因为 calculation 在您的程序中已不再被识别。原因是:一旦使用 as 为模块设置了别名,原名称在该脚本中将不再可用。

Python 中的模块搜索路径

您可能希望在不同的程序或项目中使用自己的模块,而它们在目录中的物理位置可能不同。如果要使用位于其他目录的模块,Python 提供了若干选项。

当您导入名为 calculation 的模块时,解释器会先搜索是否存在该名称的内置模块;如果没有,再在由变量 sys.path 指定的目录列表中搜索名为 calculation.py 的文件。sys.path 包含以下位置:

  • 包含输入脚本的目录(或当前目录)

  • PYTHONPATH(与 shell 变量 PATH 语法相同的目录名列表)

  • 与安装相关的默认路径

假设 module_test.py 位于 /home/datacamp/ 目录,而您把 calculation.py 移动到了 /home/test/。您可以修改 sys.path,将 /home/test/ 加入到解释器搜索模块的路径列表中。为此,您需要按如下方式修改 module_test.py:

import sys
sys.path.append('/home/test/')

import calculation
print(calculation.add(1,2))

Python 中的字节码文件

导入模块会增加程序的执行时间,因此 Python 通过一些技巧来加速。其中一种方式是创建以 .pyc 为扩展名的字节码文件。

在内部,Python 会将源代码转换为称为字节码的中间形式,然后再将其翻译为计算机的本地语言并运行。下次从另一个程序导入该模块时,这个 .pyc 文件会派上用场——导入速度会更快,因为导入模块所需的部分处理工作已经完成。此外,这些字节码文件与平台无关。

注意,这些 .pyc 文件通常会在与相应 .py 文件相同的目录中创建。如果 Python 无权在该目录写文件,则不会创建 .pyc 文件。这些文件通常存放在 __pycache__ 目录中,和您的 .py 文件并列,文件名类似于 calculation.cpython-312.pyc,以反映所用的 Python 版本。您可以放心忽略该文件夹,或在 .gitignore 中排除它。Python 会自动管理它。

Python 的 dir() 函数

dir() 函数用于查看模块中定义的所有名称。它会返回一个排序后的字符串列表,包含模块中定义的名称。

import calculation
print(calculation.add(1,2))
print(dir(calculation))
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'add', 'sub']

在输出中,您可以看到在模块中定义的函数名 add 和 sub。属性 __name__ 包含模块的名称。所有以下划线开头的属性,都是与模块关联的 Python 默认属性。

结语

创建模块有助于更好地管理代码并提升复用性。Python 为您提供了一些内置模块,可通过 import 关键字导入。Python 也允许您创建自己的模块并在程序中使用。它通过字节码文件来降低使用模块的开销,从而加快执行速度。您可以使用 dir() 来了解程序中所用模块定义了哪些属性。该函数既可用于预定义模块,也可用于用户自定义模块。

如果您想要进一步学习 Python,欢迎查看我们的 数据科学进阶 Python 课程。

作者

Nishant Kumar

常见问答

我可以在函数内部导入模块吗?

可以。您可以在函数内部导入模块,但为了清晰与性能,通常最好在文件顶部进行导入。

如果两个模块同名会怎样?

Python 会按模块搜索路径(sys.path)中首先匹配到的进行导入。请注意命名以避免冲突。

我需要手动把模块编译成 .pyc 吗?

不需要。导入模块时,若具有写权限,Python 会自动创建 .pyc 文件。

如何查看模块是从哪里被导入的?

使用模块的 __file__ 属性:

import math
print(math.__file__)
使用 from module import * 可以吗?

可以用,但不推荐在生产代码中使用。它会污染命名空间,并使追踪实际使用的内容更加困难。

编辑后可以重新加载模块吗?

可以。在交互式会话中,使用 importlib.reload():

import importlib
import mymodule
importlib.reload(mymodule)

主题