Python三大器:装饰器、迭代器、生成器
Python的“三大器”通常指的是迭代器(Iterators)、生成器(Generators)和装饰器(Decorators)。这三种构造是Python中非常强大的功能,广泛应用于各种编程场景中,特别是在处理数据流、函数增强和代码抽象方面。
迭代器(Iterators)
迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。迭代器有两个基本的方法:iter() 和 next()。字符串、列表或元组对象都可用于创建迭代器:
my_list = [1, 2, 3, 4]
my_iter = iter(my_list)
print(next(my_iter)) # 输出 1
print(next(my_iter)) # 输出 2
生成器(Generators)
生成器是一种用普通函数语法定义的迭代器。它们使用yield语句每次产生一个值,暂停执行,保存执行状态,以便下次从它离开的地方继续执行。生成器提供了一种高效的方式来处理大数据集,因为它们在任何时候只需处理数据集中的一部分,而不是在开始时就加载整个数据集到内存中。
def my_generator():
n = 1
print('This is printed first')
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
for item in my_generator():
print(item)
装饰器(Decorators)
装饰器是修改其他函数的功能的函数。它们提供了一种简单的方法来修改函数、方法或类的行为,而不需要改动它们的代码。装饰器在定义时使用@符号,紧跟在函数的定义之前。装饰器可以被认为是返回另一个函数的函数,通常用于在不修改原始函数代码的情况下增加额外的功能。
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
动态传参
- 使用*args处理不定数量的位置参数
当你不确定调用函数时会传递多少个参数,或者想要允许函数接受任意数量的参数时,可以使用args。在函数定义中,参数前的星号表示将所有位置参数(那些没有被命名的参数)收集到一个名为args的元组中。
def print_args(*args):
for arg in args:
print(arg)
print_args('one', 'two', 'three')
- 使用**kwargs处理不定数量的关键字参数
与*args类似,**kwargs允许你处理那些在函数调用时提供的不定数量的关键字参数。这些关键字参数被打包进一个字典中,其中参数名是字典的键,参数值是字典的值。
def print_kwargs(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_kwargs(first='one', second='two', third='three')
- 组合使用*args和**kwargs
你可以在同一个函数定义中同时使用args和**kwargs来允许它接受任意数量的位置参数和关键字参数。
注意,当同时使用args和kwargs时,*args必须在kwargs之前。
def print_all_args(*args, **kwargs):
for arg in args:
print(arg)
for key, value in kwargs.items():
print(f"{key}: {value}")
print_all_args('one', 'two', third='three', fourth='four')
- 函数调用时使用和*
同样地,当调用函数时,你也可以使用*和**语法来展开序列或字典,作为参数传递给函数。
args = [1, 2, 3]
kwargs = {'a': 4, 'b': 5}
def func(*args, **kwargs):
print(args)
print(kwargs)
func(*args, **kwargs)
闭包
- 闭包的创建涉及三个关键点:
- 必须有一个嵌套函数(函数内部定义的函数)。
- 嵌套函数必须引用其外部作用域中的变量。
- 外部函数必须返回嵌套函数。
通用装饰器写法
- 解决被装饰函数存在参数与返回值的问题
# 装饰器
def wrapper(fn):
def inner(*args, **kwargs):
"""在执行目标函数之前"""
ret = fn(*args, **kwargs) # 处理目标函数的返回值
"""在执行目标函数之后"""
return ret
return inner
# 目标函数
@wrapper
def target():
pass
# 执行
target()
同一个函数有多个装饰器
- 装饰器
def decorator1(func):
def wrapper():
print("Decorator1 before function execution")
func()
print("Decorator1 after function execution")
return wrapper
def decorator2(func):
def wrapper():
print("Decorator2 before function execution")
func()
print("Decorator2 after function execution")
return wrapper
- 使用装饰器
@decorator1
@decorator2
def say_hello():
print("Hello!")
- 调用&&输出
say_hello()
Decorator1 before function execution
Decorator2 before function execution
Hello!
Decorator2 after function execution
Decorator1 after function execution
- 装饰器执行顺序
理解装饰器的执行顺序非常重要,特别是当装饰器影响函数的执行方式时。装饰器的执行顺序遵循“先进后出”的规则,可以想象成一个栈结构,最后应用的装饰器会首先执行其额外的逻辑。
参数化装饰器
当装饰器接受参数时,需要添加另一层函数来处理这些参数。这会稍微复杂一些,但原理相同。每个装饰器依然是从下到上应用,只不过每个装饰器本身可能会因为参数而有更复杂的行为。
在这个例子中,say_goodbye
函数首先被repeat
装饰器修饰,repeat
装饰器接受一个参数times
,然后是decorator1
。这展示了即便装饰器接受参数,装饰器的应用顺序和行为规则依然不变。
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@decorator1
@repeat(2)
def say_goodbye():
print("Goodbye!")
def gua_outer(name):
def gua(fn):
def inner(*args, **kwargs):
print(f"开启{name}外挂")
ret = fn(*args, **kwargs)
print("关闭外挂")
return ret
return inner
return gua
@gua_outer("锁血") # 先执行函数的调用,函数返回一个装饰器,和@组合成语法糖
def dnf():
print('我要打LOL')
@gua_outer("自瞄")
def cs_go():
print("我要打CSGO")