Python中的别名是否保证引用同一对象?

3 投票
4 回答
1605 浏览
提问于 2025-04-18 17:19

Python文档中提到,名字其实是对象的别名:

对象是独一无二的,多个名字(在不同的作用域中)可以指向同一个对象。这在其他编程语言中被称为别名。在初学Python时,这一点可能不太容易理解,尤其是在处理不可变的基本类型(比如数字、字符串、元组)时,可以暂时忽略这个概念。不过,当涉及到可变对象(比如列表、字典和大多数其他类型)时,别名可能会对Python代码的含义产生意想不到的影响。通常情况下,这种特性对程序是有利的,因为别名在某些方面表现得像指针。例如,传递一个对象是很便宜的,因为实现上只传递了一个指针;如果一个函数修改了作为参数传入的对象,调用者会看到这个变化——这就省去了像Pascal那样需要两种不同参数传递机制的麻烦。

在一些其他高级语言中,基本类型通常会被特殊处理,为了性能原因,它们会被复制而不是引用。例如,在Java中:

int a = 20000;
int b = a;

上面的代码会复制值20000,而不是指向值20000的指针。在这种情况下,ab可能会占用内存中的不同位置。由于在基本类型上,==被特殊处理用来测试相等性而不是身份,所以我认为在正常代码中无法直接观察到这种行为。

另一方面,对Python 3中的intstr等类型进行有限测试显示,确实是复制了指针而不是值,这在文档中有说明:

a = 20000
b = a
a is b # True

这是一个非常好的特性,使得语言非常一致,因为没有对基本类型的特殊处理。所有的赋值都是将一个名字重新指向另一个对象。不过,出于性能原因,Python解释器是否可能会对像int这样的类型进行特殊处理呢?

因此,我的问题是:这种基本类型的特性是否有保证?换句话说,在b = a之后,不管使用哪个Python解释器,比较a is b是否总是会返回True

4 个回答

0

在Python中,所有的变量和表达式其实都是指向对象的引用,简单来说就像是指针。如果你对C++有点了解,可以想象成下面这样:

object *a = new object(20000);
object *b = a;
a == b // true

当你把一个变量赋值给另一个变量时,实际上是复制了一个指向同一个对象的指针。也就是说,赋值之后这两个指针会一直指向同一个对象。

3
>>> int
<class 'int'>

Python 和 Java 在处理基本数据类型上有些不同。你可以看到,int 实际上是一个类。这个类的实例就是我们所说的 对象,这意味着它有很多特性。值得注意的是,这个类是内置的,而不是在某个 .py 文件中定义的。

可以想象一下 Java 中 Integerint 的区别。

当你写 a = 1; b = a 时,其实是把 b 设置为指向和 a 一样的对象,这样就不会复制值。

至于特殊情况,CPython 会把“较小”的整数(从 -5 到 255)处理成单例,这样就不需要重新创建它们,但这只是实现上的一个细节。

4

b = a 这行代码让 ba 指向同一个对象。也就是说,ab 其实是同一个东西。所以在 Python 中,a is b 这个判断永远会返回 True。

3

是的,这在文档中有说明:

如果目标是一个标识符(名字):

如果这个名字在当前代码块中没有出现在全局声明里:这个名字就会和当前本地命名空间中的对象绑定。

否则:这个名字就会和当前全局命名空间中的对象绑定。

(在Python 3中,还有一个和nonlocal相关的额外情况,但规则是一样的;唯一的区别是绑定发生在哪个命名空间中。)

需要特别注意的是,这个规则只适用于给一个裸名字赋值。如果赋值是像a.foo = b或者a[blah] = b这样的情况,那就没什么规律可言了,几乎可以发生任何事情。

撰写回答