在Python中扩展列表列表?

Pau*_* D. 10 python list extend

我可能会遗漏一些关于list扩展的预期行为,但为什么会发生以下情况呢?

x = [[],[]]
y = [[]] * 2

print x       # [[],[]]
print y       # [[],[]]
print x == y  # True

x[0].extend([1])
y[0].extend([1])

print x    # [[1],[]], which is what I'd expect
print y    # [[1],[1]], wtf?
Run Code Online (Sandbox Code Playgroud)

我猜这个*操作员在这里做了一些意想不到的事情,虽然我不确定是什么.似乎正在发生的事情正在使得原始的x和y(在调用extend之前)实际上并不相等,即使==运算符和repr两者都会使它看起来好像它们是相同的.

我只碰到这个来到这里是因为我想预填充在运行时确定的大小的空列表的列表,然后意识到,这是不工作我想象的方式.我可以找到一个更好的方法来做同样的事情,但现在我很好奇为什么这不起作用.这是Python 2.5.2 BTW - 我没有安装更新的版本,所以如果这是一个错误,我不确定它是否已经修复.

Cra*_*ast 17

在这种情况下[something] * 2,python只是制作一个引用副本.因此,如果封闭类型是可变的,则更改它们将反映在引用项目的任何位置.

在您的示例中,y[0]y[1]指向相同的封闭列表对象.您可以通过执行y[0] is y[1]或交替验证此操作id(y[0]) == id(y[1]).

但是,您可以重新分配列表元素,因此如果您已完成:

y[0] = [1]
Run Code Online (Sandbox Code Playgroud)

您将第一个元素重新绑定到包含元素"1"的新列表,您将获得预期的结果.

python存储引用中的容器,并且在大多数序列容器中可以多次引用同一项.列表实际上可以将自身引用为元素,尽管它的用处有限.

如果您将包含不可变类型的列表相乘,则不会出现此问题:

a = [0, 1] * 2
Run Code Online (Sandbox Code Playgroud)

上面的内容将为您提供列表[0, 1, 0, 1],实际上两个实例都1指向同一个对象,但由于它们是不可变的,因此您无法更改int包含"1" 的对象的值,只能重新分配元素.

这样做:a[1] = 5 会导致a显示为[0, 5, 0, 1].