我想创建一个具有多个"来源的迭代器"要迭代的对象我希望能够为其__next__()
方法提供一个可选的关键字参数,该参数可以选择源(没有关键字参数意味着,只需随机选择一个源)。
使用__next__()
会导致问题(见下文),因此我已经编写了这个令人不满意的代码:
#!/usr/bin/env python3
import random
class infinite_iterator(object):
def __init__(self, sources):
self.collector = []
for s in sources:
random.shuffle(s)
self.collector.append([])
self.sources = sources
def __iter__(self):
return self
# Workaround: calling it next instead of __next__
# (not the python3 way...)
def next(self, **kwargs):
sce_nb = random.choice([ n for n in range(len(self.sources)) ])
if 'choice' in kwargs:
sce_nb = kwargs['choice']
self.collector[sce_nb].append(self.sources[sce_nb][0])
output = self.sources[sce_nb].pop(0)
# Repopulate any empty 'source'
if not self.sources[sce_nb]:
(self.sources[sce_nb], self.collector[sce_nb]) = \
(self.collector[sce_nb], self.sources[sce_nb])
random.shuffle(self.sources[sce_nb])
return output
S = infinite_iterator([["Adam", "Paul", "Oliver", "Aaron", "Joshua", "Jack"],
["Mary", "Sophia", "Emily", "Isobel", "Grace", "Alice", "Lucy"]])
print("Any name: " + S.next())
print("Any girl's name: " + S.next(choice=1))
print("Any boy's name: " + S.next(choice=0))
问题是,如果我想写def __next__(self, **kwargs):
以使infinite_iterator成为真正的迭代器,那么当然我想写:
print("Any name: " + next(S))
print("Any girl's name: " + next(S, choice=1))
print("Any boy's name: " + next(S, choice=0))
但得到错误(第2行):
TypeError: next() takes no keyword arguments
我认为此调用next(S, choice=1)
将使用对象中定义的__next__()
函数。由于这个错误,我认为一方面它实际上没有。这可能是可以预料到的,因为它并不完全是重新定义,因为infinite_iterator不会继承自" Iterator对象" (据我所知,没有这样的对象)。但另一方面,如果我只调用next(S)
它可以正常工作,在这种情况下,实际上会调用我的 __next__()
方法(它会随机选择一个列表进行迭代)。
最后,是否有实现这种迭代器的解决方案?
答案 0 :(得分:0)
撰写generator(技术上是协程)并使用send
传递您的选择:
import random
def selector(sources):
option = None
while True:
if option is None:
option = yield random.choice(random.choice(sources))
else:
option = yield random.choice(sources[option])
s = selector([["Adam", "Paul", "Oliver", "Aaron", "Joshua", "Jack"],
["Mary", "Sophia", "Emily", "Isobel", "Grace", "Alice", "Lucy"]])
print("Any name: " + next(s))
print("Any girl's name: " + s.send(1))
print("Any boy's name: " + s.send(0))
每次调用send
时,它的工作方式都会传递给option
变量,该变量用于选择while循环的下一次迭代。
您必须至少调用next
一次,然后点击第一个yield
语句启动它,但之后它会双向工作(使用{{ 1}}或next
表示完整的随机选择,或send(None)
表示特定来源。