Python基础④-装饰器、迭代器及常用函数篇
序言
本文聚焦于 Python 编程中的几个重要概念和工具,包括装饰器嵌套、迭代器、生成器、推导式以及常用内置函数。
这些知识点在数据处理、算法设计、性能优化等领域发挥着重要作用。
通过深入学习这些内容,我们可以让代码更加简洁、模块化,提高代码的可维护性和可读性,从而更好地应对复杂的编程需求。
1.装饰器嵌套
1.1 核心概念
装饰器能在不修改原函数代码的前提下,为函数添加额外功能(如日志、权限校验等 ),让代码更简洁、功能更易扩展。
一个函数可被多个装饰器依次装饰,执行时遵循特定顺序,像给函数层层包装
,每层装饰器实现独立功能。
1.2 代码示例与执行流程
def wrapper1(fn):def inner():print('wrapper1 前置逻辑')fn()print('wrapper1 后置逻辑')return innerdef wrapper2(fn):def inner():print('wrapper2 前置逻辑')fn()print('wrapper2 后置逻辑')return inner@wrapper1
@wrapper2
def target():print('我是目标')target()
执行顺序解析如下:
这张图说明了运行的逻辑和规律,
同理,3,4个及以上的装饰器也是同样的道理。
记住一个规则就是:
装饰器嵌套时,加载顺序是从下往上(靠近函数的装饰器先装饰 ),执行顺序是从上往下(外层装饰器先触发 )。
在需要为函数叠加多个独立功能时,如同时加日志记录、性能统计、权限校验,用嵌套装饰器能清晰拆分功能,让代码模块化、易维护。
2. 迭代器(Iterator)
迭代器用于遍历可迭代对象(如列表、元组等 ),统一不同数据类型的遍历逻辑,让遍历操作更规范、灵活。
2.1 获取迭代器的方式
iter()
内置函数:
对可迭代对象调用 iter()
可获取其迭代器。
lst = [1, 2, 3]
it = iter(lst) # 获取列表的迭代器
__iter__()
特殊方法:
可迭代对象内部实现了 __iter__()
方法,调用该方法也能获取迭代器(iter()
底层就是调用此方法 )。
示例(模拟可迭代对象逻辑 ):
class MyIterable:def __init__(self, data):self.data = datadef __iter__(self):return iter(self.data)
mi = MyIterable([4, 5, 6])
it = mi.__iter__() # 等价于 iter(mi)
2.2 从迭代器中获取数据
next()
内置函数:
调用 next()
可逐个获取迭代器中的数据,迭代到末尾再调用会抛出 StopIteration
异常。
lst = [1, 2, 3]
it = iter(lst)
print(next(it)) # 输出 1
print(next(it)) # 输出 2
__next__()
特殊方法:
迭代器对象实现了 __next__()
方法,next()
函数底层调用该方法。
lst = [1, 2, 3]
it = iter(lst)
print(it.__next__()) # 输出 1,效果同 next(it)
2.3 迭代器与for循环的关系
for
循环本质是迭代器的语法糖,它会自动获取可迭代对象的迭代器,然后循环调用 next()
获取数据,直到捕获 StopIteration
异常结束循环。所以不可迭代的对象(未实现 __iter__()
等迭代协议 )无法用 for
循环遍历。
lst = [1, 2, 3]
# for 循环底层逻辑模拟
it = iter(lst)
while True:try:print(next(it))except StopIteration:break
这里的try跟except的意思是:我们在一个循环里尝试运行print(next(it))
这个程序,当捕获到StopIteration
异常时,while
循环会通过break
语句终止,从而结束迭代过程,但此时你程序循环外写的语句还是能够被正常执行。
2.4 迭代器的特性
迭代器自身也是可迭代的,同时具备以下特性:
2.4.1 单向遍历
迭代器只能从前往后逐个遍历数据,遍历过的元素无法再回退访问,就像读文件时的指针,只能单向移动。
it = iter([1, 2, 3])
print(next(it)) # 1,指针移动到下一个位置
print(next(it)) # 2,继续后移
# 无法再获取到 1
2.4.2 节省内存
迭代器按需生成数据,不会一次性把所有数据加载到内存,遍历大型数据集时优势明显。比如遍历一个包含百万级数据的生成器,迭代器每次只生成一个数据并返回,内存占用始终很低。
2.4.3 惰性机制
迭代器遵循惰性计算
原则,在调用 next()
时才会生成并返回下一个数据,不调用则不执行任何计算,有效提升程序性能,避免不必要的资源消耗。
3. 生成器(Generator)
生成器本质就是迭代器,它简化了迭代器的创建过程,可以更便捷地实现自定义遍历逻辑,同时继承了迭代器的特性。
3.1 创建生成器的方式
3.1.1 生成器函数
函数体中包含 yield
关键字的函数就是生成器函数,调用它不会执行函数体代码,而是返回一个生成器对象。
def my_generator():yield 1yield 2yield 3
gen = my_generator() # 返回生成器对象,不执行函数体
print(next(gen)) # 执行到第一个 yield,返回 1
print(next(gen)) # 执行到第二个 yield,返回 2
yield
的作用就是,它是一种可返回数据,类似return
,但yield
不会终止函数执行,只是暂停并返回值。
此外,它支持分段执行函数内容,每次调用 next()
(或 __next__()
),函数会从上次 yield
的位置继续执行到下一个 yield
处。
3.1.2 生成器表达式
语法:类似列表推导式,把方括号 []
换成圆括号 ()
。
gen = (x * 2 for x in range(3)) # 创建生成器,按需生成数据
print(next(gen)) # 0 * 2 = 0
print(next(gen)) # 1 * 2 = 2
4. 推导式(Comprehension)
推导式用于简化数据结构(列表、集合、字典 )的创建过程,让代码更简洁、高效。
4.1 列表推导式
[数据 for 循环 if 判断]
,遍历可迭代对象,根据条件筛选并处理数据,生成新列表。
# 生成 0-4 每个数的平方组成的列表
square_lst = [x ** 2 for x in range(5)]
print(square_lst) # 输出 [0, 1, 4, 9, 16]# 筛选出 0-9 中的偶数并乘 2
even_lst = [x * 2 for x in range(10) if x % 2 == 0]
print(even_lst) # 输出 [0, 4, 8, 12, 16]
这个实际上等价于for循环遍历计算输出的,但这里列表推导式就能给你用一行程序实现这个功能。
4.2 集合推导式
{数据 for 循环 if 判断}
,逻辑与列表推导式类似,但生成的是集合(自动去重 )。
# 生成 0-4 每个数的平方组成的集合
square_set = {x ** 2 for x in range(5)}
print(square_set) # 输出 {0, 1, 4, 9, 16}(集合元素无序)# 筛选出字符串中不重复的字母(忽略大小写 )
s = "Hello World"
unique_chars = {c.lower() for c in s if c.isalpha()}
print(unique_chars) # 输出 {'h', 'e', 'l', 'o', 'w', 'r', 'd'}
4.3 字典推导式
{k: v for 循环 if 判断}
,用于创建字典,k
是键,v
是对应的值。
# 生成键为 0-4,值为对应键平方的字典
square_dict = {x: x ** 2 for x in range(5)}
print(square_dict) # 输出 {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}# 交换字典的键和值(原字典值需可哈希 )
original_dict = {'a': 1, 'b': 2}
reversed_dict = {v: k for k, v in original_dict.items()}
print(reversed_dict) # 输出 {1: 'a', 2: 'b'}
这里可以看到推导式虽简洁,但复杂逻辑下很容易降低代码可读性,还是得合理使用。
5. 常用内置函数
5.1 zip
函数
这个函数将多个可迭代对象(如列表、元组 )中对应位置的元素打包成元组,返回一个迭代器,长度以最短的可迭代对象为准。
lst1 = [1, 2, 3]
lst2 = ['a', 'b', 'c']
zipped = zip(lst1, lst2) # 返回迭代器
# 转换为列表查看内容
print(list(zipped)) # 输出 [(1, 'a'), (2, 'b'), (3, 'c')]
同时遍历多个可迭代对象,配对处理对应元素,比如还可以通过以下程序将两个列表的元素一一关联成字典。
keys = ['a', 'b', 'c']
values = [1, 2, 3]
new_dict = {k: v for k, v in zip(keys, values)}
print(new_dict) # 输出 {'a': 1, 'b': 2, 'c': 3}
5.2 sorted
函数
对可迭代对象进行排序,返回一个新的排序列表,默认升序,可通过 key
参数自定义排序规则,reverse
参数控制升序/降序。
lst = [3, 1, 2]
# 默认升序排序
sorted_lst = sorted(lst)
print(sorted_lst) # 输出 [1, 2, 3]# 降序排序
sorted_lst_desc = sorted(lst, reverse=True)
print(sorted_lst_desc) # 输出 [3, 1, 2]# 按字符串长度排序(对列表里的字符串排序 )
str_lst = ['apple', 'banana', 'cherry']
sorted_by_len = sorted(str_lst, key=len)
print(sorted_by_len) # 输出 ['apple', 'cherry', 'banana']
5.3 filter
函数
根据条件筛选可迭代对象中的元素,返回一个迭代器。接收两个参数,第一个是判断函数(返回布尔值 ),第二个是可迭代对象。
def is_even(x):return x % 2 == 0
lst = [1, 2, 3, 4]
filtered = filter(is_even, lst)
# 转换为列表查看结果
print(list(filtered)) # 输出 [2, 4]
filter
和 map
返回的都是迭代器(生成器的一种 ),如需查看完整结果或进行多次遍历,可通过 list()
转换为列表,但要注意内存消耗,大型数据场景下按需使用。
通过学习迭代器、生成器、推导式及这些内置函数,能更高效地处理 Python 中的数据遍历、创建和转换任务。
小结
本学习笔记从装饰器、迭代器、生成器以及常用内置函数这几个方面进行讲解说明,希望对读者有帮助。