在 Python 中导入模块和包

PythonBeginner
立即练习

介绍

在这个 Lab 中,你将通过使用模块(modules)和包(packages)来学习组织和重用 Python 代码的基础知识。我们将从理解什么是 Python 模块开始,以及当模块被直接运行或被导入时,其执行行为会如何变化。

然后,你将练习将代码从模块引入到你的程序中的两种主要方式:使用 import 语句加载整个模块,以及使用 from...import 语句加载特定的函数或变量。最后,你将学习如何将相关的模块组织成一个包,以创建结构良好且可扩展的项目。所有的编码工作都将在 WebIDE 中使用 Python 文件和终端完成。

这是一个实验(Guided Lab),提供逐步指导来帮助你学习和实践。请仔细按照说明完成每个步骤,获得实际操作经验。根据历史数据,这是一个 初级 级别的实验,完成率为 94%。获得了学习者 97% 的好评率。

理解 Python 模块

Python 中的模块(module)本质上就是一个包含 Python 代码的文件,它具有 .py 扩展名。模块允许你逻辑化地组织代码,使其更易于管理和重用。在模块中定义的函数、类和变量可以在其他脚本中使用。

在你的 WebIDE 中,你会在左侧看到一个文件浏览器。实验环境已经在 ~/project 目录下创建了一个名为 hello.py 的文件。

首先,打开 hello.py 来检查其内容。它应该包含以下代码:

print("This code runs on import or direct execution.")

if __name__ == "__main__":
    print("This code runs ONLY when the script is executed directly.")

if __name__ == "__main__": 块是 Python 中的一个特殊结构。__name__ 变量是一个内置变量,其值等于当前模块的名称。当一个 Python 脚本从命令行直接运行时,它的 __name__ 会被设置为字符串 "__main__"。这个 if 语句允许你编写只有在文件作为主程序执行时才会运行的代码,而不是在它被其他模块导入时运行。

让我们实际操作一下。打开 WebIDE 中的终端并直接运行 hello.py 脚本:

python3 hello.py

你将看到以下输出,因为两个 print 语句都执行了:

This code runs on import or direct execution.
This code runs ONLY when the script is executed directly.

这展示了当脚本是主程序被执行时的行为。在下一步中,我们将看到当它被导入为一个模块时会发生什么。

使用 import 语句导入模块

使用 import 语句导入模块是使用模块最常见的方式。这使得模块中的所有代码都可以供你当前的脚本使用。

在文件浏览器中,你会找到一个名为 main.py 的空文件。这将是我们本次实验其余部分的主脚本。

打开 main.py 并添加以下行来导入 hello 模块:

import hello

print("The main.py script has finished.")

保存文件。现在,从终端运行 main.py

python3 main.py

仔细观察输出:

This code runs on import or direct execution.
The main.py script has finished.

注意,只有来自 hello.py 的第一条 print 语句被执行了。if __name__ == "__main__": 块中的代码被跳过了。这是因为当 main.py 导入 hello 时,在 hello.py 上下文中的 __name__ 变量被设置为 "hello"(模块的名称),而不是 "__main__"。此功能对于创建在导入时不会产生不必要副作用的可重用模块至关重要。

现在,让我们处理一个包含多于打印语句的模块。打开 module_a.py 文件。它包含一个变量、一个函数和一个类。

PI = 3.14159

def greet(name):
 print(f"Hello, {name} from module_a!")

class Calculator:
    def add(self, x, y):
        return x + y

修改 main.py 以导入 module_a 并使用其成员。要访问导入模块的成员,你使用语法 module_name.member_name

main.py 的内容替换为以下内容:

import module_a

## Access the PI variable
print(f"The value of PI is {module_a.PI}")

## Call the greet function
module_a.greet("LabEx")

## Create an instance of the Calculator class and use its method
calc = module_a.Calculator()
result = calc.add(5, 3)
print(f"5 + 3 = {result}")

保存文件并运行它:

python3 main.py

输出将是:

The value of PI is 3.14159
Hello, LabEx from module_a!
5 + 3 = 8

这演示了 import 语句如何加载整个模块,以及你如何使用模块名作为前缀来访问其内容。

使用 from...import 导入特定对象

有时,你只需要模块中的少数特定项。from...import 语句允许你将特定的函数、类或变量直接导入到你当前脚本的命名空间(namespace)中。这意味着你可以使用它们而无需 module_name. 前缀。

让我们修改 main.py 来使用这种导入方法。我们将不再导入整个 module_a,而是只导入 PI 变量和 greet 函数。

使用以下代码更新 main.py

from module_a import PI, greet

## Access PI and greet directly without the module prefix
print(f"The value of PI is {PI}")
greet("World")

保存文件并从终端运行它:

python3 main.py

输出将是:

The value of PI is 3.14159
Hello, World from module_a!

如你所见,PIgreet 被直接使用了。但是,如果你尝试访问你没有导入的内容,比如 Calculator 类,你会收到一个错误。

现在尝试一下。将以下两行添加到 main.py 的末尾:

calc = Calculator()
print(calc.add(10, 20))

再次运行脚本:

python3 main.py

这次,脚本将因 NameError 而失败:

The value of PI is 3.14159
Hello, World from module_a!
Traceback (most recent call last):
  File "/home/labex/project/main.py", line 7, in <module>
    calc = Calculator()
NameError: name 'Calculator' is not defined

这个错误证实了只有在 from...import 语句中指定的对象才会被带入当前命名空间。这种方法可以使你的代码更具可读性,但如果从不同模块导入同名对象,也会增加命名冲突的风险。

在进入下一步之前,请从 main.py 中删除导致错误的这两行。

理解和使用 Python 包 (Packages)

随着项目的增长,你可能希望将相关的模块组织到一个单一的目录层次结构中。这就是包(Packages)的作用。包是一个包含名为 __init__.py 的特殊文件的目录(该文件可以是空的)。该文件的存在会告诉 Python 将该目录视为一个包。

让我们创建一个包来存放我们的 module_a

首先,在 ~/project 目录下创建一个名为 my_package 的新目录。你可以在文件浏览器中右键单击并选择“新建文件夹”来完成此操作。

mkdir my_package

接下来,在新的 my_package 目录中创建必需的 __init__.py 文件。

touch my_package/__init__.py

现在,将 module_a.py 移动到 my_package 目录中。你可以在文件浏览器中拖放该文件。

mv module_a.py my_package/

你的项目结构现在应该如下所示:

~/project/
├── main.py
├── hello.py
└── my_package/
    ├── __init__.py
    └── module_a.py

有了这种包结构,我们需要更新在 main.py 脚本中导入 module_a 的方式。要从包中导入模块,你需要使用点分隔的模块名称,例如 package_name.module_name

打开 main.py 并修改它以从 my_package.module_a 导入 greet 函数:

from my_package.module_a import greet

greet("Package")

保存文件并运行它:

python3 main.py

你应该会看到以下输出:

Hello, Package from module_a!

这展示了如何从包内的模块导入特定对象。或者,你也可以导入模块本身:

## Alternative import style
import my_package.module_a

my_package.module_a.greet("Alternative")

包是组织大型代码库(如库和框架)成清晰且可维护结构的强大工具。

总结

在这个实验(Lab)中,你学习了 Python 代码组织的基本概念。你从理解什么是模块(module)以及 if __name__ == "__main__": 块在创建可重用代码中的作用开始。然后,你练习了使用 import module_name 语法导入模块,并使用点表示法(dot notation)访问它们的成员。

此外,你探索了 from...import 语句,它可以将模块中的特定对象直接引入到你的脚本命名空间中。最后,你学习了如何通过创建包含 __init__.py 文件的目录,将相关模块结构化为一个包(package),以及如何从该包中导入。这些技能对于编写清晰、有组织且可扩展的 Python 应用程序至关重要。