【问题标题】:Why is my object properly removed from a list when __eq__ isn't being called?当 __eq__ 没有被调用时,为什么我的对象会从列表中正确删除?
【发布时间】:2014-12-18 01:15:57
【问题描述】:

我有以下代码,这让我摸不着头脑 -

class Element:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return self.name

def eq(self, other):
    print('comparing {} to {} ({})'.format(self.name, 
        other.name, 
        self.name == other.name))

    return self.name == other.name

Element.__eq__ = eq
elements = [
    Element('a'), 
    Element('b'), 
    Element('c'), 
    Element('d')    
]

print('before {}'.format(elements))
elements.remove(elements[3])
print('after {}'.format(elements))

产生以下输出 -

before [a, b, c, d]
comparing a to d (False)
comparing b to d (False)
comparing c to d (False)
after [a, b, c]

为什么eq() 不输出comparing d to d (True)

我使用猴子修补 __eq__ 而不是简单地在我的 Element 类中实现它的原因是因为我在使用我正在使用的库之一实现它之前测试猴子修补的工作原理。

【问题讨论】:

    标签: python list python-3.x


    【解决方案1】:

    第四个元素是与代码传递的对象完全相同的对象 (elements[3])。

    换句话说,

    >>> elements[3] is elements[3]
    True
    >>> elements[3] == elements[3]
    True
    

    因此,无需检查相等性,因为它们(?)是相同的。

    如果它们不相同,则会进行相等检查。例如,如果代码传递另一个具有相同值的对象,则将调用__eq__

    elements.remove(Element('d'))
    

    【讨论】:

      【解决方案2】:

      Python 的 list.remove() 方法首先检查两个对象是否相同,否则在这种情况下会退回到常规比较方法,如 __eq__。因此,在这种情况下,由于两个对象相同,因此将其从列表中删除。

      listremove(PyListObject *self, PyObject *v)
      {
          Py_ssize_t i;
      
          for (i = 0; i < Py_SIZE(self); i++) {
              int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);
              ...
      

      这里PyObject_RichCompareBool(PyObject *o1, PyObject *o2, int opid) 用于比较,来自其文档:

      如果o1o2 是同一个对象,PyObject_RichCompareBool() 将 对于Py_EQ,总是返回1,对于Py_NE,总是返回0

      【讨论】:

      • 感谢发布 Python 实际实现源代码的 sn-p。我真的应该学会在那里寻找我的答案。
      猜你喜欢
      • 2022-06-27
      • 2018-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多