Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generator expression in class not producing output I expect

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?

like image 860
shuttle87 Avatar asked Aug 17 '13 20:08

shuttle87


1 Answers

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.

like image 151
Blckknght Avatar answered Sep 28 '22 04:09

Blckknght