Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用decorator给出函数元数据?_Python_Decorator - Fatal编程技术网

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
属性,您是否希望它在装饰时被设置?我唯一的遗憾是,对于这个答案,我只有一票赞成。谢谢谢谢你的解释!