2012-04-22 9 views
12

dado:python: ¿Cómo capturo una variable declarada en un ámbito externo ancestral no global?

def f(): 
    x = 0 
    def g(): 
     h() 
    def h(): 
     x += 1 
     print(x) 
    g() 

>>> f() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 8, in f 
    File "<stdin>", line 4, in g 
    File "<stdin>", line 6, in h 
UnboundLocalError: local variable 'x' referenced before assignment 
>>> 

¿Cómo puedo hacer h ver la variable x?

Gracias.

EDITAR

debería haber mencionado antes, estoy usando Python 2.7.3

+0

parece como casi -Global para mí ... ¿mala idea? (pero aún es una buena pregunta) – Shep

+0

@Shep: quiere una x diferente para cada llamada f(), por lo que una variable global no funcionaría. – EOL

Respuesta

11

Usted puede hacer un xfunction attribute:

def f(): 
    f.x = 0 
    def g(): 
     h() 
    def h(): 
     f.x += 1 
     print(f.x) 
    g() 

Además, a partir de Python 3, puede usar la palabra clave nonlocal.

+3

+1 Buena solución. –

+3

Si lo adjunta a 'g' o' h', obtiene una 'x' separada para cada llamada a' f' en lugar de una global que tiene alcances como 'f' y probablemente sea global. Eso es especialmente importante si 'g' o' h' terminan como cierres (incluso indirectamente, por ejemplo al agregarse como devolución de llamada). – delnan

5

Si está utilizando Python 3, se utiliza la palabra clave nonlocal. Ponga nonlocal x al comienzo de la función h. Si está utilizando Python 2.x, una solución es hacer x una lista con un elemento, por lo que puede modificarlo:

def f(): 
    x = [0] 
    def g(): 
     h() 
    def h(): 
     x[0] += 1 
     print x[0] 
    g() 

f() 
4

En Python 3 sólo tiene que utilizar nonlocal:

def f(): 
    x = 0 
    def g(): 
     h() 
    def h(): 
     nonlocal x 
     x += 1 
     print(x) 
    g() 
f() 
+1

Solo funciona en Python 3 – jamylak

+0

Está usando print() significa que OP está utilizando Python 3.x solamente. –

+0

Vale la pena mencionar. Pero 'print()' con un argumento realmente funciona en python 2 aunque también estoy de acuerdo en que está usando python 3. – jamylak

0

no podemos poner x como argumentos de la función como solución

def f(): 
    x = 0 
    def g(): 
     h(x) 
    def h(x): 
     x += 1 
     print(x) 
    g() 

f() 
0

más fácil es usar un diccionario o una clase de vacío, por ejemplo:

class Empty: 
    x = 0 

def f(): 
    closure1 = dict(x=0) 
    closure2 = Empty() 
    def g(): h(x) 
    def h(x): 
     closure1["x"] += 1 
     closure2.x += 1 
    g() 
    print closure1["x"], closure2.x 

Aunque ya se proporcionaron muchas buenas soluciones, th ey tienen casos de esquina:

  • no locales, por Ashwini, es Python 3.x
  • atributo de función, por ovgolovin, se fallará se redefine f y más tarde llamada por referencia
Cuestiones relacionadas