[ACCEPTED]-python: attributes on a generator object-python
Yes.
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
0
Unfortunately, generator objects (the results 10 returned from calling a generator function) do 9 not support adding arbitrary attributes. You 8 can work around it to some extent by using 7 an external dict indexed by the generator 6 objects, since such objects are usable as keys 5 into a dict. So where you'd like to do, say:
a = filter(23)
b = filter(45)
...
a.foo = 67
...
x = random.choice([a,b])
if hasattr(x, 'foo'): munge(x.foo)
you 4 may instead do:
foos = dict()
a = filter(23)
b = filter(45)
...
foos[a] = 67
...
x = random.choice([a,b])
if x in foos: munge(foos[x])
For anything fancier, use 3 a class instead of a generator (one or more 2 of the class's methods can be generators, after 1 all).
If you want to interrogate them for debugging 5 purposes, then the following function will 4 help:
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
"""
If you want to interrogate them to 3 implement functionality then classes implementing 2 the iterator protocol are probably a better 1 idea.
No. You can't set arbitrary attributes 7 on generators.
As S. Lott points out, you 6 can have a object that looks like a generator, and 5 acts like a generator. And if it looks like 4 a duck, and acts like a duck, you've got 3 yourself the very definition of duck typing, right 2 there.
It won't support generator attributes 1 like gi_frame
without the appropriate proxy methods, however.
Thinking about the problem, there is a way 9 of having generators carry around a set 8 of attributes. It's a little crazy--I'd 7 strongly recommend Alex Martelli's suggestion 6 instead of this--but it might be useful 5 in some situations.
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)
If you want to ask the 4 generator what it's filtering on, just call 3 send
with a value that evaluates to true. Of 2 course, this code is probably too clever 1 by half. Use with caution.
I realize this is a very belated answer, but...
Instead 4 of storing and later reading some additional 3 attribute, your code could later just inspect 2 the generator's variable(s), using:
filter.gi_frame.f_locals
I 1 guess Ants Aasma hinted at that.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.