1. 装饰器语法糖示例
注解形式:
# 1定义一个装饰器(装饰器的本质是闭包) def check(fn): def inner(): print("请先登陆") fn() return inner # 2使用装饰器装饰函数(增加一个登陆功能) # 解释器遇到@check 会立即执行 comment = check(comment) @check def comment(): print("发表评论") comment()
真实面目:
1 # 1. 定义一个装饰器(装饰器的本质是闭包) 2 def check(fn): 3 def inner(): 4 print("登陆验证。。。") 5 fn() 6 7 return inner 8 9 10 # 需要被装饰的函数 11 def comment(): 12 print("发表评论") 13 14 15 # 2. 使用装饰器装饰函数(增加一个登陆功能) 16 comment = check(comment) # comment函数就是被装饰器装饰后的函数 17 18 # 3. 执行装饰器函数 19 comment()
输出结果:
登陆验证。。。 发表评论
一句话总结:利用闭包特点、不改变函数源码,为其执行前后添加功能。
2. 装饰有参数的函数
1 # 1. 定义装饰器 2 def logging(fn): # fn = sum_num,如果只有1个参数,此参数的实参必须是被修饰函数 3 def inner(a, b): # 内部函数的参数列表,必须直接或间接包含被装饰的参数列表 4 print("被装饰函数执行之前") 5 fn(a, b) 6 print("被装饰函数执行之后") 7 8 return inner # sum_num = inner 9 10 11 # 2. 使用装饰器装饰函数 12 @logging 13 def sum_num(a, b): 14 result = a + b 15 print(result) 16 17 18 # 3. 执行被装饰函数验证 19 sum_num(1, 2) # 输出结果是3
执行结果:
被装饰函数执行之前 3 被装饰函数执行之后
总结:
1. 装饰器就是闭包
2. 装饰器的外部函数的参数的实参必须是被装饰函数
3. 内部函数的参数直接或间接包含被装饰函数的列表
3. 装饰有返回值的函数
1 # 1. 定义装饰器 2 def logging(fn): # fn = sum_num,如果只有1个参数,此参数的实参必须是被修饰函数 3 def inner(a, b): 4 print("被装饰函数执行之前") 5 result = fn(a, b) # 内部函数的参数列表,必须直接或间接包含被装饰的参数列表 6 print(f"被装饰函数执行之后,结果为:{result}") 7 return result 8 9 return inner # sum_num = inner 10 11 12 # 2. 使用装饰器装饰函数 13 @logging 14 def sum_num(a, b): 15 result = a + b 16 return result 17 18 19 # 3. 执行被装饰函数验证 20 result = sum_num(1, 2) 21 print(result)
执行结果:
被装饰函数执行之前 被装饰函数执行之后,结果为:3 3
总结:跟其他装饰器的使用,没有区别,要是有区别,就是内部函数必须有返回值,返回值为装饰函数的执行结果。
4. 装饰带有不确定参数的函数
1 # 定义装饰器 2 def logging(fn): # fn = sum_num 3 def inner(*args, **kwargs): 4 print("被装饰函数执行之前") 5 fn(*args, **kwargs) 6 print("被装饰函数执行之后") 7 8 return inner # sum_num = inner 9 10 11 # 使用装饰器装饰函数 12 @logging 13 def sum_num(*args, **kwargs): 14 print(args, kwargs) 15 16 17 sum_num(1, 2, 3, age="18")
输出:
被装饰函数执行之前 (1, 2, 3) {'age': '18'} 被装饰函数执行之后
1 # 定义装饰器 2 def logging(fn): # fn = sum_num 3 def inner(*args, **kwargs): 4 print("被装饰函数执行之前") 5 result = fn(*args, **kwargs) 6 print("被装饰函数执行之后") 7 return result 8 9 return inner # sum_num = inner 10 11 # 使用装饰器装饰函数 12 @logging 13 def sum_num(*args, **kwargs): 14 print(args, kwargs) 15 16 17 sum_num(1, 2, 3, age="18")
5. 多个装饰器装饰一个函数
1 # 定义装饰器1 2 def check1(fn1): 3 def inner1(): 4 print("登陆验证1") 5 fn1() 6 7 return inner1 8 9 10 # 定义装饰器2 11 def check2(fn2): 12 def inner2(): 13 print("登陆验证2") 14 fn2() 15 16 return inner2 17 18 # 被装饰器的函数 19 20 @check1 21 @check2 22 def comment(): 23 print("发表评论") 24 25 26 comment()
输出:
登陆验证1 登陆验证2 发表评论
6. 类装饰器
前提:需要掌握__init__、__call__ 2个内置函数。__init__函数用于类对象的初始化。当一个类的实例被像函数一样调用时,__call__
方法会被调用。
1 # 定义一个类,实现__call__方法 2 class Check(object): 3 def __call__(self, *args, **kwargs): 4 print("我是call方法") 5 6 c = Check() 7 c()
当执行到“对象()”即c()时,会自动咨询__call__方法。输出:我是call方法
动态行为修改:在特定条件下,可以通过动态修改 __call__
方法来改变类的实例的行为。
1 class DynamicBehavior: 2 def __call__(self, *args, **kwargs): 3 if 'override' in kwargs: 4 print("动态修改行为") 5 else: 6 print("默认行为") 7 8 9 dyn = DynamicBehavior() 10 dyn() # 输出:默认行为 11 dyn(override=True) # 输出:动态修改行为
默认行为 动态修改行为
类装饰器是一种特殊类型的装饰器,它使用类而不是函数来装饰其他函数或类。类装饰器可以通过定义 __call__
方法来实现调用。
最佳实践:
- 创建一个类装饰器时,需要确保它的
__init__
方法接受被装饰的函数或类作为参数。 - 在
__call__
方法中实现装饰器逻辑,并返回一个新的函数或类。 - 使用
@
符号将类装饰器应用到要装饰的对象上。
1 # 1. 定义类装饰器 2 class MyDecorator: 3 def __init__(self, decorated): # 1. __init__必须有函数形参,实参是被装饰的函数 4 self.decorated = decorated 5 6 def __call__(self, *args, **kwargs): # 2. 装饰逻辑写在__call__中 7 # 在调用被装饰的函数之前执行一些操作 8 print("Before function execution") 9 10 # 调用被装饰的函数 11 result = self.decorated(*args, **kwargs) 12 13 # 在调用被装饰的函数之后执行一些操作 14 print("After function execution") 15 16 return result # 如果被修饰函数有返回值就用此句,如果没有,省略此句 17 18 19 @MyDecorator 20 def my_function(): 21 print("Inside my_function") 22 23 24 my_function()
输出结果:
Before function execution Inside my_function After function execution
标签:__,函数,示例,num,print,装饰,def From: https://www.cnblogs.com/allenxx/p/17659847.html