Python中的内部MOST列表
为什么??看,一开始他们是平等的。你做同样的操作,但是你得到不同的结构。为什么构造嵌套列表的两种方法给出不同的结果Python中的内部MOST列表,python,list,reference,list-comprehension,Python,List,Reference,List Comprehension,为什么??看,一开始他们是平等的。你做同样的操作,但是你得到不同的结构。为什么构造嵌套列表的两种方法给出不同的结果 >>> lll=[[[[[]]*2 for a in xrange(2)] for b in xrange(2)]] >>> ll=[[[[[]]*2]*2]*2] >>> lll [[[[[], []], [[], []]], [[[], []], [[], []]]]] >>> ll [[[[[], []]
>>> lll=[[[[[]]*2 for a in xrange(2)] for b in xrange(2)]]
>>> ll=[[[[[]]*2]*2]*2]
>>> lll
[[[[[], []], [[], []]], [[[], []], [[], []]]]]
>>> ll
[[[[[], []], [[], []]], [[[], []], [[], []]]]]
>>> ll==lll
True
>>> ll[0][0][0][0]=1
>>> lll[0][0][0][0]=1
>>> ll==lll
False #Why?
结构
ll和lll不相等,因为它们包含不同的值:
In [3]: ll[0][0][0][0]=1
In [4]: lll[0][0][0][0]=1
In [5]: ll
Out[5]: [[[[1, []], [1, []]], [[1, []], [1, []]]]]
In [6]: lll
Out[6]: [[[[1, []], [[], []]], [[[], []], [[], []]]]]
现在,让我们退一步,举一个更简单的例子,所有这些括号都让我头晕目眩:
In [20]: a = [[0]]*2
In [21]: b = [[0] for _ in range(2)]
In [22]: a
Out[22]: [[0], [0]]
In [23]: b
Out[23]: [[0], [0]]
In [24]: a[0][0] = 1
In [25]: b[0][0] = 1
In [26]: a
Out[26]: [[1], [1]]
In [27]: b
Out[27]: [[1], [0]]
发生这种情况的原因是a的两个元素指向同一个列表,而b的两个元素指向两个不同的列表:
In [29]: id(a[0]), id(a[1])
Out[29]: (14760488, 14760488)
In [30]: id(b[0]), id(b[1])
Out[30]: (14761136, 14760704)
ll和lll不相等,因为它们包含不同的值:
In [3]: ll[0][0][0][0]=1
In [4]: lll[0][0][0][0]=1
In [5]: ll
Out[5]: [[[[1, []], [1, []]], [[1, []], [1, []]]]]
In [6]: lll
Out[6]: [[[[1, []], [[], []]], [[[], []], [[], []]]]]
现在,让我们退一步,举一个更简单的例子,所有这些括号都让我头晕目眩:
In [20]: a = [[0]]*2
In [21]: b = [[0] for _ in range(2)]
In [22]: a
Out[22]: [[0], [0]]
In [23]: b
Out[23]: [[0], [0]]
In [24]: a[0][0] = 1
In [25]: b[0][0] = 1
In [26]: a
Out[26]: [[1], [1]]
In [27]: b
Out[27]: [[1], [0]]
发生这种情况的原因是a的两个元素指向同一个列表,而b的两个元素指向两个不同的列表:
In [29]: id(a[0]), id(a[1])
Out[29]: (14760488, 14760488)
In [30]: id(b[0]), id(b[1])
Out[30]: (14761136, 14760704)
当您使用这样的列表理解时,会为每个迭代创建新的列表 当您将一个列表相乘时,同一个引用会一次又一次地重复 当该引用指向一个列表时,它意味着同一个内部列表被一次又一次地复制 因此,当你乘法时,只有一个空列表,被一个列表引用两次,被一个列表引用两次,被另一个列表引用两次,这是最终的外部列表中的唯一项 当您使用列表理解时,每个引用都指向一个新的、不同的列表 因此,当您将包含对空列表的两个引用的列表的第一项指向另一个对象时,您可以在引用该列表的任何地方看到更改。因为它被一个本身被引用了两次的列表引用了两次,所以您可以在四个地方看到更改 如果要将值附加到最内部的列表中:
ll[0][0][0][0].append(1)
您将看到该值被引用了八次:
[[[[[1], [1]], [[1], [1]]], [[[1], [1]], [[1], [1]]]]]
因为所有的内部列表实际上都是相同的列表
ll的真正结构不是上面看起来的那样,而是:
[ ]
|
[ , ]
\ /
[ , ]
\ /
[ , ]
\ /
[]
Python显示它的方式很容易引起误解。当您使用这样的列表理解时,每次迭代都会创建新的列表 当您将一个列表相乘时,同一个引用会一次又一次地重复 当该引用指向一个列表时,它意味着同一个内部列表被一次又一次地复制 因此,当你乘法时,只有一个空列表,被一个列表引用两次,被一个列表引用两次,被另一个列表引用两次,这是最终的外部列表中的唯一项 当您使用列表理解时,每个引用都指向一个新的、不同的列表 因此,当您将包含对空列表的两个引用的列表的第一项指向另一个对象时,您可以在引用该列表的任何地方看到更改。因为它被一个本身被引用了两次的列表引用了两次,所以您可以在四个地方看到更改 如果要将值附加到最内部的列表中:
ll[0][0][0][0].append(1)
您将看到该值被引用了八次:
[[[[[1], [1]], [[1], [1]]], [[[1], [1]], [[1], [1]]]]]
因为所有的内部列表实际上都是相同的列表
ll的真正结构不是上面看起来的那样,而是:
[ ]
|
[ , ]
\ /
[ , ]
\ /
[ , ]
\ /
[]
Python显示对象的方式很容易引起误解。在Python中,出于效率原因,对象复制尽可能简单,这就是[[0]]*2生成最内层列表副本的原因 但是列表理解每次通过循环对表达式求值,这就是为什么[[0]for uin range2]会生成一个不同列表的列表。在本例中,表达式为[0],求值时每次都会创建一个列表的唯一实例 摘自文件: 理解包含一个表达式,后跟至少 一个用于子句,零个或多个用于或if子句。在这种情况下 新容器的元素是将由 将每个for或if子句视为一个块,从左侧嵌套 ,并对表达式求值以生成每个元素 到达最内层块的时间
我自己强调的重点是关键短语。在Python中,出于效率原因,对象复制尽可能简单,这就是[[0]]*2生成最里面列表副本的原因 但是列表理解每次通过循环对表达式求值,这就是为什么[[0]for uin range2]会生成一个不同列表的列表。在本例中,表达式为[0],求值时每次都会创建一个列表的唯一实例 摘自文件: 理解包含一个表达式,后跟至少 一个用于子句,零个或多个用于或if子句。在这种情况下 新容器的元素是将由 将每个for或if子句视为一个块,从左侧嵌套 ,并对表达式求值以生成每个元素 到达最内层块的时间 我自己对关键短语的强调
.…这很有趣,ll[0][0][0]。append1和lll[0][0][0]。append1的工作方式完全不同+我从没想过这个,很好。这肯定会有更令人惊讶的结果,thingking…@hhh核心是每个嵌套级别上只有一个列表,尽管随着您的深入,似乎会有更多列表,并且每个嵌套级别上只有两个对同一对象的引用。因此,当对嵌套列表使用乘法运算时,对任何内部列表执行任何操作都会得到奇怪的结果……这很有趣,ll[0][0][0]。append1和lll[0][0][0]。append1的工作方式完全不同+我从没想过这个,很好。这肯定会有更令人惊讶的结果,thingking…@hhh核心是每个嵌套级别上只有一个列表,尽管随着您的深入,似乎会有更多列表,并且每个嵌套级别上只有两个对同一对象的引用。正因为如此,当你在嵌套列表上使用乘法运算时,对任何内部列表做任何事情都会得到奇怪的结果……从来没有想过列表理解可以像这样使用。在没有列表理解或理解的情况下创建它是一件多么痛苦的事情啊?我确实在回答的顶部简要地解释了这一点,但是链接到文档的链接很好……从来没有想过列表理解可以像这样使用。在没有列表理解或理解的情况下创建它是一件多么痛苦的事情啊?我确实在回答的顶部简要地解释了这一点,但是与文档的链接很好。关于可变类型的问题已经被回答了很多次。请使用搜索bar@JBernardo:哪个问题?如果是这么简单的事情,请继续回答。我不能马上看出易变性和这个问题之间的联系。你将列表中的易变对象相乘,从而创建对同一对象的大量引用。起初,它们看起来像另一个版本,但当您添加一个元素时,它们都将具有该元素。这已经被回答了很多次了。@JBernardo:如果回答了那么多次,你能发布一个dup吗?如果这个问题真的有重复的话,我会很高兴地投票结束这个问题,而不是重复这个特定的问题,一些乱七八糟的问题相互之间有很多列表。只需搜索数百个关于列表乘法的问题中的一个,这个关于可变类型的问题已经被回答了很多次了。请使用搜索bar@JBernardo:哪个问题?如果是这么简单的事情,请继续回答。我不能马上看出易变性和这个问题之间的联系。你将列表中的易变对象相乘,从而创建对同一对象的大量引用。起初,它们看起来像另一个版本,但当您添加一个元素时,它们都将具有该元素。这已经被回答了很多次了。@JBernardo:如果回答了那么多次,你能发布一个dup吗?如果这个问题真的有重复的话,我会很高兴地投票结束这个问题,而不是重复这个特定的问题,一些乱七八糟的问题相互之间有很多列表。只需搜索数百个关于列表乘法的问题中的一个