问题描述
基于 ,我有以下内容
import functools
def predicate(author, version, **others):
def _predicate(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
func.meta = {
'author': author,
'version': version
}
func.meta.update(others)
func(*args, **kwargs)
return wrapper
return _predicate
但我无法得到简单的用例
@predicate('some author', 'some version')
def second_of_two(a, b):
return b
按预期工作:
>>> second_of_two.meta['author']
'some author'
>>> second_of_two(1, 2)
2
我在这做错了什么?
1楼
好吧,我不明白为什么你在这里使用functools
东西,而你需要使它成为一个带参数的简单装饰器:
def predicate(author, version, **others):
def _predicate(func):
func.meta = {
'author': author,
'version': version
}
func.meta.update(others)
return func
return _predicate
@predicate('foo', 'bar')
def myfunc(i,j):
return i+j
print myfunc.meta
print myfunc(1,2)
得到:
{'version': 'bar', 'author': 'foo'}
3
2楼
你错误地做了很多事情,所以让我们看看它:
在你的代码中, predicate
是装饰器的生成器;
实际的装饰者是_predicate
。
装饰器接受一个函数并返回一个函数;
后者将被分配到添加原始代码的位置。
因此,使用@predicate(…) def second_of_two
,名称second_of_two
将获得装饰器返回的值。
那么让我们看看你的装饰师做了什么:
def _predicate(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
…
return wrapper
它构建了一个新的内部函数,使用functool.wraps
(这是一个很好的实践),然后返回该函数。
到现在为止还挺好;
所以second_of_two
正确获取了修饰函数。
现在,包装函数做了什么呢?
def wrapper(*args, **kwargs):
func.meta = {
'author': author,
'version': version
}
func.meta.update(others)
func(*args, **kwargs)
包装函数在原始函数对象上设置元数据。
这是第一个错误;
您在原始函数上设置元数据,以后不再参考。
second_of_two
是包装函数,因此它没有那些元函数。
此外,您只在函数运行时设置这些元数据。
因此,如果您在包装器函数上正确设置元数据,那么只有在您调用一次后它仍然可用。
第三个错误是你调用原始函数并简单地抛弃它的返回值。
这就是为什么你没有得到任何输出。
那么你该怎么做呢? 首先,将元数据设置在包装函数之外,并将其设置在您返回的函数上。 在包装函数内部,返回原始函数的返回值:
def predicate(author, version, **others):
def _predicate(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper.meta = {
'author': author,
'version': version
}
wrapper.meta.update(others)
return wrapper
return _predicate
而现在,您的wrapper
函数不再具有任何特殊功能,因此您只需使用原始函数:
def predicate(author, version, **others):
def _predicate(func):
func.meta = {
'author': author,
'version': version
}
func.meta.update(others)
return func
return _predicate