共享引用——共享引用和相等

未匹配的标注

为了充分披露信息,应该指出:对某些类型,本章之前描述的垃圾回收行为可能是概念化的而非很精确的。考虑下面这些语句:

>>> x = 42
>>> x = 'shrubbery' # 现在回收42了?

前面提到:因为Python缓存和重用了小整数和小字符串,这里的对象42很可能不被真的回收;相反,它将很可能保留在一个系统表中,在代码下次产生42时被重用。然而,大多数对象,当它们不被引用时就被立即回收;对于那些不被立即回收的,缓存机制也和代码无关。

比如,因为Python的引用模型,在Python程序中有两种不同方法来检查相等。创建一个共享引用来展示:

>>> L = [1, 2, 3]
>>> M = L # M 和 L 引用同一对象
>>> L == M # 值相同
True
>>> L is M # 对象相同
True

这里第一个技术,==操作符,测试两个被引用对象是否有相同值;这是Python中几乎总是用来进行相等检查的方法。第二个方法,is操作符,测试对象相等——如果两个名称指向相同的对象,它才返回true,所以它是一个强很多的相等测试形式,在大多数程序中很少使用。

真的,is简单地比较实现引用的指针,而且如果需要,它作为代码中探测共享引用的一种方式。如果名称指向等价但不同的对象,它返回False,和运行两个不同字面量表达式时的情况一样:

>>> L = [1, 2, 3]
>>> M = [1, 2, 3] # M 和 L 引用不同对象
>>> L == M # 值相同
True
>>> L is M # 对象不同
False

现在,观察当对小数字执行同样操作时会发生什么:

>>> X = 42
>>> Y = 42 # 应该是两个不同对象
>>> X == Y
True
>>> X is Y # 不管怎样是同样的对象: 缓存起作用了!
True

在这个交互中,X 和 Y 应该 == (值相等),但不是 is (同样的对象)因为运行了两个字面量表达式(42)。然而, 因为小数字和字符串会被缓存和重用,is告诉我们它们引用了同样的单个对象。

事实上,如果真的想了解原理,可以总是问Python一个对象有多少个引用:在标准sys模块中的getrefcount函数返回了对象的引用数。比如,当在IDLE GUI中询问整数对象1时,它报告了这同一个对象的647个重用(大多数是在IDLE的系统代码中,而不是在我的代码中,然而在IDLE之外这个操作也返回了173,所以Python一定也在囤积1):

>>> import sys
>>> sys.getrefcount(1) # 这个共享内存片段的647个指针
647

这种对象缓存和重用和代码无关(除非运行is检查!)。因为不能就地修改不可变的数字或字符串,对同一个对象有多少引用是没有关系的——每个引用将总是看到同样的,不变的值。然而,这个行为反应了Python为执行速度而优化其模型的多种方式之一。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 查看所有版本


暂无话题~