Python 如何使用decorator给出函数元数据?
基于此,我有以下几点Python 如何使用decorator给出函数元数据?,python,decorator,Python,Decorator,基于此,我有以下几点 import functools def predicate(author, version, **others): def _predicate(func): @functools.wraps(func) def wrapper(*args, **kwargs): func.meta = { 'author': author, 'version
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
我在这里做错了什么?好吧,我不明白你为什么要使用这里的
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
您正在错误地执行多项操作,因此让我们来看看如何处理: 在代码中,
谓词
是装饰器的生成器;实际的装饰器是\u谓词
。装饰器接受一个函数并返回一个函数;后者将被分配到添加原始代码的位置。因此,使用@谓词(…)def second\u of theu two
,名称second\u of theu two
将获得装饰器返回的值
让我们看看你的装饰师是怎么做的:
def _predicate(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
…
return wrapper
它构建一个新的内部函数,使用functool.wrapps
(这是一个很好的实践),然后返回该函数。到现在为止,一直都还不错;因此,second\u of_two
正确地获得修饰函数
现在,包装器函数做什么呢
def wrapper(*args, **kwargs):
func.meta = {
'author': author,
'version': version
}
func.meta.update(others)
func(*args, **kwargs)
包装器函数在原始函数对象上设置这些元数据。这是第一个错误;在原始函数上设置元数据,以后不再引用second\u 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
现在,您的包装器
函数不再执行任何特殊操作,因此您只需使用原始函数即可:
def predicate(author, version, **others):
def _predicate(func):
func.meta = {
'author': author,
'version': version
}
func.meta.update(others)
return func
return _predicate
你以为会发生什么?您的包装函数只有在第一次调用时才被赋予
meta
属性,您是否希望它在装饰时被设置?我唯一的遗憾是,对于这个答案,我只有一票赞成。谢谢谢谢你的解释!