python装饰器中的变量范围 [英] Scope of variables in python decorator

查看:85
本文介绍了python装饰器中的变量范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Python 3装饰器中遇到一个非常奇怪的问题。

I'm having a very weird problem in a Python 3 decorator.

如果我这样做:

def rounds(nr_of_rounds):
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            return nr_of_rounds
        return inner
    return wrapper

它工作得很好。但是,如果我这样做:

it works just fine. However, if I do this:

def rounds(nr_of_rounds):
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            lst = []
            while nr_of_rounds > 0:
                lst.append(func(*args, **kwargs))
                nr_of_rounds -= 1
            return max(lst)
        return inner
    return wrapper

我得到:

while nr_of_rounds > 0:
UnboundLocalError: local variable 'nr_of_rounds' referenced before assignment

如果可以在返回函数中使用 nr_of_rounds ,则可以在内部函数中使用它,但是我无法执行其他任何操作。为什么?

In other words, I can use nr_of_roundsin the inner function if I use it in a return, but I can't do anything else with it. Why is that?

推荐答案

由于 nr_of_rounds closure ,您可以将其视为只读变量。如果要写入它(例如减少它),则需要明确地告诉python-在这种情况下,python3.x nonlocal 关键字会起作用。

Since nr_of_rounds is picked up by the closure, you can think of it as a "read-only" variable. If you want to write to it (e.g. to decrement it), you need to tell python explicitly -- In this case, the python3.x nonlocal keyword would work.

作为简要说明,当Cpython遇到函数定义时,它会执行以下操作:查看代码并确定所有变量是 local 还是非本地。局部变量(默认情况下)是赋值语句,循环变量和输入参数出现在左侧的任何内容。其他所有名称都不是本地名称。这样可以进行一些巧妙的优化 1 。要像使用本地变量一样使用非本地变量,您需要通过 global nonlocal 语句。当python遇到它认为应该是本地但实际上不是本地的东西时,您会得到一个 UnboundLocalError

As a brief explanation, what Cpython does when it encounters a function definition is it looks at the code and decides if all the variables are local or non-local. Local variables (by default) are anything that appear on the left-hand side of an assignment statement, loop variables and the input arguments. Every other name is non-local. This allows some neat optimizations1. To use a non-local variable the same way you would a local, you need to tell python explicitly either via a global or nonlocal statement. When python encounters something that it thinks should be a local, but really isn't, you get an UnboundLocalError.

1 Cpython字节码生成器将本地名称转换为数组中的索引,以便本地名称查找(LOAD_FAST字节码指令)与索引数组一样快加上正常的字节码开销。

1The Cpython bytecode generator turns the local names into indices in an array so that local name lookup (the LOAD_FAST bytecode instruction) is as fast as indexing an array plus the normal bytecode overhead.

这篇关于python装饰器中的变量范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆