装饰器使用方法全面解析
Topic source但是我发现一个问题,照层主的写法,在P5里面,最后执行函数的时候,不能写成f5() , 而只能写成f5, 原因在于此时的 f5 = mydecoratorfive(args,*kw)(f5),而在函数decorator里面f5()已经被执行了,因此写成f5就可以被直接运行了; 这会导致一个问题,如果以后还想取f5的名字属性会出错,此时的f5已经不是一个名字了,而是类似 f()的东西,print(f().name) 必然出错,因此,此时print(f5.name)也会返回错误“AttributeError: 'NoneType' object has no attribute '__name'”
这种思考方式非常有助于理解,但其实代码中的P1和P3并没有实现装饰器的“动态增加功能”:
比如可以看看P1这段代码:
# 定义装饰函数,被装饰函数作为参数
def decorator_one(f1):
print('start')
print('call ' + f1.__name__)
print('end')
# 被装饰函数不带参数,返回被装饰函数,最外层函数必须接受一个返回函数
return f1
当接下来定义语法糖:
@decorator_one
# 采取和上面定义不同的名字,否则会出错
def f1():
pass
的过程中时,这一段代码已经输出了:
start
call f1
end
然后返回了f1,当在下一步调用f1时,只会输出f1中的内容(pass),而不会动态增加以上的代码。
P3中的代码也是同理。
所以层主P5中的代码实际上是不符合课后习题的答案的。
我想问一下,这个:
@decorator_one
# 采取和上面定义不同的名字,否则会出错
def f1():
pass
是不是就等于:
def f1():
pass
f1 = decorator_one(f1)
这时候是不是相当于调用了decorator_one(f1) 此时根据:
def decorator_one(f1):
print('start')
print('call ' + f1.__name__)
print('end')
# 被装饰函数不带参数,返回被装饰函数,最外层函数必须接受一个返回函数
return f1
所以才会打印start这些
然后:
f1()
这时候,相当于调用:
f1()
因为 decorator_one(f1)的返回值就是f1,所以才不会打印?
但是如果写成:
def decorator_one(f1):
def wrapper:
print('start')
print('call ' + f1.__name__)
f1()
print('end')
# 被装饰函数不带参数,返回被装饰函数,最外层函数必须接受一个返回函数
return wrapper
这样根据刚刚说的,调用f1()就相当于调用wrapper,所以每次调用f1的时候会打印那些信息。而这个时候:
@decorator_one
# 采取和上面定义不同的名字,否则会出错
def f1():
pass
仅仅是:
def f1():
pass
f1 = decorator_one(f1)
decorator_one仅仅就是返回了wrapper,但并不调用,让f1指向了wrapper而已。请问是这样理解吗?
- 1
- 2
yo_才子_凯明
这一章其实要吃透还是不容易的,因为涉及到4类构造器。不过廖老师似乎没有按照这样的逻辑来讲,我在自学的过程中整理了四类构造器的使用方法和心得,希望对大家有帮助!具体可以看代码!P1 P2 P3 P4代表了四类构造器,P5是对该题目的解答!