【发布时间】:2020-11-14 20:30:31
【问题描述】:
我不熟悉 Python 的更高级功能,例如装饰器。
我无法理解 Python 解释器如何真正理解将原始函数对象放在装饰器中的什么位置。
让我们看一个例子:来自here的例子。
没有参数的简单装饰器:
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 层嵌套函数会怎样?
我很确定我在这里遗漏了一些非常基本的东西。
谢谢。
【问题讨论】:
-
“现在我们知道 Python 没有数据类型的概念,” 绝对不正确,Python 是一种强类型语言,具有明确定义的数据类型。每个对象都有一个类型,并且知道它的类型,并且该类型在运行时是可自省的。虽然,这不是装饰者知道的。请注意,Python 是动态类型的,而不是静态类型的,这可能是您的意思。
-
您可能希望看到我的回答以进一步了解:stackoverflow.com/questions/51891951/…。总而言之,
greeting("Hello")返回一个接受foo作为参数的函数,你当然可以嵌套任意多的层。 -
greeting("Hello")的第一个参数 是修饰函数。greeting的第一个参数是"Hello"。 -
@ng.newbie you 调用
greeting("Hello"),它返回一个装饰器,在这种情况下,内部的greeting_decorator与@decorator语法一起应用时,得到变成了function = greeting_decorator(function),这就是@decorator的语法被定义为如何工作 -
@ng.newbie then you 将不得不执行类似
@level1('foo')('bar')的操作,@语法只是调用 表达式的结果与功能。它不知道涉及到多少嵌套......
标签: python python-decorators language-design