文章目录
前言
掌握Python高阶特性,是告别"脚本小子"、迈向优雅编程的关键一步。本文将带你深入三个核心利器------装饰器、生成器与上下文管理器,从原理到实践,揭开Pythonic代码的神秘面纱。
一、装饰器
1.1什么是装饰器
装饰器是一种特殊的函数。它的作用是修改其他函数的行为。你可以在不改动原函数代码的情况下,给函数增加新功能。
这就像给手机套一个壳。手机本身没有变,但多了保护功能。
装饰器的优势:
- 不修改原始函数的代码,就能增强功能
- 代码更模块化,便于复用
1.2装饰器的执行原理
装饰器的本质是一个高阶函数。高阶函数就是接收函数作为参数,或则返回函数的函数。
最简单的装饰器:
python
# 定义一个装饰器
def my_decorator(func):
# 内部函数包裹原函数
def wrapper():
print("函数执行之前")
func() # 调用原函数
print("函数执行之后")
return wrapper
# 使用装饰器
@my_decorator
def say_hello():
print("你好")
say_hello()
运行结果:
plain
函数执行之前
你好
函数执行之后
代码详解:
my_decorator接收一个函数func作为参数wrapper是内部函数,它在原函数前后添加了新逻辑@my_decorator是语法糖,等价于say_hello = my_decorator(say_hello)- 调用
say_hello()时,实际执行的是wrapper()
带参数的装饰器:
python
def my_decorator(func):
def wrapper(*args, **kwargs):
print("函数执行之前")
result = func(*args, **kwargs) # 传递参数给原函数
print("函数执行之后")
return result
return wrapper
@my_decorator
def add(a, b):
return a + b
result = add(1, 2)
print(result)
plain
函数执行之前
函数执行之后
3
代码详解:
*args接收所有位置参数,**kwargs接收所有关键字参数- 这样装饰器就能包裹任何参数的函数
1.3装饰器参数
有时候装饰器本身也需要参数。比如你想要控制是否打印日志。
带参数的装饰器需要三层嵌套:
python
def log_decorator(enabled=True):
# 第一层接收装饰器参数
def decorator(func):
# 第二层接收被装饰的函数
def wrapper(*args, **kwargs):
# 第三层是实际的包裹逻辑
if enabled:
print(f"正在调用函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
return decorator
# 使用带参数的装饰器
@log_decorator(enabled=True)
def greet(name):
print(f"你好, {name}")
greet("张三")
plain
正在调用函数: greet
你好, 张三
代码详解:
- 第一层
log_decorator接收装饰器自己的参数 - 第二层
decorator接收被装饰的函数 - 第三层
wrapper执行实际的包裹逻辑
1.4装饰器的返回值
装饰器可以修改原函数的返回值。
python
def double_result(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result * 2 # 返回值翻倍
return wrapper
@double_result
def get_number():
return 5
print(get_number()) # 输出10
实际应用场景:计算函数执行时间
python
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"函数{func.__name__}执行了{end - start:.4f}秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
return "完成"
slow_function()
二、迭代器与生成器
2.1什么是迭代器
迭代器是一种对象。它可以让你逐个访问集合中的元素,而不需要一次性把所有的元素都加载到内存里。
你可以把迭代器理解为一个水龙头。水一滴一滴流出来,而不是一桶水直接倒出来。
2.2迭代器的原理
迭代器对象必须实现两个方法:
__iter__():返回迭代器对象本身__next__():返回下一个元素,没有元素时抛出StopIteration异常
python
class MyIterator:
def __init__(self, max_num):
self.max_num = max_num
self.current = 0
def __iter__(self):
# 返回迭代器对象本身
return self
def __next__(self):
# 返回下一个元素
if self.current < self.max_num:
num = self.current
self.current += 1
return num
else:
# 没有元素了,抛出异常
raise StopIteration
# 使用迭代器
my_iter = MyIterator(5)
for num in my_iter:
print(num)
plain
0
1
2
3
4
代码详解:
__init__初始化迭代器,设置最大值和当前值__iter__返回自身,让迭代器可以被for循环使用__next__每次调用返回下一个值,直到没有值可返回
2.3什么是生成器
生成器是一种特殊的迭代器。它用函数来定义,而不是类。
生成器函数使用yield关键字。当执行到yield时,函数会暂停,并返回一个值。下次调用时,函数从暂停的地方继续执行。
2.4生成器的原理
python
def my_generator():
print("开始执行")
yield 1 # 暂停,返回1
print("继续执行")
yield 2 # 暂停,返回2
print("再次继续")
yield 3 # 暂停,返回3
print("执行结束")
# 使用生成器
gen = my_generator()
# 手动获取下一个值
print(next(gen)) # 输出1
print(next(gen)) # 输出2
print(next(gen)) # 输出3
# next(gen) 再次调用会抛出StopIteration
plain
开始执行
1
继续执行
2
再次继续
3
代码详解:
- 调用
my_generator()不会执行函数体,而是返回一个生成器对象 next()触发函数执行,直到遇到yield- 每次
yield后函数暂停,状态被保存 - 下次
next()从暂停处继续执行
用for循环遍历生成器:
python
def count_up_to(max_num):
count = 1
while count <= max_num:
yield count
count += 1
# 使用生成器
for num in count_up_to(5):
print(num)
生成器表达式:
python
# 列表推导式,一次性生成所有元素
my_list = [x * 2 for x in range(5)]
print(my_list) # [0, 2, 4, 6, 8]
# 生成器表达式,按需生成元素
my_gen = (x * 2 for x in range(5))
print(next(my_gen)) # 0
print(next(my_gen)) # 2
2.5生成器与迭代器的区别
| 对比项 | 迭代器 | 生成器 |
|---|---|---|
| 定义方式 | 用类定义,需要写__iter__和__next__ |
用函数定义,使用yield |
| 代码量 | 较多 | 较少,更简洁 |
| 状态保存 | 手动管理 | 自动保存,由Python处理 |
| 内存占用 | 取决于实现 | 惰性计算,占用小 |
三、上下文管理器
3.1什么是上下文管理器
上下文管理器用于管理资源的生命周期。它确保资源在使用前正确打开,在使用后正确关闭。
最常见的例子是文件操作。打开文件后,必须关闭文件。上下文管理器可以自动帮你关闭。
基本用法:
python
# 不使用上下文管理器
file = open("test.txt", "w")
file.write("你好")
file.close() # 容易忘记关闭
# 使用上下文管理器
with open("test.txt", "w") as file:
file.write("你好")
# 退出with块时,文件自动关闭
3.2是哪个下文管理器的应用场景
场景一:文件操作
python
# 读取文件
with open("data.txt", "r") as file:
content = file.read()
print(content)
# 文件自动关闭,即使发生异常也会关闭
# 同时操作多个文件
with open("source.txt", "r") as source, open("target.txt", "w") as target:
target.write(source.read())
场景二:数据库连接
python
import sqlite3
# 使用上下文管理器管理数据库连接
with sqlite3.connect("mydb.db") as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
results = cursor.fetchall()
print(results)
# 连接自动关闭
场景三:自定义上下文管理器
可以用类来实现自定义的上下文管理器。需要实现__enter__和__exit__两个方法。
py
class MyContext:
def __enter__(self):
# 进入上下文时执行
print("进入上下文")
return self # 返回的对象会赋值给as后面的变量
def __exit__(self, exc_type, exc_val, exc_tb):
# 退出上下文时执行
# exc_type: 异常类型
# exc_val: 异常值
# exc_tb: 异常追踪信息
print("退出上下文")
return True # 返回True表示异常已被处理
# 使用自定义上下文管理器
with MyContext() as ctx:
print("执行中")
运行结果:
plain
进入上下文
执行中
退出上下文
结语
装饰器让功能扩展如行云流水,生成器让内存效率化繁为简,上下文管理器让资源管控稳若磐石。三者皆是Python"简洁即美"哲学的最佳诠释。善用它们,你写出的将不再是能运行的代码,而是值得品味的工程艺术。