python 装饰器从哪里获取装饰函数的参数

Where does a python decorator get the arguments from the decorated function

我有这个代码:

def foo(bar):
    def test(some_string):
        return 'Decorator test: '+bar(some_string)
    return test


def main():
    print(bar('test1'))


@foo
def bar(some_string):
    return some_string[:3]

我知道调用 bar('test1) 基本上就是调用 foo(bar('test1')),但是当我尝试在其他函数之前在 foo 中打印 some_string 时,我得到 some_string is not defined:

def foo(bar):
    print(some_string)
    def test(some_string):
        return 'Decorator test: '+bar(some_string)
    return test
  1. test 如何知道 some_stringfoo 不知道?
  2. 为什么我必须 return test 装饰器才能工作? return 直接 Decorator test: '+bar(some_string) 不起作用,因为 some_string 未定义。

I understand that calling bar('test1) is basically calling foo(bar('test1'))

不,不是,你的理解不正确。基本上就是调用

foo(bar)('test')

@foo 装饰器语法告诉 Python 调用 foo() 传入由 bar 命名的函数对象(并将结果分配回名称 bar).

foo()装饰器返回了一个新的函数对象:

def test(some_string):
    # ...
return test

所以 foo(bar) 的结果是名为 test 的函数对象(foo() 装饰器中的局部名称)。 foo(bar)('test') 因此称为 test('test').

如果您想打印传递给 test(..) 的参数,请在内部 函数中执行此操作:

def foo(bar):
    def test(some_string):
        print(some_string)
        return 'Decorator test: '+bar(some_string)
    return test

I understand that calling bar('test1) is basically calling foo(bar('test1'))

不,这是不正确的。

调用bar('test1')等同于

bar = foo(bar)
bar('test1')

Why do I have to return test for the decorator to work? returning directly Decorator test: '+bar(some_string) doesn't work as some_string is not defined.

当你这样做时

@decorator
def func():
    pass

Python 将其翻译成

def func():
    pass

func = decorator(func)

如您所见,Python 期望 decorator 到 return 一个 new 函数。这就是为什么您必须从 foo return test 才能使 bar 正常工作。否则,None 被分配给 bar:

>>> def foo(bar):
    def test(some_string):
        return 'Decorator test: '+bar(some_string)


>>> @foo
def bar(some_string):
    return some_string[:3]

>>> bar()
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    bar()
TypeError: 'NoneType' object is not callable

How does test know about some_string while foo doesn't?

仅仅是因为 some_string 直到达到 test 才创建。 some_stringtest的一个参数,所以只存在于test的范围内。否则,不存在名称 some_string,因此如果您尝试访问它,您将得到一个 NameError - 包括 foo.

内部

如果您想 print some_string 的值,请在 test:

内执行
def foo(bar):
    def test(some_string):
        print(some_string)
        return 'Decorator test: '+bar(some_string)
    return test