2009-06-05 20 views
5

¿Es posible crear un atributo en un objeto generador?python: atributos en un objeto generador

Aquí hay un ejemplo muy sencillo:

def filter(x): 
    for line in myContent: 
     if line == x: 
      yield x 

Ahora dicen que tengo una gran cantidad de éstos generador de filtrar objetos que flotan alrededor ... tal vez algunos de ellos son anónimos ... Quiero volver más tarde e interrogar por lo que están filtrando. ¿Hay alguna manera de que pueda a) interrogar al objeto generador por el valor de xob) establecer un atributo con el valor de x que luego pueda interrogar?

Gracias

Respuesta

6

Desafortunadamente, los objetos del generador (los resultados devueltos al llamar a una función de generador) no admiten la adición de atributos arbitrarios. Puede solucionarlo hasta cierto punto utilizando una dict externa indexada por los objetos del generador, ya que tales objetos son utilizables como claves en un dict. Así que el lugar donde quiere como hacer, dicen:

a = filter(23) 
b = filter(45) 
... 
a.foo = 67 
... 
x = random.choice([a,b]) 
if hasattr(x, 'foo'): munge(x.foo) 

en su lugar puede hacer:

foos = dict() 
a = filter(23) 
b = filter(45) 
... 
foos[a] = 67 
... 
x = random.choice([a,b]) 
if x in foos: munge(foos[x]) 

Para cualquier cosa más elegante, utilizar una clase en lugar de un generador (una o más de la clase de los métodos pueden ser generadores, después de todo).

16

Sí.

class Filter(object): 
    def __init__(self, content): 
     self.content = content 
    def __call__(self, someParam): 
     self.someParam = someParam 
     for line in self.content: 
      if line == someParam: 
       yield line 
2

No. No puede establecer atributos arbitrarios en los generadores.

Como S. Lott señala, puede tener un objeto que se ve como un generador, y actos como un generador. Y si se ve como un pato, y actúa como un pato, usted mismo tiene la definición misma de tipado de pato, allí mismo.

No es compatible con generador de atributos como gi_frame sin los métodos de apoderado adecuados, sin embargo.

0

Pensando en el problema, existe es una forma de tener generadores llevar a través de un conjunto de atributos. Es un poco loco, recomendaría encarecidamente la sugerencia de Alex Martelli en lugar de esto, pero podría ser útil en algunas situaciones.

my_content = ['cat', 'dog days', 'catfish', 'dog', 'catalog'] 

def filter(x): 
    _query = 'I\'m looking for %r' % x 

    def _filter(): 
     query = yield None 
     for line in my_content: 
      while query: 
       query = yield _query 

      if line.startswith(x): 
       query = yield line 

     while query: 
      query = yield _query 

    _f = _filter() 
    _f.next() 
    return _f 

for d in filter('dog'): 
    print 'Found %s' % d 

cats = filter('cat') 
for c in cats: 
    looking = cats.send(True) 
    print 'Found %s (filter %r)' % (c, looking) 

Si desea solicitar el generador de lo que está filtrando en adelante, simplemente llame send con un valor que se evalúa como verdadera. Por supuesto, este código es probablemente demasiado inteligente a la mitad. Usar con precaución.

3

Si desea interrogar a ellos para fines de depuración, entonces la función siguiente le ayudará:

import inspect 

def inspect_generator(g): 
    sourcecode = open(g.gi_code.co_filename).readlines() 
    gline = g.gi_code.co_firstlineno 
    generator_code = inspect.getblock(sourcecode[gline-1:]) 

    output = "Generator %r from %r\n" % (g.gi_code.co_name, g.gi_code.co_filename) 
    output += "".join("%4s: %s" % (idx+gline, line) for idx, line in enumerate(generator_code)) 

    output += "Local variables:\n" 
    output += "".join("%s = %r\n" % (key,value) for key,value in g.gi_frame.f_locals.items()) 

    return output 

print inspect_generator(filter(6)) 
"""Output: 
Generator 'filter' from 'generator_introspection.py' 
    1: def filter(x): 
    2:  for line in myContent: 
    3:   if line == x: 
    4:    yield x 
Local variables: 
x = 6 
""" 

Si desea interrogar a ellos para implementar la funcionalidad continuación, las clases que implementan el protocolo de iteración son probablemente una mejor idea.

0

me di cuenta que es una respuesta muy tardía, pero ...

En lugar de almacenar y más tarde la lectura de algún atributo adicional, el código podría más tarde sólo inspeccionar variable (s) del generador, usando:

filter.gi_frame.f_locals

supongo hormigas Aasma alusión a eso.

+0

Intenté su sugerencia para inspeccionar las variables del generador. Funciona en la medida en que 'StopIteration' aún no se ha alcanzado. Después de eso, 'gi_frame' se convierte en' None'. – bli

Cuestiones relacionadas