python - 装饰方法赋值前引用的局部变量

标签 python python-3.x decorator python-decorators

我正在创建一个装饰器,它允许我做如下事情:

@cooldownf(lambda self, **eargs: 30 - self.level)
def method(self, **eargs):
    ...

这将简单地修饰方法,使其具有冷却时间。 这一切都很好,现在可以每 30 - self.level 秒执行一次该方法。

但是,我想添加一条消息,如果该方法仍在冷却,则会显示该消息。 我为 cooldownf 装饰器添加了一个 message 参数,但随后我从该行收到错误 UnboundLocalError: local variable 'message' referenced before assignment ìf message: 在我的装饰器代码中:

def cooldownf(fn, message=None):
    """Decorates a method to have a dynamic cooldown.

    Decorator function for easily adding cooldown as a dynamic time
    (function) into skill's methods. The function gets called when the
    cooldown is needed, and the skill is passed to the function.

    Args:
        fn: Function to determine the cooldown of the method
        message: Optional message sent if there's still cooldown left

    Returns:
        Decorated method with a dynamic cooldown
    """

    # Create a decorator using the function and message provided
    def method_decorator(method):

        # Create a wrapper method
        @wraps(method, assigned=WRAPPER_ASSIGNMENTS+('__dict__',), updated=())
        def method_wrapper(self, **eargs):

            # If the method's cooldown is over
            if method_wrapper.cooldown.remaining <= 0:

                # Restart the cooldown
                method_wrapper.cooldown.start(1, fn(self, **eargs))

                # And call the function
                return method(self, **eargs)

            # If there was cooldown remaining and a message is provided
            if message:

                # Format the provided message
                message = message.format(
                    name=self.name,
                    cd=method_wrapper.cooldown.remaining,
                    max_cd=method_wrapper.cooldown.limit
                )

                # Send it to the player
                SayText2(message=message).send(eargs['player'].index)

                # And exit with code 3
                return 3

        # Create the cooldown object for the wrapper
        method_wrapper.cooldown = TickRepeat(lambda: None)

        # And return the wrapper
        return method_wrapper

    # Return the decorator
    return method_decorator

这是什么原因造成的? 我可以在 cooldownfmethod_decorator 中打印 message,但是在 method_wrapper 中添加打印会导致提出错误。 这是确切的代码,我无法在 IDLE 中复制它函数,和我特别使用方法有关系吗?

最佳答案

您正在分配给最内层函数中的message:

message = message.format(
    name=self.name,
    cd=method_wrapper.cooldown.remaining,
    max_cd=method_wrapper.cooldown.limit
)

该赋值使其成为一个局部变量,但您必须先访问 message 才能进行该赋值。本地人做不到。

由于您不想修改封闭参数,所以您想在这里使用一个本地名称:

formatted_message = message.format(
    name=self.name,
    cd=method_wrapper.cooldown.remaining,
    max_cd=method_wrapper.cooldown.limit
)
SayText2(message=formatted_message).send(eargs['player'].index)

关于python - 装饰方法赋值前引用的局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28738962/

相关文章:

Python、XML 和 MySQL - ascii v utf8 编码问题

python - 输出中可见反斜杠

python - 无法在 python 3.6 中将字符串转换为 float

python - 更 retrofit 饰器内的实例属性

python - python 2.7 中的 string_builder 装饰器 - 如何做以及我应该做吗?

python - 如何在 Python 中读取 gzipped parquet 文件

python - 如何在 Python 中打印我的对象名称

python - 序列化模型列表时,获取“QuerySet”对象没有属性“_meta”错误

python - Kivy Ios ./toolchain.py 构建 kivy 不工作

oop - Head First 设计模式 - 使用 Starbuzz 的装饰器模式