我一直在尝试了解装饰器,我发现了这个奇怪的小东西,假设我们有一个像这样的装饰器
import functools
global_event_registration =[]
def handler_all(func):
if(func):
global_event_registration.append(func)
return func
它只是将函数添加到全局列表并返回它,如果我们运行该函数,我们会得到预期的输出
@handler_all
def print_yay():
print('yay!')
print(global_event_registration)
print_yay()
输出:
[<function __main__.print_yay()>]
yay!
但是如果我们更改
handler_all
以接受任意参数,比如说 count
,然后再次运行相同的操作,则会出错,
def handler_all(func, count=2):
if(func):
global_event_registration.append(func)
return func
@handler_all(count=2)
def print_yay():
print('yay')
它会错误地指出缺少位置论证
func
,我的问题是因为在第一种情况下,func
是隐式传递的,为什么第二种情况不是这样?
我还发现了这个stackoverflow线程,它使用
functools.partial
像来处理它
def handler_all(func=None, count=2):
if not func:
return functools.partial(handler_all, count=count)
if(func):
func()
global_event_registration.append(func)
return func
我得到了线程的答案,我们只是返回一个部分函数,该函数已隐式传递给它
func
但同样的问题仍然存在,这是如何将函数传递给它而不是根本不使用它?为什么它在第二种情况下隐式传递,而不是在第一种情况下,因为函数定义是相同的?
还有一个奇怪的事情是,
在这个例子中
def test(name="your_name"):
def decorator(func):
print(name)
func()
return func
return decorator
@test(name='altair')
def print_yay():
print('yay')
当你运行这个时,输出是
altair
yay
我的问题是为什么?我们只是返回对内部函数的引用而不是调用它,那么为什么它会被调用呢?
如果我们将 func 移至外部函数,它会按预期工作,没有输出。
def test(func):
def decorator():
func()
return func
return decorator
@test
def print_yay():
print('yay')
同样的细微差别,如果我定义一个像这样的装饰器并显式调用内部函数,这反过来应该返回传递给它的函数,但是当我运行它时它返回一个
NoneType
,又是为什么?
def test(func=None,name="your_name"):
def decorator(func):
print(name)
func()
return func
return decorator(func)
输出是
altair
<function print_yay at 0x7fcf60466440>
新行由装饰器返回,这意味着我们作为
print
传入的 func
工作正常。
但如果我打电话给 print_yay
,它只会说 NoneObject is not callable
。
@test(func=print, name='altair')
def print_yay():
print('yay')
print_yay()
输出:
1 @test(func=print,name='altair')
2 def print_yay():
3 print('yay')
----> 5 print_yay()
TypeError: 'NoneType' object is not callable
有人可以向我解释这些细微差别吗?我很难弄清楚幕后到底发生了什么,而且我根本找不到任何资源可以解释这一点。
因为:
@decorator(some_arg)
def foo():
pass
相当于:
def foo():
pass
foo = decorator(some_arg)(foo)
所以只关注这个例子:
def handler_all(func, count=2):
if(func):
global_event_registration.append(func)
return func
@handler_all(count=2)
def print_yay():
print('yay')
所以,这就是正在发生的事情:
>>> def handler_all(func, count=2):
... if(func):
... global_event_registration.append(func)
... return func
...
>>> @handler_all(count=2)
... def print_yay():
... print('yay')
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: handler_all() missing 1 required positional argument: 'func'
>>> def print_yay():
... print("yay")
...
>>> print_yay = handler_all(count=2)(print_yay)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: handler_all() missing 1 required positional argument: 'func'
>>>
正如你所说,它出错是因为它缺少一个参数。发生的事情是因为 你在糖发生变化以传递任何东西之前调用装饰器。