1

我有以下装饰器:

from decorator import decorator
def my_decorator(key=None, timeout=None, retry=0):
    """
    My decorator
    """
    import pdb; pdb.set_trace()

    def _my_decorator(func):
        import pdb; pdb.set_trace()
        key = key or func.__name__

        @decorator
        def __my_decorator(f, *args, **kwargs):
            result = "abc"
            return result
        return __my_decorator(func)
    return _my_decorator

在第一个 pdb 部分中,结果locals()是:

>>> locals()
{'key': None, 'retry': 0, 'pdb': <module 'pdb' from '/opt/python/2.7/lib/python2.7/pdb.pyc'>, 'timeout': None}

在第二个 pdb 部分中,结果locals()是:

>>> locals()
{'timeout': None, 'retry': 0, 'pdb': <module 'pdb' from '/opt/python/2.7/lib/python2.7/pdb.pyc'>, 'func': <function get_items at 0x9e172cc>}

没有 pdb 的异常:

key = key or func.__name__
UnboundLocalError: local variable 'key' referenced before assignment

您知道为什么key嵌套函数 _my_decorator 中的参数消失了吗?更奇怪的是,因为timeoutretry参数仍然可以访问(尽管这是嵌套函数中的正常行为)。

有一个解决方法:

def my_decorator(key=None, timeout=None, retry=0):
    """
    My decorator
    """
    key2 = key

    def _my_decorator(func):
        key = key2 or func.__name__
    ...

但这不是解决方案(参数key仍然存在_my_decorator,但key2现在可以访问)

Python版本:2.7.3

4

2 回答 2

4

如果您在内部范围内绑定变量名称,它将从外部范围的闭包中省略。这是因为否则后续代码将不知道要引用哪个绑定:

def outer(x=None):
    def inner(y=0):
        if y:
            x = y
        return x    # outer.x or inner.x?

解决方法是重命名变量,使它们不会影响封闭范围:

def my_decorator(key=None, timeout=None, retry=0):
    def _my_decorator(func):
        func_key = key or func.__name__
        ...
于 2012-10-31T10:51:09.853 回答
1

您正在分配 key,这使得该变量成为本地变量。你不能用 Python 2 来做你想要实现的事情(在 Python 3 中你可以将它标记为nonlocal)。

解决方法是制作key一个可变的,然后改变它的内容而不是分配给它:

from decorator import decorator
def my_decorator(key=None, timeout=None, retry=0):
    """
    My decorator
    """
    key = [key]

    def _my_decorator(func):
        key[0] = key[0] or func.__name__

现在我们正在mutating key,而不是分配给变量。换句话说,我们正在执行道德上的等价物key.__setitem__(0, key[0] or func.__name__),当你的代码正在执行时locals()['key'] = key or func.__name,一个标记key为局部变量的行为。

于 2012-10-31T10:50:19.260 回答