Python中的未绑定局部变量问题

5 投票
1 回答
7737 浏览
提问于 2025-04-16 16:41

我有一段代码:

def isolation_level(level):
    def decorator(fn):
        def recur(level, *args, **kwargs):
            if connection.inside_block:
                if connection.isolation_level < level:
                    raise IsolationLevelError(connection)
                else:
                    fn(*args, **kwargs)
            else:
                connection.enter_block()
                try:
                    connection.set_isolation_level(level)
                    fn(*args, **kwargs)
                    connection.commit()
                except IsolationLevelError, e:
                    connection.rollback()
                    recur(e.level, *args, **kwargs)
                finally:
                    connection.leave_block()
        def newfn(*args, **kwargs):
            if level is None: # <<<< ERROR MESSAGE HERE, Unbound local variable `level`
                if len(args):
                    if hasattr(args[0], 'isolation_level'):
                        level = args[0].isolation_level
                elif kwargs.has_key('self'):
                    if hasattr(kwargs['self'], 'isolation_level'):
                        level = kwargs.pop('self', 1) 
            if connection.is_dirty():
                connection.commit()
            recur(level, *args, **kwargs)
        return newfn
    return decorator

这段代码具体做什么其实不重要,我只是把它原封不动地贴出来,因为我没法用更简单的例子重现这个情况。

问题是,当我调用 isolation_level(1)(some_func)(some, args, here) 时,在第21行(在列表中标记了)出现了 Unbound local variable 的错误。我不明白为什么会这样。我尝试重建一个相同的函数结构和函数调用,但不包含所有的实现细节,想找出问题所在。不过那时候我没有收到错误信息。例如,下面这个就能正常工作:

def outer(x=None):
    def outer2(y):
        def inner(x, *args, **kwargs):
            print x
            print y
            print args
            print kwargs
        def inner2(*args, **kwargs):
            if x is None:
                print "I'm confused"
            inner(x, *args, **kwargs)
        return inner2
    return outer2

outer(1)(2)(3, z=4)

输出:

1
2
(3,)
{'z': 4}

我到底漏掉了什么??

编辑

好的,问题在于在第一个版本中,我实际上对这个变量进行了赋值。Python 检测到了这一点,因此认为这个变量是局部的。

1 个回答

9

局部变量是在编译时确定的:在出错的那一行下面几行代码中,对变量 level 的赋值使得这个变量只在内部函数中有效。所以那一行

if level is None:

实际上是在尝试访问最内层作用域中的一个变量 level,但这个变量还不存在。在 Python 3.x 中,如果你想要修改外部函数的变量,可以在内部函数的开头声明

nonlocal level

。否则,你也可以在内部函数中使用一个不同的变量名。

撰写回答