1模块:代码的"乐高积木"
模块就是一个 .py 文件。你写的每个 Python 文件,都可以被其他文件导入使用。这样就不用把所有代码塞在一个文件里了。
三种导入方式
案例:导入 Python 内置模块
# 方式1:导入整个模块import mathprint(math.pi) # 3.141592653589793print(math.sqrt(16)) # 4.0# 方式2:只导入需要的东西from math import pi, ceilprint(ceil(3.2)) # 4# 方式3:给模块起别名(避免名字冲突)import datetime as dtnow = dt.datetime.now()print(now.strftime("%Y-%m-%d")) # 2026-07-03
💡 建议:初学阶段优先用 import 模块名,代码里写 math.pi 比直接写 pi 更清晰,也避免命名冲突。
2自定义模块
把你写好的函数放在一个文件里,其他文件就能导入它。我们来创建一个 tools.py 工具模块。
案例:创建并使用自定义模块
# ===== tools.py 文件内容 ====="""常用工具函数集合"""def is_prime(n): """判断是否为质数""" if n < 2: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return Truedef fibonacci(n): """生成前n个斐波那契数""" fibs = [0, 1] while len(fibs) < n: fibs.append(fibs[-1] + fibs[-2]) return fibs[:n]# ===== main.py 文件内容 =====from tools import is_prime, fibonacciprint(is_prime(17)) # Trueprint(fibonacci(10)) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
3包:模块的文件夹
当模块多了,就按文件夹分门别类——这就是"包"。包就是一个包含 __init__.py 文件的文件夹。
项目结构示例
my_project/ ├── main.py # 主程序 ├── utils/ # 工具包 │ ├── __init__.py # 包标识文件(可以为空) │ ├── math_tools.py # 数学工具模块 │ └── str_tools.py # 字符串工具模块 └── models/ # 数据模型包 ├── __init__.py └── user.py |
# main.py 中导入包里的模块from utils.math_tools import is_primefrom utils.str_tools import capitalize_allfrom models.user import User
💡 一句话理解:模块 = 一个 .py 文件;包 = 一个装了多个 .py 文件的文件夹。作用都是分而治之,让代码有结构。
4装饰器:给函数自动"加buff"
装饰器是一种"不修改原函数代码,就能给它增加功能"的技术。最常见用途:计时、日志、权限校验。
你可以把装饰器理解为" gift wrapping"——不改变礼物本身,但在外面包一层漂亮的包装纸。
案例1:函数计时器
import time# 定义装饰器def timer(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) # 执行原函数 elapsed = time.time() - start print(f"⏱ {func.__name__} 耗时 {elapsed:.4f} 秒") return result return wrapper# 用 @ 应用装饰器@timerdef slow_sum(n): """计算1到n的和""" total = 0 for i in range(n + 1): total += i return totalprint(slow_sum(1000000))
运行结果:⏱ slow_sum 耗时 0.0512 秒500000500000 |
案例2:带参数的装饰器——日志记录
def log(level="INFO"): """带参数的装饰器,三层嵌套""" def decorator(func): def wrapper(*args, **kwargs): print(f"[{level}] 调用 {func.__name__},参数:{args}") result = func(*args, **kwargs) print(f"[{level}] {func.__name__} 执行完毕") return result return wrapper return decorator@log(level="DEBUG")def add(a, b): return a + bprint(f"结果:{add(3, 5)}")
| 运行结果: [DEBUG] 调用 add,参数:(3, 5)[DEBUG] add 执行完毕结果:8 |
💡 装饰器执行顺序:@timer 等价于 slow_sum = timer(slow_sum)。调用 slow_sum(1000000) 实际上调用的是 wrapper(1000000),wrapper 内部再调用真正的 slow_sum。
5生成器:处理大数据不吃内存
普通函数用 return 返回结果,一次返回就结束了。生成器用 yield 返回,可以暂停-恢复,一次只产出一个值,内存占用极低。
案例1:生成器 vs 列表
# 普通列表:一次性生成100万个数,全部存在内存big_list = [range(1000000)]print(len(big_list)) # 1(实际上range本身就很省)# 但如果这样写,内存会爆# big_list = [x**2 for x in range(10000000)] # 列表推导式,全部加载# 生成器表达式:一次只算一个,不吃内存big_gen = (x**2 for x in range(10000000))print(next(big_gen)) # 0print(next(big_gen)) # 1print(next(big_gen)) # 4
案例2:用 yield 写生成器函数
def countdown(n): """倒数生成器""" while n > 0: yield n # 产出值,暂停 n -= 1 # 恢复后继续执行# 使用生成器for num in countdown(5): print(num, end=" ") # 5 4 3 2 1print()# 读取大文件:一行一行yield,不吃内存def read_large_file(filepath): with open(filepath, "r", encoding="utf-8") as f: for line in f: yield line.strip()# 10GB的文件也能轻松遍历# for line in read_large_file("huge_data.txt"):# process(line) # 每次只有一行在内存里
💡 什么时候用生成器?① 处理大文件/大数据,内存放不下;② 数据是"流水线"式产生,不需要随机访问;③ 生成无限序列(如斐波那契数列)。
6推导式进阶
上一篇学过列表推导式,这里补充字典推导式和集合推导式——一行代码完成循环+条件+构建。
案例:三种推导式
# 列表推导式:筛选+变换nums = range(1, 11)evens = [x for x in nums if x % 2 == 0]print(evens) # [2, 4, 6, 8, 10]# 字典推导式:键值对变换scores = {"语文": 85, "数学": 92, "英语": 78}grades = {k: "优" if v >= 90 else "良" if v >= 80 else "中" for k, v in scores.items()}print(grades) # {'语文': '良', '数学': '优', '英语': '中'}# 集合推导式:去重words = "hello world hello python".split()unique = {w.upper() for w in words}print(unique) # {'HELLO', 'WORLD', 'PYTHON'}
7综合实战:带日志的质数筛选器
把模块、装饰器、生成器三个知识点串起来,写一个"带计时和日志的质数筛选器"。
案例:prime_sieve.py
import time# ===== 装饰器:计时 + 日志 =====def profile(func): def wrapper(*args, **kwargs): print(f"[LOG] 开始执行 {func.__name__}") start = time.time() result = list(func(*args, **kwargs)) # 生成器转列表 elapsed = time.time() - start print(f"[LOG] {func.__name__} 耗时 {elapsed:.4f}s,产出 {len(result)} 个结果") return result return wrapper# ===== 生成器:逐个产出质数 =====@profiledef prime_generator(max_num): """生成小于max_num的所有质数""" for num in range(2, max_num): is_prime = True for i in range(2, int(num**0.5) + 1): if num % i == 0: is_prime = False break if is_prime: yield num # 生成器:一次产出一个质数# ===== 主程序 =====primes = prime_generator(10000)print(f"前10个质数:{primes[:10]}")print(f"最大的5个质数:{primes[-5:]}")
| 运行结果: [LOG] 开始执行 prime_generator[LOG] prime_generator 耗时 0.0031s,产出 1229 个结果前10个质数:[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]最大的5个质数:[9929, 9931, 9941, 9949, 9967] |
💡 这个案例用到了:自定义装饰器(@profile)、生成器函数(yield)、list() 将生成器转为列表、time 模块计时。三个知识点协同工作。
本篇小结
- 模块
- 包是包含
__init__.py 的文件夹,组织多个模块 - 装饰器用
@ 语法,不修改原函数就能加功能(计时/日志/权限) - 生成器用
yield,一次产出一个值,处理大数据不吃内存 - 推导式有列表、字典、集合三种,一行代码完成循环+条件+构建
下一篇我们将进入第三方库实战——用 requests 抓网页、用 pandas 处理数据、用 json 解析接口,真正用 Python "干活"。
Python · 模块 · 装饰器 · 生成器 · 连载第3篇
觉得有用?收藏起来慢慢看,转发给想学编程的朋友吧 👍