Reputation: 4282
I want to have a class with an __iter__
method that depends on a cache
argument when instances are created.
If an instance is created with cache=False
, then the instance should be iterated through like a generator (creating and discarding each item as needed). If an instance is created with cache=True
, then the object should create a list of the items, store it, and then have it available to be iterated through repeatedly.
So for example (this doesn't work):
class Foo(object):
def __init__(self, max=5, cache=False):
if cache:
self.items = range(max)
self.__iter__ = iter(self.items)
else:
self.__iter__ = iter(range(max))
Then if I did this, the expected result is to print 0--4, and to have this available only once.
test_obj = Foo()
for i in test_obj:
print i, # 0 1 2 3 4
for i in test_obj:
print i, # empty
But if I do this, the expected result is to print 0--4, and to have this available as many times as necessary.
test_obj = Foo(cache=True)
for i in test_obj:
print i, # 0 1 2 3 4
for i in test_obj:
print i, # 0 1 2 3 4
Upvotes: 1
Views: 142
Reputation: 104832
Python won't look up a __op__
method on an instance, only on a class. So your idea of defining __iter__
from __init__
won't work. However, you can implement __iter__
such that its behavior differs dending on a value set in __init__
. Here's one way:
class Foo(object):
def __init__(self, max=5, cache=False):
if cache:
self.iterable = range(max)
else:
self.iterable = iter(xrange(max))
def __iter__(self):
return iter(self.iterable)
This works because an iterator is "iterable" just like a sequence is. However, its __iter__
method returns itself (so no matter how many times you can iter
on it, you can only iterate through its values once).
Upvotes: 2
Reputation: 122154
Here is one way to approach it - if it's not cached, discard self.items
the first time __iter__
is called:
class Foo(object):
def __init__(self, max_=5, cached=False):
self.items = range(max_)
self._cached = cache
def __iter__(self):
out = self.items
if not self._cached:
self.items = []
return iter(out)
In action:
>>> test_obj = Foo()
>>> for i in test_obj:
print i,
0 1 2 3 4
>>> for i in test_obj:
print i,
>>> test_obj = Foo(cached=True)
>>> for i in test_obj:
print i,
0 1 2 3 4
>>> for i in test_obj:
print i,
0 1 2 3 4
Upvotes: 1