我了解到我们可以在Python中将一个函数与另一个函数等同于:
def func_1(x)
print("func_1")
print(x)
def func_2(x)
print("func_2")
print(x)
func_1 =func_2
所以在这里发生的事情是每次调用func_1都会执行func_2。
但是,我读到了装饰器,下面是一个简单的代码说明:
def our_decorator(func):
def function_wrapper(x):
print("Before calling " + func.__name__)
func(x)
print("After calling " + func.__name__)
return function_wrapper
def foo(x):
print("Hi, foo has been called with " + str(x))
print("We call foo before decoration:")
foo("Hi")
print("We now decorate foo with f:")
foo = our_decorator(foo)
print("We call foo after decoration:")
foo(42)
我们可以在以下行中看到:
foo = our_decorator(foo)
类似于之前的函数方程式正在发生。我认为这就是装饰器可能正在工作的方式,即通过调用decorator来替换对decoratee的调用。
然而,在这种印象下,如果我写下如下代码:
def our_decorator():
def function_wrapper(x):
print("Before calling " )
foo(x)
print("After calling " )
return function_wrapper
def foo(x):
print("Hi, foo has been called with " + str(x))
print("We call foo before decoration:")
foo("Hi")
print("We now decorate foo with f:")
foo = our_decorator()
print("We call foo after decoration:")
foo(42)
上面的结果是无限递归打印无限数量"在调用"之前。
所以,我可以得出结论,装饰器必须是一个将函数作为参数的东西。
因此,函数的等同在这两个cae中是不同的,即等同于将另一个函数作为参数的函数,并将两个不接受另一个函数作为参数的函数等同起来。
这两者在内部实施方面有何不同?
答案 0 :(得分:1)
你所谓的“等同函数”实际上只是一个变量赋值。函数定义(带def
)创建一个函数并将其赋值给变量名。执行func_1 = func_2
后,您有2个变量引用相同的函数。
装饰器示例中发生的情况是前一段的自然结果。如果您需要进一步澄清,请发表评论。
答案 1 :(得分:0)
我希望通过解释几个术语来回答你的问题。
您使用术语“等同于”来表示通常称为“分配”的内容。 name = expr
是一个赋值语句。名称name
被赋予(分配)给对象,该对象是表达式expr
的结果。
在Python中,函数不受特殊处理。这有时用句子“函数是第一类对象”表示,基本上它意味着函数对象可以分配给变量(名称),作为参数传递等,与数字,字符串和其他对象。
(函数)装饰器处理另一个函数。它是一个函数,它将函数作为参数进行修饰,并返回一个“装饰”(即以某种方式增强或修改)版本。有时它只注册函数,例如作为处理程序或作为API的一部分并返回它不变。它有一个特殊的语法:
@decorator
def func(...):
pass
相当于:
func = decorator(func)
还有:
@decorator(args)
def func(...):
pass
相当于:
_real_decorator = decorator(args)
func = _real_decorator(func)
因为这个@decorator
语法易于使用且易于阅读,所以通常不会写:
func = decorator(func)
总结:
func1 = some_func
是明确的作业,为some_func
提供其他名称。
func2 = create_function()
这在某些语言中称为函数工厂。你在问题中写了这个。
func = decorate_function(func)
这是func
注意:存在类装饰器,它们非常相似,但增强了类定义而不是函数。
答案 2 :(得分:0)
装饰师看起来像这样:
def decorator_with_args(*args, **kwargs):
def wrapper(f: "the function being decorated"):
def wrapped(*args, **kwargs):
# inside here is the code that is actually executed
# when calling the decorated function. This should
# always include...
f(*args, **kwargs)
# and usually return its result
return wrapped
return wrapper
# or
def decorator_without_args(f: "the function being decorated"):
def wrapped(*args, **kwargs):
# as above
return f(*args, **kwargs)
return wrapped
并用于:
@decorator_with_args("some", "args")
def foo(x):
print("foo:", x) # or whatever
@decorator_without_args
def bar(x):
print("bar:", x)
这相当于在没有@decorator...
魔法的情况下定义每个函数并在之后应用装饰器
def baz(x):
print("baz:", x)
baz = decorator_with_args("some", "arguments")(baz)
# or
baz = decorator_without_args(baz)
在你的示例代码中,你在装饰器中调用foo
,然后用装饰器装饰foo
,这样你最终会无限递归。每次调用foo
时,它都会运行您的装饰器代码,该代码也会调用foo
。每次装饰者调用foo
时,它都会运行您的装饰器代码,该代码也会调用foo
。每当装饰者的装饰者调用foo
时,都会运行你的装饰师代码......等等