2011-04-29 18 views
5

Tengo un fragmento de código siguiente:problema local variable en Python

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 

Realmente no importa lo que hace, sin embargo, que lo ponga en su forma original, ya que era incapaz de recrear la situación con algo más simple.

El problema es que cuando llamo a isolation_level(1)(some_func)(some, args, here) obtengo la excepción Unbound local variable en la línea 21 (marcada en el listado). No entiendo por qué. Traté de volver a crear la misma estructura de funciones y llamadas a funciones que no contuviera todos los detalles de implementación para descubrir qué es lo que está mal. Sin embargo, no recibo el mensaje de excepción. Por ejemplo, las siguientes obras:

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) 

Prints:

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

¿Qué me falta ??

EDITAR

Ok, por lo que el problema es que en la primera versión que se realizan realmente una asignación a la variable. Python detecta eso y, por lo tanto, asume que la variable es local.

+3

El mensaje de error se puede reproducir en unas pocas líneas, y es fácil si se sabe cuál es la causa. Ver http://codepad.org/nI0vCx4L – delnan

+0

Muchas gracias, lo entiendo ahora. – julkiewicz

+0

@delnan: el código más corto que causa el error es usar 'x = x' dentro de la función interna :) –

Respuesta

9

Las variables locales se determinan en tiempo de compilación: las asignaciones a la variable level unas pocas líneas debajo de la línea se produce el error al convertir esa variable en local para la función interna. Por lo que la línea de

if level is None: 

en realidad trata de acceder a una variable level en el ámbito más interno, pero esa variable no existe todavía. En Python 3.x, puede resolver este problema al declarar

nonlocal level 

al comienzo de la función interna, si realmente se quiere alterar la variable de la función externa. De lo contrario, simplemente puede usar un nombre de variable diferente en la función interna.

+0

Mira, hago lo mismo en el listado a continuación que publiqué. Y no se cuelga. No entiendo cuál es la diferencia. – julkiewicz

+0

@julkiewicz: No, no haces lo mismo. No hay * asignaciones * en absoluto en su segundo fragmento. (Una asignación es una línea como 'a = 2 '. Esta línea, en cualquier lugar dentro de una función, haría' a' una variable local en cualquier lugar dentro de esta función.) –

+0

Oh, de acuerdo, entonces detecta la tarea. Estúpido yo. Gracias. Aceptaré y agregaré otra edición. Gracias. – julkiewicz

Cuestiones relacionadas