【问题标题】:Decorator execution?装饰器执行?
【发布时间】:2023-03-04 13:24:02
【问题描述】:

玩装饰器,发现一些奇怪的东西:我有一些简单的东西如下(一个装饰器将函数注册到列表中:

stored_f = []

def register(f):
    stored_f.append(f.__name__)
    return f

@register
def say_hello(name):
    print(f"Hello {name}")

@register
def ur_awesome(name):
    return f"{name}, you are awesome!"

我以为上面的代码什么都不会做(它什么都不会打印出来),因为我没有执行任何东西,但实际上一个打印命令“print(stored_f)”会有一个输出:

['say_hello', 'ur_awesome']

意思是 register() 中的“stored_f.append(f.__name__)”行实际上被执行了两次。这对我来说很奇怪。

我尝试像往常一样在寄存器中定义一个 wrapper(),然后返回 wrapper,问题就会消失。但是我还是不明白为什么上面的代码会部分执行装饰器而不调用它。

【问题讨论】:

  • 你为什么认为不会被处决?它不会“不调用就部分执行装饰器”;它完全通过调用装饰器来执行它。
  • “因为我没有执行任何操作” - 但@register 执行register
  • @jonrsharpe 因为我没有执行任何东西,所以它只是所有定义。就像我最后说的,如果我在寄存器中放一个包装器,它绝对不会像我预期的那样做任何事情。
  • “如果我在寄存器中放一个包装器,它绝对不会像我预期的那样做任何事情” - 因为你执行了register,而不是包装器。
  • register 的主体被执行。你在里面做什么都会做。如果您更改 register 的定义,以便不附加到其中的 stored_f,那么是的,它仍然是空的。装饰器语法基本上是say_hello = register(say_hello) 的简写。

标签: python python-decorators


【解决方案1】:

导入并运行 Python 文件会执行它,添加带有 @register 的装饰器会执行装饰器。

所以,即使你的脚本只包含变量声明、装饰器和两个函数定义,当你运行它时,这两个定义都会被执行(定义函数)并且它们上面的装饰器函数也会被执行,这样函数被正确修饰。

在您的评论之后添加:考虑一下:

stored_f = []

def register(f):
    stored_f.append(f.__name__)
    print('it runs!')
    return f

@register
def say_hello(name):
    print(f"Hello {name}")

@register
def ur_awesome(name):
    return f"{name}, you are awesome!"

你会发现,如果你运行这个脚本,输出是:

it runs!
it runs!

装饰器中的所有代码都会运行,您只需返回它接收到的相同函数,因此f 在前后的工作方式相同。

另外,如果你在该脚本的末尾添加say_hello("john"),你会发现装饰器不再运行,只有函数再次运行。

另外,比较一下:

stored_f = []

def register(f):
    stored_f.append(f.__name__)
    def decorated_f(*args):
        print('it runs!')
        f(*args)
    return decorated_f

@register
def say_hello(name):
    print(f"Hello {name}")

say_hello("john")
say_hello("pete")

这会导致:

it runs!
Hello john
it runs!
Hello pete

也许这更接近您的预期。请注意,装饰器不会返回原始函数,而是返回新函数。

【讨论】:

  • 我想,但如果我错了,请纠正我:@register 不执行装饰器,只有@register() 或 say_hello()(注意两种情况下的括号)会执行。另外,如果我尝试遵循您的逻辑,为什么 python 只在寄存器中执行第一行,然后停止?
  • 我已经添加了一些示例,希望能为您阐明情况。
  • 不客气 - 如果您认为答案对您的问题来说足够好,请也单击复选标记,以便问题显示为已回答,这有助于其他人寻找答案或已回答问题。
【解决方案2】:

根据 Grimar 的回答,我做了以下事情,可以从另一个角度解释,至少对我自己来说:

def do_twice(f):
    print('This will be executed anyway')
    def wrapper():
        f()
        f()
    return wrapper

@do_twice
def say_hello():
    print('This is say hello')

输出:

This will be executed anyway

如果我跑步:

say_hello()

输出:

This is say hello
This is say hello

【讨论】:

    猜你喜欢
    • 2015-02-05
    • 2012-01-20
    • 2016-07-25
    • 2021-12-15
    • 2020-07-09
    • 2019-02-09
    • 2013-08-21
    • 1970-01-01
    相关资源
    最近更新 更多