解释列出所有排列的Python代码
联机找到此代码()。我试图弄明白,但没有取得多大进展。真正让我感到困惑的是:解释列出所有排列的Python代码,python,generator,permutation,Python,Generator,Permutation,联机找到此代码()。我试图弄明白,但没有取得多大进展。真正让我感到困惑的是: class Permutation: def __init__(self,justalist): self._data = justalist[:] self._sofar = [] def __iter__(self): return self.next() def next(self): for elem in self._da
class Permutation:
def __init__(self,justalist):
self._data = justalist[:]
self._sofar = []
def __iter__(self):
return self.next()
def next(self):
for elem in self._data:
if elem not in self._sofar:
self._sofar.append(elem)
if len(self._sofar) == len(self._data):
yield self._sofar[:]
else:
for v in self.next():
yield v
self._sofar.pop()
要运行类的代码,请执行以下操作:
for v in self.next():
yield v
self._sofar.pop()
我读过:
“通过调用yield,下一个成员现在是一个生成器函数,因此我们不能简单地再次调用next-如果这样做,我们将丢失返回的生成器对象,从而丢失返回的置换!我们必须在self中使用一个简单的for v循环返回的结果。next():yield v。这样,结果将正确地传播到”家长“呼叫”
我不知道这是否能解释发生了什么,但这对我来说毫无意义。(我以为我理解生成器。)这个类是一个递归调用自身的生成器(
self.next()
)
这有点奇怪,因为当您要求生成器提供其所有值时,它并不像您所期望的那样返回self
(一个带有.next()
函数的对象),从而真正遵循迭代协议。相反,它返回self.next()的结果,这是非常糟糕的措辞。next
函数应该被称为permutations()
,因为next
函数实际上与迭代协议中需要next
函数这一事实无关
无论如何,如果使用递归深度参数扩充函数,则可以看到此函数的递归跟踪:
for i in Permutation(a):
print(i)
演示:
如您所见,数据流如下所示:递归前进到最深的级别(在本例中为4,len([0,1,2,3])
is 4),生成置换,并返回到上一级别。该水平将使其返回到上一水平,以此类推。在最高水平,收益率将返回该水平
总之,这是一个失败而糟糕的实施,因为:
next()
,在某种程度上强烈暗示了某些东西,但实际上却做了其他事情置换([0,1,1])
将失败您应该只使用(
来自itertools导入置换)这个类是一个递归调用自身的生成器(self.next()
)
这有点奇怪,因为当您要求生成器提供其所有值时,它并不像您所期望的那样返回self
(一个带有.next()
函数的对象),从而真正遵循迭代协议。相反,它返回self.next()
的结果,这是非常糟糕的措辞。next
函数应该被称为permutations()
,因为next
函数实际上与迭代协议中需要next
函数这一事实无关
无论如何,如果使用递归深度参数扩充函数,则可以看到此函数的递归跟踪:
for i in Permutation(a):
print(i)
演示:
如您所见,数据流如下所示:递归前进到最深的级别(在本例中为4,len([0,1,2,3])
is 4),生成置换,并返回到上一级别。该水平将使其返回到上一水平,以此类推。在最高水平,收益率将返回该水平
总之,这是一个失败而糟糕的实施,因为:
next()
,在某种程度上强烈暗示了某些东西,但实际上却做了其他事情置换([0,1,1])
将失败您应该只使用(
从itertools导入排列
)关键思想是排列。next()
生成\u数据
中以\u开头的所有项目排列
为此,我们尝试将每个可能的元素添加到\u sofar
的末尾。然后有两种情况:要么\u sofar
足够长(即,我们有一个完整的排列),在这种情况下,我们只产生一个副本;或者它不是(也就是说,我们有一个部分排列),在这种情况下,我们递归地调用next
——通常,这会产生很多排列,所以我们必须一个接一个地产生它们
顺便说一句,如果代码更像这样,我认为代码会更整洁、更容易理解(危险:未经测试的代码):
它还有一个优点,就是在没有元素的情况下给出正确的答案(只有一个排列,即空序列;给定的代码不会产生任何元素)。我也倾向于进行一些优化,但它们并不重要。关键思想是排列。next()
产生\u data
中所有以\u sofar
开头的项的排列
为此,我们尝试将每个可能的元素添加到\u sofar
的末尾。然后有两种情况:要么\u sofar
足够长(即,我们有一个完整的排列),在这种情况下,我们只产生一个副本;或者它不是(也就是说,我们有一个部分排列),在这种情况下,我们递归地调用next
——通常,这会产生很多排列,所以我们必须一个接一个地产生它们
顺便说一句,如果代码更像这样,我认为代码会更整洁、更容易理解(危险:未经测试的代码):
它还有一个优点,就是在没有元素的情况下给出正确的答案(只有一个排列,即空序列;给定的代码不会产生任何元素)。我也倾向于做一些优化,但它们并不重要。尝试一下产量
,编写一个生成器函数
>>> 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]
def next(self):
if len(self._sofar) == len(self._data):
yield self._sofar[:]
else:
for elem in self._data:
if elem not in self._sofar:
self._sofar.append(elem)
for v in self.next():
yield v
self._sofar.pop()