python 中is 相当于比较两个对象的id,这个怎么解释

def zhuangshi(cls):
    def inner():
        pass

    return inner


class A:
    pass


print(zhuangshi(A) is zhuangshi(A))
print(id(zhuangshi(A)) == id(zhuangshi(A)))


print(id(zhuangshi(A)))
print(id(zhuangshi(A)))

控制台输出结果如下:
False
True
31665416
31665416
惊呆! 为什么两个对象的内存地址都一样,为何 is 运行结果是false?

阅读 4.7k
3 个回答

楼上都没答到点子上,这个现象与 gc 有关,属于未定义行为。

事情是这样的:

执行 zhuangshi(A) is zhuangshi(A) 时,表达式从左到右求值,先运算第一个 zhuangshi(A),并将返回值存在一个临时变量,假设为 tmp1;再运算第二个,返回值存在 tmp2。此时内存中实际上有两个 inner 的副本,各被一个引用 tmp1 tmp2 指向,它们地址当然是不同的,因此 is 的结果为 False

再看第二个例子:

执行 id(zhuangshi(A)) == id(zhuangshi(A)) 时,表达式从左到右、从内向外求值。先运算 zhuangshi(A),再将返回值传给 id,最后我们得到一个整数。注意此处与上一个例子不同,此时已经没有任何指向 inner 的引用,因此垃圾回收器可以将其回收。待对第二个表达式求值时,有一定的概率 Python 会在先前的 inner 对象的地址上创建新的 inner 对象,从而导致两个地址相同。

总而言之,看上去它们是同一个对象,实际上它们是先后被创建在同一个地址上的两个不同对象,因此有相同的 id。

print(zhuangshi(A) is zhuangshi(A))等价于
a, b = zhuangshi(A), zhuangshi(A)
print(a is b)  #False
print(id(a) == id(b)) #False

print(id(zhuangshi(A)) == id(zhuangshi(A)))等价于
a, b = id(zhuangshi(A)), id(zhuangshi(A))
print(a == b)    #True 两次id相同所以true

== 是比较两个对象的值是否相等。
is 除了比较对象的值是否相等,还涉及到比较两个对象的内存地址是否相等。

>>> type(zhuangshi(A))
<class 'function'>
>>> zhuangshi(A)
<function zhuangshi.<locals>.inner at 0x7f7823a98b70> # 注意查看最后的内存地址
>>> zhuangshi(A)
<function zhuangshi.<locals>.inner at 0x7f78208ac7b8> # 注意查看最后的内存地址
>>> c, d = A, A
>>> type(c)
<class 'type'>
>>> type(d)
<class 'type'>
>>> c
<class '__main__.A'>
>>> d
<class '__main__.A'>
>>>
>>> c is d
True
>>>

综上比较,分明是 zhuangshi 这个类定义的是 返回一个 inner 对象,每次调用都会执行一次 inner 函数,所以调用的内存地址是不一样的。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏