首页 > 解决方案 > Python 如何知道哪个参数将是装饰器中的原始函数?

问题描述

我对 Python 的更高级功能(如装饰器)不熟悉。

我无法理解 Python 解释器如何真正理解将原始函数对象放在装饰器中的位置。

让我们看一个例子:从这里获取的例子。

没有参数的简单装饰器

def call_counter(func):
    def helper(*args, **kwargs):
        helper.calls += 1
        return func(*args, **kwargs)
    helper.calls = 0

    return helper

@call_counter
def succ(x):
    return x + 1

如果我们可以假设装饰器的第一个/唯一参数call_counter(func)是需要包装的函数对象,这将非常有意义。在这种情况下succ()功能。

但是当您谈论“带参数的装饰器”时,事情变得不一致。看下面的例子:

带有一个参数的装饰器:

def greeting(expr): # Shouldn't expr be the function here ? Or at least isn't there suppose to be another parameter.
    def greeting_decorator(func): # How does Python know to pass the function down here ?
        def function_wrapper(x):
            print(expr + ", " + func.__name__ + " returns:")
            func(x)
        return function_wrapper
    return greeting_decorator

@greeting("Hello")
def foo(x):
    print(42)

foo("Hi")

现在我们知道 Python 没有数据类型的概念,所以函数参数没有提供关于它们将包含什么类型的对象的信息。

我对么 ?

话虽如此,让我们看一下上面示例中的行:

def greeting(expr):

如果对于装饰器,第一个参数是要包装的函数,那么该逻辑expr应该指向foo()正确的吗?否则应该至少有两个参数greeting(),例如:

def greeting(func, expr):

但相反,Python 可以“神奇地”理解内部函数需要传递函数引用:

def greeting(expr): 
    def greeting_decorator(func): # How is it correctly put one level down ?

代码没有指定数据类型或类型信息,那么对于没有参数的装饰器,函数是如何作为第一个参数传递的,而对于有参数的装饰器,函数是如何传递给内部函数的呢?

口译员如何检测到这一点?

这里发生了什么 ?

这对我来说似乎是“魔法”。

如果我有 5 或 6 层嵌套函数会怎样?

我很确定我在这里遗漏了一些非常基本的东西。

谢谢。

标签: pythonpython-decoratorslanguage-design

解决方案


Python 计算之后的表达式@并将结果用作装饰器函数。

Python__call__以函数作为参数调用装饰器对象的方法。

使用

@call_counter
def succ(x):
    return x + 1

callcounter是寻找__call__给出论点的对象func

如果你使用

@greeting("Hello")
def foo(x):
    print(42)

greeting("Hello")被评估,其结果是 Python 使用__call__带有func参数的方法的对象。


推荐阅读