"a == b" 与"id(a) == id(b)"的本质区别

2021-01-22 15:19:15 +08:00
 hanssx

群友 Jin 发出一段代码,

class Person:
    def say(self):
        pass
    
p1 = Person()
p2 = Person()

print(p1.say, id(p1.say))
print(p2.say, id(p2.say))
print(p1.say == p2.say)  # False
print(p1.say is p2.say)  # False
print(p1.say is p1.say)  # False
print(id(p1.say) == id(p2.say))  # True

输出:

<bound method Person.say of <__main__.Person object at 0x7f6739300898>> 140081602502024
<bound method Person.say of <__main__.Person object at 0x7f67393005c0>> 140081602502024
False
False
False
True

python 官网上对 id 的解释

id(object)

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

CPython implementation detail: This is the address of the object in memory.

Raises an auditing event builtins.id with argument id.

我理解就是返回内存地址

StackOverFlow 上对 is 的解释: https://stackoverflow.com/questions/132988/is-there-a-difference-between-and-is 也就是引用比较,不就是比较内存地址?

群友 Sweeneys 发了一篇 StackOverFlo 的类似问题帖子: https://stackoverflow.com/questions/2906177/what-is-the-difference-between-a-is-b-and-ida-idb-in-python

回答中有一段话

b.test happens to have the same id as the bound method you had before and it's allowed to because no other objects have the same id now.

这意思就是说 a.test 被 gc 之后恰好释放的内存,正好被 b.test 所使用?所以才导致 True ?

于是群友 Jin 改成了如下代码,依然输出同样的结果,

import gc
gc.disable()

class Person:
    def say(self):
        pass
    
p1 = Person()
p2 = Person()

print(p1.say, id(p1.say))
print(p2.say, id(p2.say))
print(p1.say == p2.say)  # False
print(p1.say is p2.say)  # False
print(p1.say is p1.say)  # False
print(id(p1.say) == id(p2.say))  # True

我尝试改成这样,依然输出同样的结果。

class Person:
    def say(self):
        pass
    
p1 = Person()
p2 = Person()

print(p1.say, id(p1.say))
print(p2.say, id(p2.say))
print(p1.say == p2.say)  # False
print(p1.say is p2.say)  # False
print(p1.say is p1.say)  # False
p1_ref = p1.say
p2_ref = p2.say
print(id(p1.say) == id(p2.say))  # True

话说,python 中一个类中的 self 方法本身应该只在内存中占一个位置吧?然后调用的时候把对象地址 self 传进来调用,我记得 C++是这样的,虽然 Python 底层是 c 的 struct 实现的,但是也不至于这么弱智,同个类的不同对象的 self 方法占用多块内存吧?

2315 次点击
所在节点    Python
14 条回复
hanssx
2021-01-22 15:22:48 +08:00
改成群友确实就是 False 了,为啥我上面最后写的那段不行?
```python
class Person:
def say(self):
pass

p1 = Person()
p2 = Person()

print(p1.say, id(p1.say))
print(p2.say, id(p2.say))
print(p1.say == p2.say) # False
print(p1.say is p2.say) # False
print(p1.say is p1.say) # False
p1_ref = p1.say
p2_ref = p2.say
print(id(p1_ref) == id(p2_ref)) # False
```
AoEiuV020
2021-01-22 15:28:14 +08:00
太复杂,没看出来每个都改了啥,
forbxy
2021-01-22 15:33:11 +08:00
class Dog:
def say(self):
pass

d = Dog()

id(d.say) == id(p2.say) # Ture
zk8802
2021-01-22 15:33:56 +08:00
func.__eq__() 可能比较特殊。我猜它会检查 self 是否一致。
todd7zhang
2021-01-22 15:34:23 +08:00
不知道,盲猜 id 相等是因为
p1.say.im_func is p2.say.im_func
python3 就是 p1.say.__func__ is p2.say.__func__
AlohaV2
2021-01-22 15:36:54 +08:00
AoEiuV020
2021-01-22 15:39:05 +08:00
我刚知道,这个 id 居然是每次都不一样的,那就不可能是返回内存地址啥的了,具体还是要看这个方法底层实现,
hanssx
2021-01-22 15:40:50 +08:00
@AoEiuV020 是不是每次分配的内存地址不一样?
AlohaV2
2021-01-22 15:42:44 +08:00
@AoEiuV020 是内存地址相关的一个东西
调用 bound method 的话,id(p1.say)其实是新建了一个 bound method, 里面绑定了 Person.say 和 p1 这俩东西。
所以类似的操作还有
```
class WhatEver:
def say(self):
pass
def run(self):
pass

foo = WhatEver()
print(id(foo.say) == id(foo.run))
```
todd7zhang
2021-01-22 15:49:11 +08:00
学到了
zhanglintc
2021-01-22 16:03:34 +08:00
为啥这个是 False 来着:
print(p1.say is p1.say) # False
hanssx
2021-01-22 16:17:20 +08:00
更新群友 Sweeneys 回复:

对,我 jio 得大家不能 get 的点在这,即每次 instance.method_name 都会创建一个新的方法对象( Method Object )。还有一点就是生命周期的问题,如果两个对象的生命周期不重叠,那么 id(object)得到的值可能会一样。
milkpuff
2021-01-22 16:54:08 +08:00
https://github.com/satwikkansal/wtfpython#-strings-can-be-tricky-sometimes
github 上的一个专门总结 python 奇特特性的仓库,叫做 wtfpython,有 23k star
hanssx
2021-01-22 16:57:54 +08:00
@milkpuff 有点意思

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/747425

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX