第六章|模块与包:站在巨人的肩膀上
本文介绍了Python模块和包的核心概念及使用方法。主要内容包括:模块的定义与导入方式(基础导入、指定导入、别名导入和全部导入),包的创建与组织结构,模块搜索路径机制,以及常用的入口惯用法if __name__ == '__main__'。文章还列举了9个常用标准库模块(如sys、os、math等)的典型用法,展示了Python"内置电池"的强大功能。通过学习这些内容,开发者可
📌 引言:不要重复发明轮子,但要学会怎么用轮子
想象一下:你想做个蛋糕,难道要从种小麦开始?当然不!你会去超市买现成的面粉、鸡蛋、糖。编程也一样——你想写个程序处理日期、发个网络请求、画个图表,难道都要自己从头写?Python 说:不用!别人早就写好了,打包成 模块,你直接拿来用就行。
Python 最强大的地方就是它庞大的生态系统。标准库自带“电池”,第三方库更是成千上万。学会导入和使用模块,你的编程能力将瞬间膨胀。
本章我们就来学习:
- 如何导入和使用模块
- 如何组织自己的模块成为包
- Python 的模块搜索路径是怎么回事
- 入口惯用法
if __name__ == '__main__'是干嘛的 - 标准库里那些常用模块的快速巡礼
准备好了吗?让我们一起站上巨人的肩膀!🚀
一、模块是什么?—— 一个 .py 文件就是一个模块
模块就是包含 Python 代码的 .py 文件。你可以把相关的函数、类、变量放在一个文件里,方便在其他地方导入使用。
# mytools.py
def add(a, b):
return a + b
PI = 3.14159
这个 mytools.py 就是一个模块。其他 Python 文件可以导入它,然后使用里面的函数和变量。
为什么用模块?
- 代码复用:写一次,到处用
- 命名空间:避免名字冲突(不同模块的同名函数互不影响)
- 组织代码:把相关功能放在一起,清晰易维护
二、导入模块的四种姿势
Python 提供了多种导入语法,适应不同场景。
1️⃣ import module —— 最基础的方式
import math
print(math.sqrt(16)) # 4.0
用这种方式,你需要通过 模块名.函数名 来调用,避免了命名冲突。
2️⃣ from module import name —— 直接导入指定内容
from math import sqrt, pi
print(sqrt(16)) # 4.0
print(pi) # 3.141592653589793
现在可以直接用函数名,不用加模块前缀。方便,但可能造成命名冲突。
3️⃣ import module as alias —— 给模块起个别名
import numpy as np
arr = np.array([1, 2, 3])
适合模块名很长或者你想避免命名冲突的情况。
4️⃣ from module import * —— 导入所有(谨慎使用!)
from math import *
print(sin(0)) # 0.0
这样会导入模块的所有公共内容,但不推荐,因为:
- 你不知道导入了哪些名字,可能覆盖已有的变量
- 代码可读性差,别人看不出函数来自哪个模块
🧠 冷知识:模块也是单例
一个模块无论被导入多少次,在整个解释器进程中只会被执行一次(第一次导入时)。后续的导入只是把已经加载的模块对象绑定到当前命名空间。所以不用担心重复导入的开销。
三、包:模块的集合
当模块越来越多,就需要用包来组织。包就是一个包含 __init__.py 文件的目录(Python 3.3+ 可以没有 __init__.py,成为命名空间包,但传统包还是推荐保留)。
mypackage/
__init__.py
module1.py
module2.py
subpackage/
__init__.py
module3.py
导入包中的模块
import mypackage.module1
from mypackage import module2
from mypackage.subpackage import module3
__init__.py 的作用
- 标识目录是 Python 包
- 可以在里面写初始化代码,或者定义
__all__控制from package import *导入的内容
四、模块搜索路径:Python 去哪找模块?
当你执行 import xxx,Python 会按照以下顺序搜索:
- 当前目录(或者脚本所在目录)
PYTHONPATH环境变量中的路径- 标准库目录
- 任何
.pth文件定义的路径
所有这些路径存放在 sys.path 列表中:
import sys
print(sys.path) # 打印模块搜索路径
你可以动态添加路径:
sys.path.append('/my/custom/path')
但更规范的做法是通过设置环境变量 PYTHONPATH,或者把模块安装到 site-packages。
五、入口惯用法:if __name__ == '__main__'
你肯定在很多 Python 脚本末尾看到过这个:
def main():
print("程序入口")
if __name__ == '__main__':
main()
这是干什么的?
每个 Python 模块都有一个内置属性 __name__:
- 当模块被直接运行时,
__name__被设为'__main__' - 当模块被导入时,
__name__被设为模块名(如'mytools')
所以这个判断可以让一段代码只在直接运行时执行,被导入时不执行。常用于:
- 测试代码
- 命令行入口
# test.py
def add(a, b):
return a + b
if __name__ == '__main__':
print("测试:2+3=", add(2, 3))
现在直接运行 python test.py 会执行测试;如果在其他文件导入 test,则不会打印测试信息。
🧠 冷知识:你也可以手动修改 __name__
虽然没人会这么干,但理论上你可以修改 __name__ 的值,影响它的行为。千万别在生产代码里这么玩。
六、常用内置模块巡礼
Python 标准库非常庞大,号称“内置电池”。这里精选一些最常用的,让你有个印象,用到时知道去哪查。
1️⃣ sys —— 系统相关
import sys
print(sys.version) # Python 版本
print(sys.argv) # 命令行参数列表
sys.exit(0) # 退出程序
2️⃣ os —— 操作系统接口
import os
print(os.getcwd()) # 当前工作目录
os.mkdir('newdir') # 创建目录
print(os.environ['PATH']) # 环境变量
3️⃣ math —— 数学函数
import math
print(math.pi) # 3.141592653589793
print(math.sqrt(2)) # 1.4142135623730951
print(math.factorial(5)) # 120
4️⃣ random —— 随机数
import random
print(random.random()) # [0,1) 随机浮点数
print(random.randint(1, 10)) # 1-10 随机整数
print(random.choice(['a','b','c'])) # 随机选一个
5️⃣ datetime —— 日期时间
from datetime import datetime, timedelta
now = datetime.now()
print(now.strftime("%Y-%m-%d %H:%M:%S"))
tomorrow = now + timedelta(days=1)
6️⃣ json —— JSON 数据
import json
data = {'name': 'Alice', 'age': 25}
json_str = json.dumps(data) # 序列化为 JSON 字符串
parsed = json.loads(json_str) # 解析回 Python 对象
7️⃣ pickle —— Python 对象序列化(注意安全!)
import pickle
data = {'name': 'Alice', 'scores': [90, 85, 88]}
with open('data.pkl', 'wb') as f:
pickle.dump(data, f) # 存到文件
with open('data.pkl', 'rb') as f:
loaded = pickle.load(f) # 加载
⚠️ 安全警告:永远不要 pickle.load 不可信的数据,可能执行恶意代码。
8️⃣ collections —— 高级容器
from collections import Counter, defaultdict, deque
# Counter 计数
words = ['a','b','a','c','b','a']
print(Counter(words)) # Counter({'a':3, 'b':2, 'c':1})
# defaultdict 默认值
dd = defaultdict(int) # 默认值 0
dd['count'] += 1
# deque 双端队列
dq = deque([1,2,3])
dq.appendleft(0) # [0,1,2,3]
9️⃣ itertools —— 迭代器工具
from itertools import count, cycle, permutations
# count 无限计数
for i in count(10): # 10,11,12...
if i > 15: break
# cycle 无限循环
colors = cycle(['红','黄','蓝'])
for _ in range(5):
print(next(colors)) # 红 黄 蓝 红 黄
# permutations 排列
print(list(permutations([1,2,3], 2))) # [(1,2),(1,3),(2,1),(2,3),(3,1),(3,2)]
🔟 functools —— 高阶函数工具
from functools import partial, lru_cache
# partial 固定参数
def power(base, exp):
return base ** exp
square = partial(power, exp=2)
print(square(5)) # 25
# lru_cache 缓存结果
@lru_cache(maxsize=128)
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
1️⃣1️⃣ argparse —— 命令行参数解析
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--name', default='world')
args = parser.parse_args()
print(f"Hello, {args.name}!")
1️⃣2️⃣ logging —— 日志
import logging
logging.basicConfig(level=logging.INFO)
logging.info("程序开始")
logging.error("出错了")
1️⃣3️⃣ pathlib —— 面向对象路径操作(3.4+)
from pathlib import Path
p = Path('/usr/bin/python3')
print(p.name) # python3
print(p.parent) # /usr/bin
print(p.exists()) # True
七、如何创建自己的模块和包
创建模块
随便写一个 .py 文件,比如 mymath.py:
# mymath.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
PI = 3.14
然后在同目录下的另一个文件中导入:
import mymath
print(mymath.add(5, 3))
创建包
创建目录结构:
mypkg/
__init__.py
stats.py
utils.py
__init__.py 可以为空,也可以写包的初始化代码。
stats.py:
def mean(data):
return sum(data) / len(data)
utils.py:
def echo(msg):
return msg
在其他地方导入:
from mypkg import stats
print(stats.mean([1,2,3,4,5]))
八、第三方模块:pip install 大法
标准库虽好,但总有覆盖不到的需求。这时就需要第三方模块。用 pip 安装:
pip install requests
然后在代码里导入:
import requests
response = requests.get('https://api.github.com')
print(response.status_code)
常用的第三方库我们在第20章会详细介绍。
九、常见陷阱与冷知识
1️⃣ 模块重复导入只执行一次
如前所述,模块是单例。但如果你用 importlib.reload() 可以强制重新加载(开发调试用)。
2️⃣ __pycache__ 目录是什么?
为了提高加载速度,Python 会把编译后的字节码缓存到 __pycache__ 目录里,文件名如 module.cpython-39.pyc。可以安全删除,但会减慢下次启动速度。
3️⃣ 循环导入(circular import)
如果 a.py 导入 b.py,而 b.py 又导入 a.py,就会形成循环导入,可能导致错误。解决办法是重构代码,把公共部分抽到第三个模块,或者在函数内部导入。
4️⃣ from module import * 和 __all__
模块可以定义 __all__ 列表,控制 from module import * 导入的内容。
# mymodule.py
__all__ = ['func1', 'CONST']
def func1(): pass
def func2(): pass # 不会被 import * 导入
CONST = 100
✅ 本章总结
| 概念 | 说明 |
|---|---|
| 模块 | 一个 .py 文件 |
| 包 | 包含 __init__.py 的目录 |
| 导入方式 | import, from ... import, as 别名 |
| 模块搜索路径 | sys.path,可动态添加 |
if __name__ == '__main__' |
判断是否直接运行 |
| 标准库常用模块 | sys, os, math, random, datetime, json, pickle, collections, itertools, functools, argparse, logging, pathlib 等 |
| 第三方模块 | 用 pip install 安装 |
| 循环导入 | 避免,必要时重构 |
🚀 下集预告
掌握了模块和包,你已经能站在巨人的肩膀上写代码了。下一章我们将学习 文件操作——如何读写文件、操作路径、用 with 管理资源。这些是几乎所有程序都离不开的技能。
记得动手试试:自己写个小模块,包含几个函数,然后在另一个文件里导入使用。再试试用 argparse 写个带命令行参数的小工具。实践出真知!🔥
🔗 上一篇:函数(基础篇):写一次,用一辈子
🔗 下一篇:文件操作:与硬盘对话的艺术(待更新)
更多推荐



所有评论(0)