简体   繁体   中英

Different behavior of consumed Python generators depending on implementation

Consider the following code example. I defines two implementations of a generator which yields the numbers 0, 1, 2. My expectation is that SimpleClass().classgen behaves the same way as mygen. I know that generators can be consumed only once. That means one can only iterate over a generator once.

class SimpleClass(object):
    @property
    def classgen(self):
        for i in range(3):
            yield i

mygen = (p for p in range(3))


##### Test behavior
sc = SimpleClass()
print(type(sc.classgen))
print(type(mygen))
print("")

print("Iterating over new sc.classgen")
for i in sc.classgen:
    print(i)
print("")

print("Iterating over consumed sc.classgen")
for i in sc.classgen:
    print(i)
print("")


print("Iterating over new mygen")
for i in mygen:
    print(i)
print("")

print("Iterating over consumed mygen")
for i in mygen:
    print(i)

My expectation was that the first iteration over each of the generators print the numbers 0, 1, 2 and in fact that's what's happening. But then I would expect that when I iterate the second time over each generator that I will see no prints. That is true for the second loop over mygen, but the second loop over sc.classgen still prints the numbers 0, 1, 2. I cannot explain why that is. I thought generators can only be used once?

This is because you are not calling the same generator, if you assign sc.classgen to a variable, it will behave like you expect.

class SimpleClass(object):
    @property
    def classgen(self):
        for i in range(3):
            yield i

mygen = (p for p in range(3))


##### Test behavior
sc = SimpleClass()
print(type(sc.classgen))
print(type(mygen))
print("")

g = sc.classgen

print("Iterating over new sc.classgen")
for i in g:
    print(i)
print("")

print("Iterating over consumed sc.classgen")
for i in g:
    print(i)
print("")


print("Iterating over new mygen")
for i in mygen:
    print(i)
print("")

print("Iterating over consumed mygen")
for i in mygen:
    print(i)

As classgen property is a function, it will create a new one every time you access it.

@property doesn't cache the return value of the method, therefore you are using different generators every time you call sc.classgen . You can test this:

import time


class SimpleClass(object):
    @property
    def the_time(self):
        return time.time()


sc = SimpleClass()

time1 = sc.the_time
time.sleep(2)
time2 = sc.the_time

print(time1 == time2)
> False

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM