Reputation: 5805
I want to get "next asset" with an iterator-like object, but (instead of __next__()
method) there are two algorithms loading next asset (next1
and next2
below), which can be implemented as a "quasi-iterator" like:
class AssetLoader(object):
def __init___(self):
pass
def next1(self):
# ...
def next2(self):
# ...
To be clear, what is the next retrieved object may depends on the "history" of calling next1
and next2
, like:
next1()
; next1()
; next2()
; next1()
; next2()
My question: May this (two kinds of "next" step in an iterator) be implemented as a generator function?
I guess this can be done with a global variable to which the function refers. But can it be done without using global variables, but with some local variable?
If it is hard or impossible with current Python, can we discuss how to add new semantics to Python to make it possible?
Upvotes: 1
Views: 167
Reputation: 55469
Here's a simple example of using send
to switch a generator between two different iteration modes: it either increments its current value or multiplies it. The same principle can be applied to your graph traversal task.
The send
method allows you to send an object into the generator. Annoyingly, the result of send
is the current value that you would have obtained by calling next
; it would be nice if you could send without having the generator yield a value, but that's just something we have to live with.
def add_or_mul(current, step, scale, mode='add'):
''' A generator that either adds step to the current value,
or multiplies it by scale
'''
while True:
newmode = yield current
if newmode is not None:
if newmode not in ('add', 'mul'):
raise ValueError('Bad mode: ' + newmode)
mode = newmode
if mode == 'add':
current += step
else:
current *= scale
# Test
gen = add_or_mul(1, 1, 2)
for i in range(5):
print(next(gen))
print(gen.send('mul'))
for i in range(4):
print(next(gen))
print(gen.send('add'))
for i in range(4):
print(next(gen))
output
1
2
3
4
5
10
20
40
80
160
161
162
163
164
165
If you have trouble applying this technique to your graph traversal task please ask a fresh question (possibly linking to this one) that includes some relevant graph code, so that answerers don't have to write that stuff from scratch in order to test and demonstrate their code.
Upvotes: 3
Reputation: 991
You can try this:
class AssetLoader(object):
def __init___(self):
self.current_next = self.next1
def next1(self):
if condition:
self.current_next = self.next2
elif conition:
return x
else:
raise StopIteration
def next2(self):
if condition:
self.current_next = self.next1
elif conition:
return y
else:
raise StopIteration
def __next__(self):
return self.current_next()
def __iter__(self):
return self
Upvotes: 1