Python变量没有类型,它们只是对象的引用。无论引用什么,引用的大小都相同。在Python的C实现中,它是一个指针,并且有一种类型,它是指向Python对象的指针:PyObject *
。无论对象的类别如何,指针的类型都是相同的。另一方面,对象知道它们属于哪个类。
有人认为Python没有变量,只有名称,尽管这对大多数人来说都太过分了。
在CPython实现中,引用具有id(标识符),它实际上是一个虚拟地址。这个地址的细节和值不值得追究-它可以(并且可能会)在版本之间改变,而且不应该被用于除了唯一标识对象的编号之外的任何事情。然而,它可以提供有趣的指针(请原谅双关语)以了解正在发生什么:
>>> x = 42
>>> y = x
>>> id(x)
4297539264
>>> id(y)
4297539264
请注意,
x
和
y
的id(地址)是相同的 - 它们引用了同一个对象,一个值为42的
int
。那么,当我们改变
x
时,
y
也会改变吗?
>>> x = "hello"
>>> id(x)
4324832176
>>> id(y)
4297539264
感谢不用担心。现在
x
只是一个类为
str
的新对象,其值为“Hello”。
当我们:
>>> id(y)
4297539264
>>> y = 37
>>> id(y)
4297539104
y
的id已经改变了!这是因为它现在引用的是一个不同的对象。
int
是不可变的,所以赋值
y = 37
没有改变原始对象(42),它只是创建了一个新的对象。值为42的对象的引用计数被减少,现在可以(理论上)被删除。实际上,出于效率的原因,它可能会保留在内存中,但这是一些具体实现细节。
然而,让我们尝试对列表进行类似操作:
>>> a = [1,2,3,4]
>>> b = a
>>> id(a)
4324804808
>>> id(b)
4324804808
>>> a[0] = 99
>>> b
[99, 2, 3, 4]
所以改变列表a
已经改变了b
!这是因为Python中的列表(与R不同)是可变的,因此它们可以原地更改。赋值b = a
仅复制了引用,从而节省了内存(实际上没有复制任何数据)。字典是另一个具有此类行为的对象。请参见标准库中的copy。