I'd like to use some generator expressions as attributes for some expensive computation of data. If possible I would like to be able to do something like this:
class Test:
def __init__(self):
self.data = []
self.evens = (i for i in self.data if i % 2 == 0)
def __main__():
t = Test()
t.data = [1,2,3,4,5,6,7,8]
for item in t.evens:
print(item)
if __name__ == '__main__':
__main__()
I would liked to have seen this print out 2 4 6 8
but this gives no output. Have I made some sort of simple mistake here?
Is what I am trying to do here possible or will I need to use yield
to do this?
While the other answers have correctly diagnosed the error (that your evens
generator is being initialized with the original empty data
list), I think the suggestion to set a value for data
still won't do what you want.
Currently you can only iterate over evens
once, and after you do it will have been consumed. What I think you want is for evens
to always be accessible as a generator of the even values of whatever the current data
value has. The way to do that is to make it a property
, with a function that returns the generator each time it is called:
class Test:
def __init__(self):
self.data = []
@property
def evens(self):
return (i for i in self.data if i % 2 == 0)
Usage:
>>> t = Test()
>>> t.data = [1, 2, 3, 4, 5, 6]
>>> list(t.evens)
[2, 4, 6]
>>> list(t.evens) # works more than once
[2, 4, 5]
>>> t.data = [10, 15, 20, 25, 30]
>>> list(t.evens)
[10, 20, 30]
If you needed a more complicated generator, you could use yield
in the function, rather than returning a generator object, but a generator expression works easily enough for getting even values.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With