模块
在 Python 中,模块是一种组织和重用代码的方式。一个模块基本上就是一个包含 Python 代码的 .py 文件。这些文件可以包含可执行的代码、函数、类或变量。模块不仅仅是提供代码重用的方式,它们还可以帮助我们更好地组织和管理复杂的代码。
模块的导入
Python 自带了很多模块,当我们需要使用到这些模块提供的功能时,首先需要使用 import 语句导入模块。import 语句通常是在一个程序的最开头。比如,我们需要计算一个数据的平方根,这个平方根计算函数 sqrt() 在 Python 内置的 math 模块中。使用方法如下:
import math # 导入 math 模块
print(math.sqrt(16)) # 输出 4.0
在使用 sqrt() 函数时,前面要加上 math.
前缀表示这是 math 模块中的 sqrt() 函数。程序中可能在其它地方也定义一个叫做 sqrt 的函数,或者其它模块中也可能会有叫做 sqrt 的函数,所以要前缀区分清楚。
如果我们可以确定,程序中就只会有这一个 sqrt 函数,肯定不会重名,那么我们可以使用 from import
语句导入 sqrt 函数,这样,在之后的使用中,就不需要在给它添加前缀了:
from math import sqrt
print(sqrt(16)) # 输出 4.0
如果程序中会使用到多个 math 库中的函数,可以在 from import
语句导入多个函数,比如:
from math import sqrt, sin
print(sqrt(16)) # 输出 4.0
print(sin(0.5)) # 输出 0.479425538604203
如果需要用到 math 库中的很多函数和变量,可以使用星号 from import *
导入库中的所有函数、变量等:
from math import *
print(sqrt(16)) # 输出 4.0
# 计算圆面积
circle_radius = 5
print(pi * circle_radius ** 2) # 输出 78.53981633974483
# 计算 45 度角正弦值
print(sin(pi / 4)) # 输出 0.7071067811865475
上面的示例程序中,sqrt() 函数、sin() 函数、常量 pi 都是在 math 库中被定义的。
对于一些特别常用的库,我们会希望重命名导入的模块或函数,以便在当前上下文中更容易使用。我们可以使用 as 关键字重命名库或函数:
import numpy as np
# 创建一个一维数组
arr1 = np.array([1, 2, 3, 4, 5])
print("数组:", arr1)
# 计算数组点积
dot_product = np.dot(arr1, np.array([1, 0, 1, 0, 1]))
print("点积:", dot_product)
# 输出:
# 数组: [1 2 3 4 5]
# 点积: 9
上面程序中用到的 numpy(Numerical Python 的简称) 是一个开源的 Python 库,它提供了大量的函数来进行线性代数、逻辑、统计学等的运算。这个库在导入时,通常都会被命名为 np。Python 中有很多常用的库都有这种约定俗成的短名。比如下面几个都是最常用的缩写短名:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tkinter as tk
Python 标准库
Python 有一个丰富的标准库,提供了许多内置模块,帮助用户执行各种常见任务。极大的丰富了 Python 的应用场景,这也是 Python 能够获得成功的重要原因之一。 下面列出了一些最常用的 Python 标准库模块及其简要描述:
- math: 提供数学运算函数和常量。
- datetime: 提供日期和时间处理的类。
- os: 提供与操作系统交互的功能,如文件和目录操作。参考:路径处理
- sys: 提供 Python 解释器和它的环境交互的功能。
- re: 提供正则表达式相关功能。
- json: 提供 JSON 格式数据的编码和解码功能。
- urllib: 提供 URL 处理模块,用于读取Web数据。
- random: 提供随机数生成器和随机操作函数。
- collections: 提供额外的数据结构,如命名元组、双端队列等。
- sqlite3: 提供 SQLite 数据库的接口。
- subprocess: 提供启动和与子进程交互的功能。
- threading: 提供基于线程的并行处理。
- multiprocessing: 提供基于进程的并行处理。
- socket: 提供底层网络通信功能。
- email: 提供电子邮件相关的功能,如发送和解析邮件。
- csv: 提供CSV 文件的读写功能。
- xml: 提供 XML 处理功能。
- argparse: 提供命令行参数解析功能。
- gzip, tarfile, zipfile: 提供文件压缩和解压缩功能。
- logging: 提供日志记录功能。参考:日志记录
- itertools: 提供了一系列的迭代器,可以进行复杂的迭代操作,比如组合数据等。参考:迭代器
在后续的章节中,我们会陆续介绍到标准库中一些最常用的函数。以上列出的也只是标准库中模块的一部分。Python的标准库非常庞大,涵盖了许多领域和功能,使Python成为一种真正的通用编程语言。要查看完整的标准库列表,可以查看 Python 官方文档: https://docs.python.org/3/library/
用户自定义模块
创建模块
模块是一个包含 Python 代码的 .py 文件,我们自己也可以通过保存一个这样的 .py 文件来创建一个模块,在模块中定义一些函数、变量,然后在其它 Python 程序中导入并使用模块中定义的功能。创建用户自定义模块的步骤很简单:
首先,创建一个新的 .py 文件,比如我们创建一个叫做 mymodule.py 的新文件。
接下来,在 mymodule.py 中添加一些函数:
# mymodule.py
def hello(name):
print(f"Hello, {name}!")
def add(a, b):
return a + b
我们创建了两个函数: hello() 和 add() 。保存新创建的文件,然后就可以在另一个 Python 程序中导入并使用这个模块了:
import mymodule
mymodule.hello("小明")
result = mymodule.add(5, 3)
print(result)
在导入模块时,模块名是不含 .py 文件扩展名的。另外,在导入自定义的模块时,还要确定这些模块被放在 Python 的搜索路径中,否则,Python 可能找不到它们。
包
不同人创建的模块有可能也会重名,这样导入的时候就会有冲突。Python 中可以按照目录来组织模块,把多个模块组织成一个包(Package)。再导入模块的时候,需要把目录名也加入到导入的模块名字里面,这样就避免了同名。
假如,我们的项目文件结构如下:
my_project/
│
├── modules/
│ ├── __init__.py
│ └── mymodule.py
│
├── demo/
│ ├── __init__.py
│ └── demo.py
│
├── __init__.py
└── main.py
在这个项目的文件夹下,都有一个 __init__.py
文件,这个文件可以是空的。如果文件夹下有 __init__.py
文件,就表示这是一个包;否则就是一个普通文件夹,不能用来导入模块。
在 main.py 中导入 mymodule.py 可以如下方法实现:
# main.py
import modules.mymodule
在导入的时候,每一层机文件夹或文件名之间用 .
号分隔。
如果在 demo.py 中也需要导入 mymodule.py 中的内容,可以如下实现:
# demo.py
import ..modules.mymodule
开头的 ..
表示上一级目录,如果需要从更上层的目录导入,可以继续添加点 .
,每增加一层就增加一个点。例如,要从上两级目录导入,可以使用 from ... import some_module
。
Python 的搜索路径
默认情况下,搜索路径包括当前目录和 Python 安装目录。如果要导入的模块不在这些位置,那么需要将其所在目录添加到搜索路径中,或者将其放在一个已经在搜索路径中的目录,Python 才能找到这个模块。
临时搜索路径
使用 sys 模块中的 path 属性可以查看当前的 Python 搜索路径。例如:
import sys
print(sys.path)
在程序中修改 sys.path 可以临时添加新的路径。例如:
import sys
sys.path.append('/path/to/directory')
这种方法的修改的搜索路径只在当前的 Python 环境中有效,重启 Python 解释器或编程环境后,新添加的路径就会失效。
环境变量
如果想永久地添加某文件夹到 Python 的搜索路径,可以修改 PYTHONPATH 环境变量,将其指向想添加到搜索路径的目录。Python 每次启动时会自动读取这个环境变量并把它添加到搜索路径中。
在 Windows 上设置 PYTHONPATH 的步骤如下:
- 打开“控制面板” > “系统” > “高级系统设置” > “环境变量”。
- 在“系统变量”区域,点击“新建”来创建一个新的环境变量。
- 在“变量名”字段中输入 PYTHONPATH。
- 在“变量值”字段中输入想要添加的目录路径。如果有多个路径,用分号 (;) 分隔它们。
- 点击“确定”保存更改。
在 macOS 或 Linux 上设置 PYTHONPATH 需要在 shell 配置文件中设置环境变量,步骤如下:
- 打开你的 shell 配置文件,不同 shell 的配置文件会有不同,例如:
~/.bashrc
、~/.bash_profile
或者~/.zshrc
- 在文件中添加一行:
export PYTHONPATH="$PYTHONPATH:/path/to/directory
(替换/path/to/directory
为真正想要添加的目录路径。) - 保存文件并重新加载配置(运行 source ~/.bashrc 命令或者重启终端)
site-packages
Python 的 site-packages 目录是一个特殊的目录,用于存储第三方包。我们可以在此目录下创建一个 .pth 文件来永久添加自定义路径到 Python 搜索路径。方法是:
- 找到 Python 的 site-packages 目录。这个目录通常位于 Python 安装目录下。
- 在 site-packages 目录下创建一个新的 .pth 文件,例如 mymodules.pth。
- 在 .pth 文件中,添加的目录路径,每行一个路径。比如:
/path/to/directory
- 保存 .pth 文件。Python 将在下一次启动时自动读取这些路径。
从 ZIP 文件中导入模块
为了方便打包和部署模块,我们可以把一个或多个文件打包成 ZIP 格式的压缩文档。利用 Python 的模块搜索路径机制,我们可以导入存储在 ZIP 文件中的模块和包。在使用时,首先把包含需要导入模块的 ZIP 文件的路径添加到 sys.path
列表中。然后,就可以像导入普通模块一样导入ZIP文件中的模块了。
假设我们有一个 ZIP 文件 my_package.zip
,里面包含一个叫做 my_module.py
的模块,我们可以按照以下方式导入它:
import sys
# 将ZIP文件的路径添加到 sys.path
sys.path.insert(0, '/path/to/my_package.zip')
# 现在可以导入ZIP文件中的模块了
import my_module
# 使用模块中的功能
my_module.some_function()
从 ZIP 文件中导入模块可能会影响启动时间,因为 Python 需要额外处理ZIP归档。不过,对于已经加载到内存中的模块,性能影响可以忽略不计。从 ZIP 文件中导入的模块不能执行写入操作,因为 ZIP 归档是只读的。
需要注意的是只有 .py 文件可以使用 ZIP 方式导入。有些模块是使用其它语言开发的,它们的模块中包含了使用其它语言编译出来的动态链接库文件,这样的模块是无法使用 ZIP 打包导入的。
导入时运行
当我们使用 import 导入一个模块的时候,Python 立刻就会运行这个模块内的代码。这与 C、Java 等编译型语言不太一样,在那些语言中,include, import 仅仅是表示程序可以调用模块里定义的内容了,导入的过程本身并不会执行模块里的代码。但 Python 是解释型语言,它需要运行被导入的库中的代码,才能定义库中函数、变量以备之后使用。我们可以利用 Python 的这一行为,在导入模块的同时去做一些事情。比如,我们可以对模块进行一些初始化工作:配置日志文件,检查环境变量的设置是否正确,连接到所需的资源,注册或显示提示信息等等。
比如,我们编写了如下的一个库:
print("正在初始化 mylibrary...")
# 示例:初始化配置
default_config = {
"precision": 2,
"method": "standard"
}
# 示例:初始化日志
def _initialize_logging():
print("mylibrary 的日志文件已配置好。")
_initialize_logging()
def set_precision(precision):
global default_config
default_config["precision"] = precision
print(f"精度设置为: {precision}")
def calculate_square_root(number):
precision = default_config["precision"]
result = round(number ** 0.5, precision)
print(f"{number} 的开方是: {result} (精度 {precision})")
return result
上面这个库除了定义了一些函数外,还有一些其它可执行代码。当我们在另一个程序中导入它时
import mylibrary
mylibrary.set_precision(3)
mylibrary.calculate_square_root(9)
导入 mylibrary 模块会直接运行模块中的代码,于是它会打印 "正在初始化 mylibrary...",和 "mylibrary 的日志文件已配置好。"
有些代码,我们是不希望在导入时运行的。最常见的情况是,某个文件中的程序,即可以直接运行,也可以作为模块被其他文件导入,这其中就会有一些代码,只希望在直接运行时才运行。为实现这个目的,我们需要在程序中添加一个条件语句: if __name__ == "__main__"
来控制代码的执行方式。在这个语句中,__name__
是一个特殊的变量,当 Python 文件被直接运行时,Python 解释器会把这个文件的 __name__
变量的值设为字符串 "__main__"
;当 Python 文件作为模块被其他文件导入时,__name__
变量会被设定为该模块的名称。因此,只有当 Python 文件被直接运行时 if __name__ == "__main__"
的条件才会成立,它下面的代码块才会被运行。我们可以把那些只在直接运行时才运行代码放它下面。
假设有一个名为 example.py 的文件:
def function_a():
print("Function A")
def function_b():
print("Function B")
if __name__ == "__main__":
function_a() # 这行只有在直接运行 example.py 时才会执行
当直接运行 example.py 时,__name__
会被设为 "__main__"
,因此 function_a() 会被调用。如果从另一个文件中导入 example.py,__name__
将不会是 "__main__"
,所以 function_a() 不会被调用。
第三方库
常用功能
除了 Python 自带的标准库,还拥有一个极其活跃的开源社区。这个社区为 Python 贡献了庞大而丰富的第三方库,覆盖了从网络编程到数据分析,再到图像处理和机器学习等各个领域。下面列举了几个最知名的第三方库,我们会在后续章节中介绍它们以及其它一些第三方库的使用方法:
- Web 开发
- Flask: 一个轻量级的Web应用框架,易于学习,适合小到中型项目。
- Django: 一个高级的Web框架,提供了完整的功能,适用于大型项目。
- 数据科学与分析
- 机器学习与人工智能
- Scikit-learn: 一个简单有效的机器学习库,提供了很多常用的机器学习算法。
- TensorFlow: Google 开发的一个强大的机器学习框架,广泛用于深度学习。
- PyTorch: 由 Facebook 开发,是一个灵活且强大的深度学习框架。
- 网络编程与爬虫
- Requests: 用于发送 HTTP 请求的库,简单易用。
- Scrapy: 一个强大的网页爬虫框架,适用于大规模的数据抓取。
- 图像处理
- Pillow: Python Imaging Library (PIL) 的一个现代化的分支,提供了丰富的图像处理功能。
- OpenCV: 用于计算机视觉以及图像处理的强大库,支持多种语言和平台。
- 数学与统计
- SciPy: 基于 NumPy,提供了一系列用于数学、科学和工程的函数。
- Statsmodels: 用于统计分析和计量经济学的库。
- 文件和数据格式处理
- Beautiful Soup: 解析 HTML 和 XML 文件的库,适合网页数据抓取。
- PyYAML: 用于读写 YAML 文件的库。
- GUI 开发
- Tkinter: Python 自带的 GUI 工具包,可以快速创建简单的 GUI 应用。
- PyQt/PySide: 基于 Qt 的跨平台 GUI 工具包。
安装
与 Python 自带的标准库不同,第三方库在使用前需要先安装。大多数库都可以直接使用 Python 的包管理工具 pip 进行安装。比如,假设我们需要使用一个名为 qrcode 的库,它依赖于 pillow 库。在命令行终端,可以使用下面的命令进行安装:
pip install qrcode[pil]
有一些特别复杂的库,比如 pytorch,对于不同系统,不同硬件的电脑,在安装时会有一些不同配置。对于这样复杂的库,最好去它们的主页,按照说明文档的指导进行安装。
使用
安装好库之后,就可以在 Python 代码中导入并使用它了,方法与使用 Python 自己的标准库完全一样。依然以 qrcode 库为例,运行下面的代码,就可以为本书的网址产生一个二维码:
import qrcode
from PIL import Image
# 创建一个 QRCode 对象
qr = qrcode.QRCode(
version=1, # 控制二维码的大小,1~40,1 是最小的
error_correction=qrcode.constants.ERROR_CORRECT_L, # 控制二维码的错误纠正功能
box_size=10, # 控制二维码中每个小格子包含的像素数
border=4, # 控制二维码四周留白包含的格子数
)
# 添加数据
qr.add_data('https://www.example.com')
qr.make(fit=True)
# 创建二维码图片
img = qr.make_image(fill='black', back_color='white')
# 显示图片
img.show()
运行结果如下:
练习
计算圆面积
import math
def circle_area(radius):
return math.pi * radius ** 2
print(circle_area(5))
将角度转换为弧度
import math
print(math.radians(180))
最大公约数和最小公倍数
import math
a, b = 48, 18
gcd = math.gcd(a, b) # 最大公约数
lcm = abs(a * b) // gcd # 最小公倍数
print(gcd, lcm)
求解二元二次方程组
我们可以使用 sympy 库来求解方程组。比如求解系列方程组:
from sympy import symbols, Eq, solve
# 定义变量
x, y = symbols('x y')
# 输入系数
a, b, c, d, e, f = 1, 1, 1, 1, 1, 1 # 示例系数
g, h, i, j, k, l = 1, 1, 1, 1, 1, 1 # 示例系数
# 定义方程
equation1 = Eq(a * x**2 + b * y**2 + c * x * y + d * x + e * y + f, 0)
equation2 = Eq(g * x**2 + h * y**2 + i * x * y + j * x + k * y + l, 0)
# 求解方程组
solutions = solve((equation1, equation2), (x, y))
# 输出结果
print(f"解为: {solutions}")