Python中is not比较行为疑问:同名属性为何ID不同?
关于防御性复制中属性身份比较与ID变化的问题解答
为什么a.lst_different_name is not a.lst_different_name返回True?
核心原因是这个属性的访问器(getter)每次调用都会返回一个全新的对象副本——这正是防御性复制的设计目的:防止外部代码直接修改类内部的可变对象(比如列表)。
is运算符比较的是两个对象的内存身份(即ID),而非值是否相等。如果你的类定义类似下面这样:
class SomeClass: def __init__(self): self._internal_list = [1, 2, 3] @property def lst_different_name(self): # 每次访问都返回内部列表的新副本 return self._internal_list.copy()
那么每次调用a.lst_different_name时,都会执行copy()生成一个新列表。两次调用得到的是两个完全独立的对象,内存地址自然不同,因此a.lst_different_name is a.lst_different_name会返回False,对应的is not就是True。
为什么同一属性的ID会有时相同有时不同?
这和Python的垃圾回收机制以及内存复用规则有关:
- 当你调用
id(a.lst_different_name)时,生成的临时列表对象没有被任何变量持有引用,Python的垃圾回收器会快速回收这块内存空间。 - 下一次调用
id(a.lst_different_name)时,新生成的列表对象可能会复用之前被回收的内存地址,此时两次ID就会相同。 - 如果在两次调用之间有其他操作创建了新对象、占用了那块内存,新生成的列表就会使用新的内存地址,ID也就随之不同。
直观示例:
a = SomeClass() # 第一次调用,生成临时列表,ID为X print(id(a.lst_different_name)) # 临时列表已被回收,新列表复用X地址 print(id(a.lst_different_name)) # 创建新对象占用内存 temp = [4, 5, 6] # 新列表只能使用新地址,ID变为Y print(id(a.lst_different_name))
内容的提问来源于stack exchange,提问作者KishuInu
相关产品推荐
相关产品推荐

