我不明白这个带有extend和append的扁平化是如何在Python3.6中工作的
我把下面的代码放在Pythontutor.com上,看看我是否能理解它是如何工作的。然而,尽管阅读了关于展平、扩展和附加的文章,我还是有点迷茫。我的问题是,为什么它会对“b”进行两次评估?例如,它进入extend,然后创建一个新列表,然后将“b”带到else和appends?我将非常感谢任何能让我更清楚这一点的帮助我不明白这个带有extend和append的扁平化是如何在Python3.6中工作的,python,python-3.x,Python,Python 3.x,我把下面的代码放在Pythontutor.com上,看看我是否能理解它是如何工作的。然而,尽管阅读了关于展平、扩展和附加的文章,我还是有点迷茫。我的问题是,为什么它会对“b”进行两次评估?例如,它进入extend,然后创建一个新列表,然后将“b”带到else和appends?我将非常感谢任何能让我更清楚这一点的帮助 aList = ['b','a','c',2],[[[3]],'dog',4,5] def flatten(aList): newList = [ ] for i
aList = ['b','a','c',2],[[[3]],'dog',4,5]
def flatten(aList):
newList = [ ]
for item in aList:
if type(item) == type([]):
newList.extend(flatten(item))
else:
newList.append(item)
return newList
print(flatten(aList))
函数用于再次调用自身。其思想是将一个较大的问题分解为较小的部分,每个部分独立解决,然后将结果组合起来解决较大的问题
在这里,只要当前序列中包含的元素是列表,Flatte就会再次调用自己。这些递归调用将继续,直到较小的部分不再包含更多列表
需要记住的是,像newList这样的本地名称对于每个函数调用都是本地的。即使展平调用本身,每个调用都会产生一个独立的新的本地newList值
对于您的输入,一个元组:
['b', 'a', 'c', 2], [[[3]], 'dog', 4, 5]
第一个元素也是一个列表:
['b', 'a', 'c', 2]
因此,这将传递给一个新的扁平化调用。该子列表中没有更多的列表,因此该函数所做的只是将每个项附加到newList列表中,并将其作为结果返回。返回后,恢复第一个展平函数,并通过extend调用将返回的列表添加到本地newList
一直以来,当您看到Pythontutor如何将其可视化时,您会注意到原始对象中有许多指向这些列表的指针:
您可以看到,第一个展平调用引用了一个包含两个元素的元组,第二个展平调用引用了该元组的第一个元素,即包含的列表。Python值都存在于一个称为“heap”的专用内存区域中,名称和列表元素都只是标签、引用、带有字符串的名称标签,您可以拥有任意数量的此类标签。看见两个展平函数都有自己的指向列表对象的newList引用,而当前活动的展平函数正忙于将列表引用中的值复制到newList
因此,一旦对扁平化的递归调用将控制权返回到剩余的、仍处于活动状态的扁平化函数。使用返回值扩展本地newList函数后,该函数将移动到下一个元素[[[3]],“dog',4,5],该元素还有几个列表要处理,首先[[3]],然后[3],然后再没有嵌套列表要处理
如果您用缩进法将这些内容全部写出来,您将得到:
->展平['b','a','c',2],[[3],'dog',4,5]
newList设置为空列表
项目设置为['b','a','c',2]
typeitem是一个列表,因此递归
->展平['b','a','c',2]
newList设置为空列表
项设置为“b”,而不是列表,附加到新列表,现在为['b']
项目设置为“a”,而不是列表,附加到新列表,现在为['b','a']
项目设置为“c”,而不是列表,附加到新列表,现在为['b'、'a'、'c']
项目设置为2,而不是列表,附加到newList,现在为['b','a','c',2]
循环完成后,返回newList
展平[[3]],“狗”,4,5]
newList设置为空列表
项目设置为[[3]]
typeitem是一个列表,因此递归
->展平[[3]]
newList设置为空列表
项目设置为[3]
typeitem是一个列表,因此递归
->展平[3]
newList设置为空列表
项目设置为3
typeitem是一个列表,因此递归
->展平[3]
项设置为3,而不是列表,附加到newList,现在为[3]
循环完成后,返回newList
如果写得更简单,也许更容易理解:
aList = ['b','a','c',2],[[[3]],'dog',4,5]
def flatten(value):
if not isinstance(value,(list,tuple)) : return [value]
return [ item for subItem in value for item in flatten(subItem) ]
如果value参数是一个列表或元组,则将每个元素连接起来以形成平坦的输出第二行。因为这些元素中的每一个元素本身都可以是列表或元组,所以函数会在连接到其他元素之前调用自身以展平该项。当函数的参数是标量值(即不是列表或元组)时,函数将停止调用自身。在这种情况下,它将返回值本身作为单个元素列表的第1行,因为它不能进一步展平,并且它的调用者本身需要一个列表
flatten( aList ) : returns ['b']+['a']+['c']+[2]+[3]+['dog']+[4]+[5]
--> flatten( ['b','a','c',2] ) : returns ['b']+['a']+['c']+[2]
--> flatten('b') : returns ['b']
--> flatten('a') : returns ['a']
--> flatten('c') : returns ['c']
--> flatten(2) : returns [2]
--> flatten( [[[3]],'dog',4,5] ): returns [3]+['dog']+[4]+[5]
--> flatten([[3]]) : returns [3]
--> flatten([3]) : returns [3]
--> flatten(3) : returns [3]
--> flatten('dog') : returns ['dog']
--> flatten(4) : returns [4]
--> flatten(5) : returns [5]
函数递归,再次调用自身来处理问题的一个子集。如果不清楚的话,值得指出的是,输入是一个元组。括号不是必须的。这对我来说更有意义了!谢谢你的帮助!很高兴能帮上忙!如果您觉得它对您有用,请随时联系-