第十一章:Python进阶话题
11.1 迭代器与生成器
11.1.1 迭代器
理论知识:迭代器是一个实现了迭代器协议的对象,即包含 __iter__() 和 __next__() 方法。__iter__() 方法返回迭代器对象本身,__next__() 方法返回容器的下一个元素,如果没有元素则引发 StopIteration 异常。Python 中的许多数据结构(如列表、元组、字典等)都是可迭代对象,可通过 iter() 函数将其转换为迭代器。迭代器允许我们逐个访问集合中的元素,而无需一次性加载整个集合到内存中,这在处理大数据集时非常高效。
示例代码:
my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list)
try:
while True:
element = next(my_iterator)
print(element)
except StopIteration:
pass
代码解释:
- 首先创建一个列表 my_list,然后使用 iter() 函数将其转换为迭代器 my_iterator。
- 在 while 循环中,通过 next() 函数不断获取迭代器的下一个元素并打印。当没有更多元素时,next() 函数会引发 StopIteration 异常,此时通过 try - except 语句捕获并结束循环。
11.1.2 生成器
理论知识:生成器是一种特殊的迭代器,它的创建方式更加简洁。生成器使用 yield 关键字来暂停函数的执行并返回一个值,当再次调用生成器时,它会从暂停的地方继续执行。生成器函数在调用时不会立即执行函数体,而是返回一个生成器对象。生成器同样具有惰性求值的特点,只有在需要时才生成值,从而节省内存。
示例代码:
def number_generator(n):
for i in range(n):
yield i
gen = number_generator(5)
for num in gen:
print(num)
代码解释:
- 定义了一个生成器函数 number_generator,它接受一个参数 n,在函数内部使用 yield 关键字依次返回 range(n) 中的值。
- 调用 number_generator(5) 创建一个生成器对象 gen,然后通过 for 循环迭代这个生成器对象,每次迭代时,生成器函数从上次暂停的地方继续执行,生成下一个值并赋值给 num 进行打印。
11.2 装饰器
11.2.1 理论知识
装饰器是 Python 中一种强大的语法结构,本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器可以在不修改原函数代码的情况下,为原函数添加额外的功能,如日志记录、性能测试、权限验证等。装饰器使用 @ 符号加上装饰器函数名,放在需要装饰的函数定义之前。
11.2.2 示例代码
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"调用函数 {func.__name__}")
result = func(*args, **kwargs)
print(f"{func.__name__} 函数调用结束")
return result
return wrapper
@log_decorator
def add_numbers(a, b):
return a + b
result = add_numbers(3, 5)
print(f"两数之和: {result}")
代码解释:
- 定义了一个装饰器函数 log_decorator,它接受一个函数 func 作为参数。在 log_decorator 内部定义了一个 wrapper 函数,wrapper 函数在调用原函数 func 前后分别打印日志信息,然后返回原函数的执行结果。log_decorator 最后返回 wrapper 函数。
- 使用 @log_decorator 装饰 add_numbers 函数,这相当于执行了 add_numbers = log_decorator(add_numbers)。
- 调用 add_numbers(3, 5) 时,实际调用的是被装饰后的 wrapper 函数,因此会先打印调用函数的日志,执行加法运算后再打印函数调用结束的日志,最后返回并打印两数之和。
11.3 上下文管理器
11.3.1 理论知识
上下文管理器用于管理资源的分配和释放,确保在代码块开始时资源被正确分配,在代码块结束时资源被正确释放。例如,文件的打开和关闭、数据库连接的建立和断开等场景。Python 中的 with 语句就是基于上下文管理器实现的。要创建自定义的上下文管理器,可以定义一个包含 __enter__() 和 __exit__() 方法的类,或者使用 contextlib.contextmanager 装饰器来创建基于生成器的上下文管理器。
11.3.2 示例代码(基于类的上下文管理器)
class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_value, traceback):
if self.file:
self.file.close()
with FileManager('example.txt', 'w') as file:
file.write('这是使用自定义上下文管理器写入的内容')
代码解释:
- 定义了 FileManager 类作为上下文管理器。__init__() 方法初始化文件名和打开模式,并将文件对象初始化为 None。
- __enter__() 方法打开文件并返回文件对象,这个返回值会赋值给 with 语句中的 file 变量。
- __exit__() 方法在 with 代码块结束时被调用,负责关闭文件。无论 with 代码块中是否发生异常,__exit__() 都会执行。
11.3.3 示例代码(基于生成器的上下文管理器)
from contextlib import contextmanager
@contextmanager
def file_manager(filename, mode):
file = open(filename, mode)
try:
yield file
finally:
file.close()
with file_manager('example.txt', 'r') as file:
content = file.read()
print(content)
代码解释:
- 使用 contextlib.contextmanager 装饰器定义了 file_manager 函数作为上下文管理器。函数内部打开文件,然后使用 yield 暂停函数执行并返回文件对象,这个文件对象会赋值给 with 语句中的 file 变量。
- yield 之后的代码在 with 代码块结束时执行,这里使用 finally 确保无论是否发生异常,文件都会被关闭。
11.4 元类
11.4.1 理论知识
元类是创建类的类,它定义了类的结构和行为。在 Python 中,所有的类都是 type 元类的实例。通过自定义元类,可以控制类的创建过程,例如动态修改类的属性、方法,或者对类进行验证等。元类的使用场景相对较少,但在一些高级的框架开发中非常有用。
11.4.2 示例代码
class MyMeta(type):
def __new__(cls, name, bases, attrs):
attrs['new_attribute'] = '这是通过元类添加的属性'
return super().__new__(cls, name, bases, attrs)
class MyClass(metaclass = MyMeta):
pass
obj = MyClass()
print(obj.new_attribute)
代码解释:
- 定义了一个元类 MyMeta,它继承自 type。__new__() 方法是元类中用于创建类对象的方法,它接受类名 name、基类元组 bases 和属性字典 attrs 作为参数。
- 在 __new__() 方法中,向 attrs 字典添加了一个新的属性 new_attribute,然后通过调用父类的 __new__() 方法创建并返回新的类对象。
- 定义 MyClass 类时,指定 metaclass = MyMeta,这使得 MyClass 由 MyMeta 元类创建。
- 创建 MyClass 的实例 obj,并访问通过元类添加的 new_attribute 属性并打印。