2011-01-19 12 views
5

¿Cómo accedería a una variable local definida dentro de un generador de Python desde fuera del generador?Acceso a variables locales dentro de un generador de Python

Tengo un caso en el que mi generador manipula un estado local, y para pruebas unitarias quiero inspeccionar este estado para asegurarme de que contiene los valores correctos.

No puedo almacenar el estado en una variable de instancia (por ejemplo, self.state = blah), porque podría estar creando múltiples generadores de la misma instancia de clase, lo que significa que los generadores podrían sobreescribir el estado del otro. Tampoco puedo devolver el estado en la expresión de rendimiento, porque el nombre de estado puede cambiar o variar debido a instancias de generador individuales.

p. Ej. Quiero hacer algo como esto (aunque este código no funciona)

from random import random 

class MyIter(object): 
    def __iter__(self): 
     context = {} 
     for i in xrange(10): 
      context[random()] = random() 
      yield i 

obj = MyIter() 
i1 = iter(obj) 
i2 = iter(obj) 
while 1: 
    try: 
     i1.next() 
     i2.next() 
     print i1.context 
     print i2.context 
    except StopIteration: 
     break 

hay alguna forma de acceder a las variables locales mediante la inspección de pila de ejecución de Python?

Respuesta

3

este momento para responder a mi propia pregunta , pero después de excavar en la interfaz del generador, encontré la ruta exacta que necesito para acceder a las variables locales del generador:

from random import random 

class MyIter(object): 
    def __iter__(self): 
     context = {} 
     for i in xrange(10): 
      context[random()] = random() 
      yield i 

obj = MyIter() 
i1 = iter(obj) 
i2 = iter(obj) 
while 1: 
    try: 
     i1.next() 
     i2.next() 
     print i1.gi_frame.f_locals['context'] 
     print i2.gi_frame.f_locals['context'] 
    except StopIteration: 
     break 
+2

¡Ay! No hagas esto, es un detalle de implementación de CPython. Podría cambiar con las versiones más nuevas y ser diferente para las diferentes implementaciones de Python (como Jython o IronPython). Y tampoco es muy fácil de leer ... –

+0

Es muy poco probable que alguna vez use Jython o IronPython, y ambos tienen muchas incompatibilidades con la funcionalidad de CPython "estándar", pero apuntan bien. – Cerin

+0

+1 Aunque nunca confío en ningún código que tenga que acceder al estado interno de un generador durante el funcionamiento normal, * es * muy útil para poder obtener estos datos durante la depuración dado que ha habido algunas veces cuando Python me ha dejado preguntándome, "¿Qué estabas pensando?" (Además, nunca me sentiría mal por responder mi propia pregunta, a menos que la respuesta fuera incorrecta;)) – Augusta

0

Debe tratar el generador como una caja negra. Las pruebas unitarias no deberían preocuparse por su estado interno, porque eso es solo un detalle de implementación; solo deberían preocuparse por el comportamiento especificado.

0

Si realmente quiere hacer esto, separar la clase de iterador de la clase de contenedor:

from random import random 

class MyContainer(object): 
    def __iter__(self): 
     return MyIter(self) 

class MyIter(object): 
    def __init__(self, container): 
     self.container = container 
     self.context = {} 
     self.it = iter(xrange(10)) 
    def next(self): 
     self.context[random()] = random() 
     return next(self.it) 
    def __iter__(self): 
     return self 

obj = MyContainer() 
# ... 

no considero esto muy útil, aunque ...

+0

Gracias. Este es un enfoque muy limpio y OO, aunque agrega un poco de complejidad adicional. – Cerin

Cuestiones relacionadas