2011-01-21 11 views
7

Say, tengo cierto margen con variables, y una función llamada en este ámbito quiere cambiar algunas variables inmutables:Acceso al ámbito exterior en Python 2.6

 
def outer(): 
    s = 'qwerty' 
    n = 123 
    modify() 

def modify(): 
    s = 'abcd' 
    n = 456 

¿Es posible de alguna manera para acceder al ámbito exterior? Algo así como nonlocal variables de Py3k.

Claro que puedo hacer s,n = modify(s,n) en este caso, pero ¿qué sucede si necesito una 'inyección' genérica que se ejecute allí y deba poder reasignar a variables arbitrarias?

que tienen en cuenta el rendimiento, por lo que, si es posible, eval & pila de inspección marco no es bienvenido :)


UPD: Es imposible. Período. Sin embargo, hay algunas opciones sobre cómo acceder a las variables en el ámbito externo:

  1. Usar globales. Por cierto, func.__globals__ es un diccionario mutable;)
  2. variables de la tienda en un dict/clase-instancia/cualquier otro recipiente mutable
  3. Dale las variables como argumentos & recuperarlos como una tupla: a,b,c = innerfunc(a,b,c)
  4. Inyectar otra función de bytecode. Esto es posible con byteplay módulo python.
+1

Eso no es cómo funciona el alcance. Solicitas acceder a un alcance en un marco de pila diferente. Sería ** muy ** confuso si el alcance permitiera lo que intentas aquí, piensa en la repetición de cola siendo reescrita en bucles. Entonces, la optimización del código de repente cambiaría el significado de un programa, esto nunca sucederá. – Tino

Respuesta

3

Ésta es no cómo nonlocal obras. No proporciona un alcance dinámico (que es solo un gran PITA esperando que suceda y aún más raramente útil que la característica promedio de "maldad"). Simplemente arregla el alcance léxico.

De todos modos, no puedes hacer lo que tienes en mente (y yo diría que esto es algo bueno). Ni siquiera hay un truco sucio pero fácil (y mientras estamos en ello: ¡tales ataques no son desalentados porque generalmente funcionan un poco peor!). Solo olvídalo y resuelve el problema real correctamente (no lo llamaste, así que no podemos decir nada al respecto).

Lo más parecido que se puede encontrar es definir algún objeto que transmita todo lo que desea compartir y pasarlo de forma explícita (por ejemplo, crear una clase y usar self, como se sugiere en otra respuesta). Pero eso es relativamente complicado de hacer en todas partes, y aún de hackeo (aunque mejor que el alcance dinámico, porque "explícito es mejor que implícito").

7

Defina las variables fuera de las funciones y use la palabra clave global.

s, n = "", 0 

def outer(): 
    global n, s 
    n = 123 
    s = 'qwerty' 
    modify() 

def modify(): 
    global n, s 
    s = 'abcd' 
    n = 456 
+1

Reemplace 'y' con' xor' para que esto funcione. Reescribe desde cero para obtener un buen consejo. – delnan

+0

@delnan, lo siento, pero ??? – orlp

+0

Quiere decir "defínalos afuera, o usa' global', pero no ambos ". – gotgenes

3

Sus opciones son utilizar global variables,

s = None 
n = None 

def outer(self): 
    global s 
    global n 
    s = 'qwerty' 
    n = 123 
    modify() 

def modify(self): 
    global s 
    global n 
    s = 'abcd' 
    n = 456 

o definir los métodos y el uso de una variable de clase o instancia.

class Foo(object): 
    def __init__(self): 
     self.s = None 
     self.n = None 

    def outer(self): 
     self.s = 'qwerty' 
     self.n = 123 
     self.modify() 

    def modify(self): 
     self.s = 'abcd' 
     self.n = 456 
7

A veces me encuentro con un código como este.Una función anidada modifica un objeto mutable en lugar de asignar a un nonlocal:

def outer(): 
    s = [4] 
    def inner(): 
     s[0] = 5 
    inner() 
+1

Eso es interesante. Feo, pero interesante. – gotgenes

+1

'outer.s = 4' etc. –

+3

Puede escribir outer.s = 4, pero eso asignará un atributo a la función outer(). No es lo mismo que asignar a la variable local llamada s. – joeforker

1

probablemente pueda también hacer esto (no diciendo que es la derecha);

definir una función que devuelve una matriz con filas al igual que

["a = qwerty","n = 123"] 

A continuación, realice en el ámbito que necesita el vars

for row in array: 
    eval(row) 

esto es bastante maldito hacky sin embargo.

+0

Creo que te refieres a 'exec (fila)'; eval es solo para expresiones – Ord