2011-04-29 82 views
5

我有下面的代码片段:非绑定本地变量问题

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)我得到Unbound local variable例外21行(在列表上标记)。我不明白为什么。我尝试重新创建功能和函数调用的相同结构,这些调用不包含所有实现细节以找出错误。但是,我没有收到异常消息。例如,下面的工作:

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检测到并因此假定该变量是本地的。

+3

错误信息可以复制几行,如果知道是什么原因,很容易。见http://codepad.org/nI0vCx4L – delnan 2011-04-29 22:36:55

+0

非常感谢,我现在明白了。 – julkiewicz 2011-04-29 22:44:18

+0

@delnan:导致错误的最短代码是在内函数中使用'x = x' :) – 2011-04-29 22:49:25

回答

9

局部变量是在编译时决定的:分配给变量level发生在错误的行下面几行做出局部变量内的功能。太行

if level is None: 

实际上是尝试在最里面的范围内访问变量level,但是这样的变量尚不存在。在Python 3.x中,你可以通过声明

nonlocal level 

在内部功能的开始,如果你真的想改变外部函数的变量解决这个问题。否则,您可以在内部函数中简单地使用不同的变量名称。

+0

看,我在我发布的下面的列表中做同样的事情。它不会崩溃。我不明白有什么区别。 – julkiewicz 2011-04-29 22:38:22

+0

@julkiewicz:不,你不会做同样的事情。在你的第二个片段中根本没有任务*。 (一个赋值是类似'a = 2'的行,这个行在函数内部的任何位置都会使'a'成为本函数中的一个局部变量。) – 2011-04-29 22:41:04

+0

噢,好吧,它会检测赋值。愚蠢的我。谢谢。我会接受并添加另一个编辑。谢谢。 – julkiewicz 2011-04-29 22:42:30