3

所以我正在用 Python 编写一个游戏,而我试图解决的一个问题需要我将 2D 列表(即列表列表)转换为 1D 列表。我已经看到了几种方法来做到这一点,但我不知道它们中的任何一个是否创建了其中包含的任何对象的副本,或者只是新的引用。老实说,Python 标准库让我感到困惑,因为对象/序列是被复制还是只是被引用填充并不总是很明显。

这些是关于我的特殊情况的假设;

  • 我们可以假设我的二维列表(如果表示为矩阵)是完美的矩形。
  • 如果我能有一个上述假设不成立的解决方案,那就太好了,但目前不需要。
  • 无需担心 3D+ 列表。

谢谢!

4

4 回答 4

7

虽然我不能代表您可能看到的所有方式,但由于 Python 的对象语义,通常不会制作副本。

>>> a = [[1,2.3,'3', object()], [None, [2,3], 4j]]
>>> b = [v for row in a for v in row]
>>> a
[[1, 2.3, '3', <object object at 0x1002af090>], [None, [2, 3], 4j]]
>>> b
[1, 2.3, '3', <object object at 0x1002af090>, None, [2, 3], 4j]
>>> [id(obj) for row in a for obj in row]
[4298185464, 4298195480, 4299558664, 4297781392, 4296523616, 4299692656, 4297773296]
>>> [id(obj) for obj in b]
[4298185464, 4298195480, 4299558664, 4297781392, 4296523616, 4299692656, 4297773296]

v并不意味着“某个新对象等于v”,它只是意味着v对象本身。

于 2012-08-26T19:22:46.630 回答
1

关于您关于副本/引用的问题,Python 以不同的方式处理可变/不可变变量:对于不可变变量(int、float、string、tuples 等),您将获得副本,对于可变(其他所有)-“引用”。

关于 python 列表的扁平化:查看itertools模块。你可以这样做:

>>> from itertools import chain
>>> chain(*[[1,2,3], [4,5,6], [7,8,9]])
<itertools.chain object at 0x104ff5110>
>>> list(_)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
于 2012-08-26T19:24:30.700 回答
1

可能python文档中的这篇文章可以帮助您了解python的作用:

没有人“拥有”一个对象;但是,您可以拥有对对象的引用。对象的引用计数现在定义为拥有的对它的引用数。当不再需要引用时,引用的所有者负责调用 Py_DECREF()。引用的所有权可以转让。有三种方法可以处理拥有的引用:传递、存储或调用 Py_DECREF()。忘记处理拥有的引用会导致内存泄漏。

现在,这指的是在 C 代码中使用 python 对象,但是,由于解释器正是这样做的,因此您可以了解对象和引用在 python 中是如何管理的。

“没有人拥有一个对象”,所以当你把一个项目放在一个列表中时,这个列表不会复制这个项目,它只是拥有一个引用。实际上,它会复制一个指针并增加引用计数(并且可能还会减少被替换的其他对象)。

从python的角度来看,您不能访问对象,而只能引用对象。您可以放入变量中的任何内容实际上都是对对象的引用。因此[1,2].append(3)不会复制 3,而只是引用。

如果你想复制一个对象,那么你应该使用copy模块 或者,对于某些类型,使用对象作为参数调用类(例如int(1234)创建“1234”的副本,即使python将整数存储在一个小数组中 - 5 到 256 和小字符串,这样做int(42)不会复制“42”)

于 2012-08-26T19:42:29.100 回答
0

您可以执行以下操作:

arr2d = [[1,2,3],[4,5,6],[7,8,9]]
arr1d = []
for x in arr2d:
   arr1d.extend(x)

这不会创建副本,更改一维数组,它不会反映。对于未来的参考,如果你想确保它不被复制,导入copy模块,并使用copy.deepcopy(array)而不是 just array,你会很安全。

于 2012-08-26T19:29:22.627 回答