[英]Confused about Python decorators and “syntactic sugar”
I have always had trouble really understanding some of Python's advanced concepts. 我一直很难真正理解Python的一些高级概念。 I just thought I finally understood decorators and ran into another wall. 我只是以为我终于了解了装饰师并碰到了另一堵墙。
As I understand, the core truth to decorators is that the following two things are exactly the same: 据我了解,装饰器的核心真理是以下两件事完全相同:
@function_generator
def original_function:
...
and 和
original_function = function_generator(original_function)
which is to say that what is being done is that function_generator
is being called and passed the original_function
, then function_generator
hands back a different function which then is given the original function's name, so that when the code calls the original_function
, what really gets executed is the code the function generator returns. 也就是说,正在执行的操作是调用function_generator
并传递了original_function
,然后function_generator
递回另一个函数,然后为其指定原始函数的名称,以便当代码调用original_function
,真正执行的是函数生成器返回的代码。
But then I tried this: 但是后来我尝试了这个:
def decorator(passed_func, times):
"""the decorator"""
def replacement():
"""the replacement"""
for i in range(times):
passed_func()
return replacement
#@decorator
def print_name():
"""prints my name"""
print("My name is Benn")
iterate = int(input("How many times?"))
print_name = decorator(print_name, iterate)
print_name()
This code works fine and does exactly what I expect. 这段代码可以正常工作,并且完全符合我的期望。 But when I uncomment the @decorator
and comment out print_name = decorator(print_name, iterate)
, it crashes. 但是,当我取消注释@decorator
并注释掉print_name = decorator(print_name, iterate)
,它崩溃。
The reason I ran this code test is because I was seeing an advanced example of decorators where they said we have to wrap the decorator in a whole other function to pass in arguments (like iterate
). 我运行此代码测试的原因是因为我看到了一个装饰器的高级示例,其中他们说我们必须将装饰器包装在其他函数中才能传递参数(例如iterate
)。 However, it seems to me that if that is true it makes the statement that @func2
is merely syntactic sugar for typing func1=func2(func1)
into a lie. 但是,在我看来,如果这是真的,那么它就会声明@func2
仅仅是将func1=func2(func1)
键入谎言中的语法糖。
So which of the following is true: 因此,以下哪一项是正确的:
typing func1=func2(func1)
is NOT exactly the same as @func2
over the def
for func1
, because if it was, then if func1=func2(func1,arg)
works then @func2
as a decorator would work; 打字func1=func2(func1)
是不完全一样的@func2
在def
为func1
,因为如果是,那么如果func1=func2(func1,arg)
的作品,然后@func2
作为装饰会工作; or 要么
they are the same even though from the above example it seems exactly the opposite – if so, why does it seem the opposite? 即使在上述示例中看起来完全相反,它们也是相同的–如果是这样, 为什么看起来相反?
That's what I am hung up on right now. 这就是我现在挂断的电话。 Why do so many people say that @decorator
is nothing but another way to write func1=decorator(func1)
when it does not work that way when you add an argument in to the mix? 为什么这么多人说@decorator
只是写func1=decorator(func1)
另一种方式,而当您在混合中添加参数时,它却无法正常工作吗?
That's because actually you still didn't understand decorator well. 那是因为实际上您仍然不太了解装饰器。 If you want to pass parameters to a decorator, the decorator should nested like this, with the parameter at the entry level, and the func is passed in the inner level. 如果要将参数传递给装饰器,则装饰器应像这样嵌套,将参数置于入口级别,并且将函数传递到内部级别。
def decorator(times):
def wrapper(passed_func):
"""the wrapper"""
def replacement():
"""the replacement"""
for i in range(times):
passed_func()
return replacement
return wrapper
# @decorator(3)
def print_name():
"""prints my name"""
print("My name is Benn")
iterate = int(input("How many times?"))
print_name = decorator(iterate)(print_name)
print_name()
You can uncomment the decorator and try as you wish. 您可以取消注释装饰器,然后根据需要尝试。
One way you can do this is to create a decorator factory: a function that returns a decorator. 一种实现方法是创建装饰器工厂:一个返回装饰器的函数。 The syntax for calling it looks like a decorator with an argument list. 调用它的语法看起来像带有参数列表的装饰器。 Here's a modified version of your code: 这是您代码的修改版本:
def decorator_factory(times):
def decorator(passed_func):
"""the decorator"""
def replacement():
"""the replacement"""
for i in range(times):
passed_func()
return replacement
return decorator
iterates = int(input("How many times? "))
@decorator_factory(iterates)
def print_name():
"""prints my name"""
print("My name is Benn")
print_name()
demo 演示
How many times? 4
My name is Benn
My name is Benn
My name is Benn
My name is Benn
It may help to understand what's happening if we re-write the last part of that code like this: 如果我们这样重写代码的最后一部分,可能有助于了解正在发生的情况:
dec = decorator_factory(iterates)
@dec
def print_name():
"""prints my name"""
print("My name is Benn")
So decorator_factory(iterates)
returns dec
, and then dec
is used to decorate print_name
. 因此decorator_factory(iterates)
print_name
decorator_factory(iterates)
返回dec
,然后使用dec
来装饰print_name
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.