このクラスは、自分自身を再帰的に呼び出すジェネレーターです ( self.next()
)。
ジェネレーターにそのすべての値を要求すると、期待どおりにself
(関数を持つオブジェクト) を返すことによって、実際には反復プロトコルに従っていないため、少し奇妙です。.next()
むしろ、self.next()
非常に不適切な表現である の結果を返します。関数は、反復プロトコルで関数が必要であるという事実とはまったく関係がないため、next
単に呼び出されるべきです。permutations()
next
next
とにかく、再帰の深さパラメータで関数を拡張すると、これの再帰トレースを見ることができます:
class Permutation:
def __init__(self,justalist):
self._data = justalist[:]
self._sofar = []
def __iter__(self):
return self.next()
def next(self, depth=0):
debug = lambda text:print('\t'*depth+' '+text)
for elem in self._data:
#print( 'self._data: {}'.format(self._data) )
#print( 'self._sofar: {}'.format(self._sofar) )
if elem not in self._sofar:
self._sofar.append(elem)
if len(self._sofar) == len(self._data):
debug( 'yielding self._sofar[:]: {}'.format(self._sofar[:]) )
yield self._sofar[:]
else:
for v in self.next(depth+1):
debug( 'yielding elements of self.next() one-by-one: {}'.format(v) )
yield v
self._sofar.pop()
デモ:
>>> list( Permutation(range(4)) )
yielding self._sofar[:]: [0, 1, 2, 3]
yielding elements of self.next() one-by-one: [0, 1, 2, 3]
yielding elements of self.next() one-by-one: [0, 1, 2, 3]
yielding elements of self.next() one-by-one: [0, 1, 2, 3]
yielding self._sofar[:]: [0, 1, 3, 2]
yielding elements of self.next() one-by-one: [0, 1, 3, 2]
yielding elements of self.next() one-by-one: [0, 1, 3, 2]
yielding elements of self.next() one-by-one: [0, 1, 3, 2]
yielding self._sofar[:]: [0, 2, 1, 3]
yielding elements of self.next() one-by-one: [0, 2, 1, 3]
yielding elements of self.next() one-by-one: [0, 2, 1, 3]
yielding elements of self.next() one-by-one: [0, 2, 1, 3]
yielding self._sofar[:]: [0, 2, 3, 1]
yielding elements of self.next() one-by-one: [0, 2, 3, 1]
yielding elements of self.next() one-by-one: [0, 2, 3, 1]
yielding elements of self.next() one-by-one: [0, 2, 3, 1]
yielding self._sofar[:]: [0, 3, 1, 2]
yielding elements of self.next() one-by-one: [0, 3, 1, 2]
yielding elements of self.next() one-by-one: [0, 3, 1, 2]
yielding elements of self.next() one-by-one: [0, 3, 1, 2]
yielding self._sofar[:]: [0, 3, 2, 1]
yielding elements of self.next() one-by-one: [0, 3, 2, 1]
yielding elements of self.next() one-by-one: [0, 3, 2, 1]
yielding elements of self.next() one-by-one: [0, 3, 2, 1]
yielding self._sofar[:]: [1, 0, 2, 3]
yielding elements of self.next() one-by-one: [1, 0, 2, 3]
yielding elements of self.next() one-by-one: [1, 0, 2, 3]
yielding elements of self.next() one-by-one: [1, 0, 2, 3]
ご覧のとおり、データの流れは次のとおりです。再帰は最も深いレベル (この場合len([0,1,2,3])
は 4、4) に進み、順列を生成し、それを前のレベルに戻します。そのレベルはそれを前のレベルに戻します。最高レベルでは、利回りはそれを返します。
結論として、これは壊れた恐ろしい実装です。
- この余分なクラスナンセンスを使用して、再帰的な機能パターンによって実現できます
next()
何かを強く暗示する方法で定義しますが、実際には別のことを行います。
- 値が重複している場合は失敗します。たとえば、
Permutation([0,1,1])
失敗します
http://docs.python.org/library/itertools.html#itertools.permutations ( from itertools import permutations
)を使用するだけです。