【问题标题】:a == b is false, but id(a) == id(b) is true?a == b 是假的,但 id(a) == id(b) 是真的?
【发布时间】:2011-01-20 02:50:54
【问题描述】:

遇到以下情况:

>>> class A:
...     def __str__(self):
...             return "some A()"
... 
>>> class B(A):
...     def __str__(self):
...             return "some B()"
... 
>>> print A()
some A()
>>> print B()
some B()
>>> A.__str__ == B.__str__
False # seems reasonable, since each method is an object
>>> id(A.__str__)==id(B.__str__)
True # what?!

这是怎么回事?

【问题讨论】:

    标签: python object methods overriding


    【解决方案1】:

    以下作品:

    >>> id(A.__str__.im_func) == id(A.__str__.im_func)
    True
    >>> id(B.__str__.im_func) == id(A.__str__.im_func)
    False
    

    【讨论】:

      【解决方案2】:

      在评估字符串id(A.__str__) == id(B.__str__) 时,会创建A.__str__,获取其ID,然后进行垃圾收集。然后B.__str__ 被创建,并且恰好到达与A.__str__ 之前完全相同的地址,因此它(在CPython 中)获得了相同的ID。

      尝试将A.__str__B.__str__ 分配给临时变量,你会看到不同的东西:

      >>> f = A.__str__
      >>> g = B.__str__
      >>> id(f) == id(g)
      False
      

      对于这种现象的一个更简单的例子,试试:

      >>> id(float('3.0')) == id(float('4.0'))
      True
      

      【讨论】:

      • 但是,为什么 >>> f = A.__str__ >>> id(f) == id(A.__str__) False
      • @jldupont:Python 在运行时创建未绑定的方法A.__str__B.__str__users.rcn.com/python/download/Descriptor.htm 是一个很好的底层机制参考。
      • hmmm...那些垃圾能这么快被收集起来吗?我仍然不相信这种解释。
      • @jldupont,CPython 被引用,所以大多数东西都会立即被垃圾收集。这是对所发生情况的正确解释。
      • @jldupont:测试理论很容易!尝试创建 float 的子类 myfloat,并覆盖 __new____del__,以便它们正确记录调用。现在观察评估id(myfloat(1.0)) == id(myfloat(2.0)) 时的操作顺序。 (不过,对__del__ 的调用不一定直接对应于垃圾回收。)
      【解决方案3】:

      对于我们这些被你的标题所吸引的人,确定一个方法是否被覆盖:

      class A:
          def __str__(self):
              return "some A()"
      
          def strWasOverridden(self):
              return A.__str__ != self.__str__
      

      【讨论】:

      • 其实,没有。这总是正确的,因为方法上的实例永远不会等于类上的方法。
      猜你喜欢
      • 1970-01-01
      • 2021-08-26
      • 2014-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-23
      • 2019-03-22
      相关资源
      最近更新 更多