"a == b" 与"id(a) == id(b)"的本质区别 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
hanssx

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

  •  3
     
  •   hanssx Jan 22, 2021 2822 views
    This topic created in 1923 days ago, the information mentioned may be changed or developed.

    群友 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 方法占用多块内存吧?

    14 replies    2021-01-22 16:57:54 +08:00
    hanssx
        1
    hanssx  
    OP
       Jan 22, 2021
    改成群友确实就是 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
    printp1.say is p1.say) # False
    p1_ref = p1.say
    p2_ref = p2.say
    print(id(p1_ref) == id(p2_ref)) # False
    ```
    AoEiuV020
        2
    AoEiuV020  
       Jan 22, 2021
    太复杂,没看出来每个都改了啥,
    forbxy
        3
    forbxy  
       Jan 22, 2021
    class Dog:
    def say(self):
    pass

    d = Dog()

    id(d.say) == id(p2.say) # Ture
    zk8802
        4
    zk8802  
       Jan 22, 2021 via iPhone
    func.__eq__() 可能比较特殊。我猜它会检查 self 是否一致。
    todd7zhang
        5
    todd7zhang  
       Jan 22, 2021
    不知道,盲猜 id 相等是因为
    p1.say.im_func is p2.say.im_func
    python3 就是 p1.say.__func__ is p2.say.__func__
    AoEiuV020
        7
    AoEiuV020  
       Jan 22, 2021
    我刚知道,这个 id 居然是每次都不一样的,那就不可能是返回内存地址啥的了,具体还是要看这个方法底层实现,
    hanssx
        8
    hanssx  
    OP
       Jan 22, 2021
    @AoEiuV020 是不是每次分配的内存地址不一样?
    AlohaV2
        9
    AlohaV2  
       Jan 22, 2021
    @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
        10
    todd7zhang  
       Jan 22, 2021
    学到了
    zhanglintc
        11
    zhanglintc  
       Jan 22, 2021
    为啥这个是 False 来着:
    print(p1.say is p1.say) # False
    hanssx
        12
    hanssx  
    OP
       Jan 22, 2021
    更新群友 Sweeneys 回复:

    对,我 jio 得大家不能 get 的点在这,即每次 instance.method_name 都会创建一个新的方法对象( Method Object )。还有一点就是生命周期的问题,如果两个对象的生命周期不重叠,那么 id(object)得到的值可能会一样。
    milkpuff
        13
    milkpuff  
       Jan 22, 2021   4
    https://github.com/satwikkansal/wtfpython#-strings-can-be-tricky-sometimes
    github 上的一个专门总结 python 奇特特性的仓库,叫做 wtfpython,有 23k star
    hanssx
        14
    hanssx  
    OP
       Jan 22, 2021
    @milkpuff 有点意思
    About     Help     Advertise     Blog     API     FAQ     Solana     1256 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 42ms UTC 23:38 PVG 07:38 LAX 16:38 JFK 19:38
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86