何时创建引用,何时分配新内存块然后复制?

Tim*_*Tim 7 python

>>> d
{1: 1, 2: 2, 3: 3}
>>> lst = [d, d]
>>> c=lst[0]
>>> c[1]=5
>>> lst
[{1: 5, 2: 2, 3: 3}, {1: 5, 2: 2, 3: 3}]
Run Code Online (Sandbox Code Playgroud)

何时lst = [d, d],是lst[0]lsg[1]都引用内存块d,而不是创建两个内存块并分别复制d它们的内容?

什么时候c=lst[0],c只是引用占用的内存lst[0],而不是创建一个新的内存块并从中复制内容lst[0]

在Python中,何时创建引用以指向现有内存块,何时分配新内存块然后复制?

Python的这种语言特性与C不同.这种语言特征的名称是什么?

谢谢.

kin*_*all 7

所有变量(以及其他容器,如字典,列表和对象属性)都包含对对象的引用.在实例化对象时发生内存分配.简单赋值始终创建对现有对象的另一个引用.例如,如果您有:

a = [1, 2, 3]
b = a
Run Code Online (Sandbox Code Playgroud)

然后ba指向同一个对象,一个列表.您可以使用is运算符验证:

print(b is a)    # True
Run Code Online (Sandbox Code Playgroud)

如果更改a,则b也会更改,因为它们是同一对象的两个名称.

a.append(4)
print(b[3] == 4)     # True
print(b[3] is a[3])  # also True
Run Code Online (Sandbox Code Playgroud)

如果要创建副本,则必须明确地执行此操作.以下是一些执行此操作的方法:

  • 对于列表,请使用切片:b = a[:].
  • 对于许多类型,您可以使用类型名称来复制该类型的现有对象:b = list(a).创建自己的类时,如果需要复制功能,这是一个很好的方法.
  • copy模块具有可用于复制对象(浅或深)的方法.

对于不可变类型,例如字符串,数字和元组,永远不需要复制.您只能通过引用不同的值来"更改"这些类型的值.

描述这个的最好方法可能是"一切都是对象".在C中,像整数这样的"原始"类型与数组的处理方式不同.在Python中,它们不是:所有值都存储为对象的引用 - 甚至是整数.


Jam*_*lls 1

简而言之; Python 是按引用传递的。对象是在其构造时创建并分配内存的。引用对象不会分配更多内存,除非您创建新对象或扩展现有对象 ( list.append())

这篇文章Is Python pass-by-reference or pass-by-value很好地介绍了它。

作为旁注;如果您担心 Python 等管理编程语言中的内存分配方式,那么您可能使用了错误的语言和/或过早优化。此外,Python 中的内存管理方式是特定于实现的,因为 Python 有许多实现;CPython(您可能正在使用的);Jython、IronPython、PyPy、MicroPython 等