2016-03-26 7 views
2

反復するオブジェクトの「ソース」がいくつかあるイテレータを作成したいとします。私は、__next__()メソッドにオプションのキーワード引数を与えて、ソースを選択することができるようにしたいと考えています(キーワード引数は無作為にソースを選択するだけです)。その後の、私は本当のIteratorをinfinite_iterator作るためにdef __next__(self, **kwargs):を書きたい場合はイテレータを作成し、いくつかの反復元を選択する

#!/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)) 

問題は、次のとおりです。回避策として、私はこのあっけなくコードを書いているので、__next__()原因の問題(下記参照)を使用して

もちろん、私が書きたい:

print("Any name: " + next(S)) 
print("Any girl's name: " + next(S, choice=1)) 
print("Any boy's name: " + next(S, choice=0)) 

が、エラー(2Dライン)を取得:

TypeError: next() takes no keyword arguments 

私はこの呼び出しでnext(S, choice=1)がオブジェクトに定義された__next__()関数を使用すると考えました。このエラーのために、私は実際にはそうではないと考えています。 infinite_iteratorは "Iteratorオブジェクト"から継承していないので、これはまったくの再定義ではないので、これは期待できます(私が理解する限り、そのようなオブジェクトはありません)。しかし、もう1つの手で、私はnext(S)と呼んだだけで、この場合、私の__next__()というメソッドが実際に呼び出されます(これは反復処理のためにリストをランダムに選択します)。

最後に、このようなイテレータを実現するソリューションはありますか?

答えて

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ループの次の反復のために選択を行うために使用されます。

あなたはそれが最初のyieldの文に当たるように、少なくとも一回nextを呼び出すことによって、それを起動する必要がありますが、それの後に、それは両方の方法は、(のためnextまたは完全なランダム選択のためのsend(None)、またはsend(option)を使用して動作します

+0

これで '__next__'を呼び出すことはできません:' next(s、choice = 1) '? – zezollo

+0

これはイテレータプロトコル(または' next'組み込み関数)がどのように定義されているのか、あなたはその定義を変更することはできませんので、いいえ、しかし、 'send'が動作します、なぜあなたは'特に 'を使用して固執しているのか分かりません。 – tzaman

関連する問題