【问题标题】:Decorator only works when method is decorated but not when the decorator is called with method passed as argument装饰器仅在装饰方法时有效,但在使用作为参数传递的方法调用装饰器时无效
【发布时间】:2022-01-19 20:12:40
【问题描述】:

长期聆听者;第一次来电,所以如果我没有完全遵守指南,请不要拍我。

所以我正在尝试创建一个装饰器,它将状态栏应用于生成器方法。使用 @decorator 语法时,我的装饰器工作得很好。然而,当调用装饰器并将方法作为参数传递时,装饰器什么也不做。我想像调用任何其他函数一样调用装饰器函数,而不是使用@status_bar,因为我想要一种简单的方法来选择使用生成器。

这是工作代码:

import time

from alive_progress import alive_bar


def status_bar(func):

    def wrapper(self):
        with alive_bar() as bar:
            for x in func(self):
                bar()

    return wrapper


class TestClass:

    def __init__(self):
        pass

    @status_bar
    def iter_range(self):
        for x in range(10000):
            time.sleep(0.01)
            yield x


TestClass().iter_range()

这会按预期在提示中产生一个状态栏。

| ▶▶▶▶▶▶▶▶▶▶▶▶▶ ▂▂▄ 326 in 3s (98.2/s)

但是在没有语法糖的情况下运行代码什么都做不了。

def status_bar(func):

    def wrapper(self):
        with alive_bar() as bar:
            for x in func(self):
                bar()

    return wrapper


class TestClass:

    def __init__(self):
        pass

    def iter_range(self):
        for x in range(10000):
            time.sleep(0.01)
            yield x


status_bar(TestClass().iter_range)

相反,代码就像没有调用任何函数一样运行。

进程以退出代码 0 结束

我似乎总是得到相同的输出,而且我知道这里有一个简单的解释,这就是为什么它让我如此烦恼以至于我无法让它工作。任何帮助是极大的赞赏。谢谢。

【问题讨论】:

    标签: python-decorators python-class python-closures


    【解决方案1】:

    我正在尝试自己学习这一点。使用https://stackoverflow.com/a/25827070/59867 作为参考,我发现:

    当您调用 status_bar(TestClass().iter_range) 时,它会返回您实际上并没有调用的修饰函数,这就是为什么没有发生任何事情的原因。

    所以类似地调用它,但只是从类(而不是从实例)中传入函数,这样就可以了:

    decorated_func = status_bar(TestClass.iter_range)
    decorated_func(TestClass())
    

    这意味着你会这样称呼它:

    status_bar(TestClass.iter_range)(TestClass())
    

    【讨论】:

    • 我觉得很愚蠢,因为我不理解第二个括号在我见过的其他示例中是如何使用的。这似乎违反直觉,但我假设它与装饰器内的嵌套函数有关。知道为什么要使用这种语法吗?我想我不完全理解为什么调用装饰器的替代方法不起作用。
    • 当您执行status_bar(TestClass().iter_range) 时,您调用的是status_bar(),它只做一件事:构建并返回一个可以调用的函数。但是你没有调用它,所以什么都没有发生。如果您将() 添加到末尾,那么您将调用它返回给您的函数。
    • 哦,好吧,我明白你的意思了。 @status_bar 有效地调用了自动返回的函数。但是对于典型的语法,我只是调用函数而不调用包装器,所以必须随后调用它?
    • 正确 - 装饰器自动将包装后的函数分配给原始函数名,但直接调用时需要调用返回的函数
    猜你喜欢
    • 2020-01-11
    • 2013-03-10
    • 2014-01-14
    • 1970-01-01
    • 2018-05-30
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多