模块与包
模块的介绍
1. 什么是模块?
一个模块就是一个 Python 文件。任何一个以 .py 结尾的 Python 文件都可以被看作是一个模块。
模块的主要作用是:
- 代码组织:将相关的代码(函数、类、变量)组织在一个文件中,使项目结构更清晰。
- 代码重用:你可以在不同的程序中导入并使用同一个模块,避免重复编写代码。
- 命名空间:模块创建了一个独立的命名空间,可以避免不同模块间的命名冲突。
例如,Python 内置的 math 模块就是一个名为 math.py 的文件,里面定义了 pi、sqrt() 等数学相关的变量和函数。
也就是说,模块就是一个py文件,里面有类、函数、变量等,我们可以拿过来用
2. 如何使用模块 (import)
使用 import 语句来引入一个模块。有几种常见的导入方式:
方式一:import module_name (推荐)
这是最常用和推荐的方式。它导入整个模块,并通过 module_name.member_name 的方式访问模块内的成员。
import math
print(math.pi) # 输出: 3.141592653589793
print(math.sqrt(16)) # 输出: 4.0
import os # 导入操作系统接口模块
print(os.getcwd()) # 输出: 当前工作目录
方式二:import module_name as alias
给导入的模块起一个别名,通常是为了简化较长的模块名。
import math as m
print(m.pi)
print(m.sqrt(16))
import pandas as pd # 这是一个非常普遍的约定
方式三:from 模块名 import 功能名
从模块中只导入特定的成员(函数、类或变量),这样就可以直接使用该成员,而不需要模块名前缀。
from math import pi, sqrt
print(pi) # 直接使用 pi,不需要 math.pi
print(sqrt(16)) # 直接使用 sqrt
**方式四:from 模块名 import * **
将模块里的所有方法(*)全部导入进来用。
不推荐使用:因为它会污染你的当前命名空间,你可能不知道导入了哪些变量和函数,如果恰好有同名的函数或变量,就会被覆盖,导致难以追踪的 bug。
自定义模块
步骤 1:创建一个 Python 文件
假设创建一个名为 my_utils.py 的文件,内容如下:
# 文件名: my_utils.py
PI = 3.14159
def greet(name):
"""一个简单的问候函数"""
return f"Hello, {name}! Welcome."
def calculate_area(radius):
"""计算圆的面积"""
return PI * (radius ** 2)
步骤 2:在另一个文件中导入并使用它
在同一个目录下,创建另一个文件,例如 main.py。
# 文件名: main.py
# 导入我们自己创建的 my_utils 模块
import my_utils
# 使用模块中的函数和变量
message = my_utils.greet("Alice")
area = my_utils.calculate_area(10)
print(message)
print(f"半径为 10 的圆的面积是: {area}")
print(f"模块中的 PI 值是: {my_utils.PI}")
运行 main.py,得到输出:
Hello, Alice! Welcome.
半径为 10 的圆的面积是: 314.159
模块中的 PI 值是: 3.14159
重要概念:if name == ‘main’:
这是一个非常重要的技巧。放在这个代码块下的代码,只有当该 .py 文件被直接运行时才会执行。如果它作为模块被导入,这个代码块下的内容则不会执行。这常用于为模块编写测试代码。
修改 my_utils.py:
# 文件名: my_utils.py
PI = 3.14159
def greet(name):
return f"Hello, {name}! Welcome."
def calculate_area(radius):
return PI * (radius ** 2)
# --- 添加测试代码 ---
if __name__ == '__main__':
# 这部分代码只有在直接运行 "python my_utils.py" 时才会执行
print("正在运行 my_utils.py 的测试代码...")
test_name = "Bob"
test_radius = 5
print(greet(test_name))
print(f"半径为 {test_radius} 的圆面积是: {calculate_area(test_radius)}")
- 运行 python main.py 时,my_utils.py 是被导入的,所以它的测试代码不会执行。
- 运行 python my_utils.py 时,它的测试代码会被执行。
Python包
1. 什么是包package?
当项目越来越大,模块文件越来越多时,你就需要一种更好的方式来组织它们。包就是一种组织模块的方式。
简单来说,一个包就是一个包含多个模块的目录(文件夹)。这个目录必须包含一个特殊的文件__init__.py(在现代 Python 中,这个文件可以是空的)。如果没有,python解释器就不会将此文件夹认为是一个包,会当作普通的文件夹处理。
目录结构示例:
my_project/
├── main.py
└── my_app/ <-- 这是一个包
├── __init__.py <-- 必须有这个文件,可以是空的
├── string_ops.py <-- 模块1
└── math_ops.py <-- 模块2
2. __init__.py 的作用
- 标识包: 它的存在告诉 Python,这个目录应该被当作一个包来处理。
- 初始化代码 (可选): 你可以在
__init__.py文件中编写代码。当包被导入时,这个文件会自动执行。这可以用来进行一些包级别的初始化设置。
3. 创建和使用自定义包
步骤 1:创建目录和文件
按照上面的结构创建目录和文件。
-
my_app/string_ops.py 内容:
-
def reverse_string(s): return s[::-1] -
my_app/math_ops.py 内容
def add(a, b): return a + b -
my_app/
__init__.py内容:# 这个文件可以是空的,或者我们可以加一句打印来观察它何时执行 print("my_app 包正在被初始化...")
步骤 2:在 main.py 中导入和使用包中的模块
# 文件名: main.py
from rich import print
from my_package import string_ops
from my_package.math_ops import add
reverse_text = string_ops.reverse_string("Alen is pig!")
res = add(4, 4)
print(reverse_text)
print(res)
运行 main.py,你将得到输出:
my_app 包正在被初始化...
!gip si nelA
8
可以看到,当 main.py 第一次从 my_app 包中导入任何东西时,__init__.py 文件就被执行了。