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

时间:2014-08-14 18:16:23

标签: python pass-by-reference

Python docs提到以下关于名称是对象的别名:

  

对象具有个性,多个名称(在多个范围内)可以绑定到同一个对象。这在其他语言中称为别名。乍一看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 :(得分:4)

b = a使名称ba引用完全相同的对象。所以是的,在Python中,a is b将始终为True。

答案 1 :(得分:3)

是的,它在the documentation中指定:

  

如果目标是标识符(名称):

     

如果名称未出现在当前代码块的全局语句中:名称绑定到当前本地名称空间中的对象。

     

否则:名称绑定到当前全局命名空间中的对象。

(在Python 3中还有一个与nonlocal相关的附加案例,但规则是相同的;唯一的区别是绑定发生在什么命名空间。)

注意,至关重要的是,这仅适用于指定裸名的情况。如果作业类似于a.foo = ba[blah] = b,则所有投注均已关闭,几乎任何事情都可能发生。

答案 2 :(得分:2)

>>> int
<class 'int'>

Python不像Java一样使用原始类型。如您所见,int是一个类。这个类的实例是 objects ,具有所有这些意义。碰巧这是一个内置类而不是某个.py文件中定义的类。

考虑Integer vs int的Java行为。

执行a = 1; b = a时,您将b设置为对a引用的同一对象的引用,因此它不会复制该值。

就特殊外壳而言,CPython确实能够制造出小型的外壳。整数(从-5到255)变成单例,因此不必重新创建它们,但这是一个实现细节。

答案 3 :(得分:0)

Python中的所有变量和表达式都是引用(在语义上等同于指向对象的指针)。如果您熟悉C ++,则如下所示:

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

将一个变量分配给另一个变量将复制该值,即指针。在赋值之后,两个指针将始终指向同一个对象。