【问题标题】:Most efficient way of comparing the contents of two class instances in python在python中比较两个类实例的内容的最有效方法
【发布时间】:2013-12-10 15:29:27
【问题描述】:

我正在寻找比较两个类实例内容的最有效方法。我有一个包含这些类实例的列表,在附加到列表之前,我想确定它们的属性值是否相同。这对大多数人来说似乎微不足道,但在仔细阅读这些论坛之后,我无法具体说明我正在尝试做什么。另请注意,我没有编程背景。

这是我目前所拥有的:

class BaseObject(object):
    def __init__(self, name=''):
        self._name = name


    def __repr__(self):
        return '<{0}: \'{1}\'>'.format(self.__class__.__name__, self.name)

    def _compare(self, other, *attributes):
        count = 0
        if isinstance(other, self.__class__):
            if len(attributes):
                for attrib in attributes:
                    if (attrib in self.__dict__.keys()) and (attrib in other.__dict__.keys()):
                        if self.__dict__[attrib] == other.__dict__[attrib]:
                            count += 1
                return (count == len(attributes))
            else:
                for attrib in self.__dict__.keys():
                    if (attrib in self.__dict__.keys()) and (attrib in other.__dict__.keys()):
                        if self.__dict__[attrib] == other.__dict__[attrib]:
                            count += 1
                return (count == len(self.__dict__.keys()))
    def _copy(self):
        return (copy.deepcopy(self))

在添加到我的列表之前,我会执行以下操作:

found = False
for instance in myList:
    if instance._compare(newInstance): 
        found = True
        Break

if not found: myList.append(newInstance)

但是我不清楚这是否是比较同一类实例内容的最有效的方式还是 python-ic 方式。

【问题讨论】:

  • 你应该把它们放在一个集合中并在你的类中实现__hash____eq__

标签: python object instance


【解决方案1】:

改为实现__eq__ special method

def __eq__(self, other, *attributes):
    if not isinstance(other, type(self)):
        return NotImplemented

    if attributes:
        d = float('NaN')  # default that won't compare equal, even with itself
        return all(self.__dict__.get(a, d) == other.__dict__.get(a, d) for a in attributes)

    return self.__dict__ == other.__dict__

现在你可以使用:

if newInstance in myList:

Python 会自动使用__eq__ 特殊方法来测试是否相等。

在我的版本中,我保留了传递一组有限属性的能力:

instance1.__eq__(instance2, 'attribute1', 'attribute2')

但使用all() 确保我们只测试所需的数量。

请注意,我们返回NotImplemented,这是一个特殊的单例对象,表示不支持比较; Python 会询问 other 对象是否支持相等性测试。

【讨论】:

    【解决方案2】:

    你可以为你的班级实现comparison magic method__eq__(self, other),然后简单地做

    if instance == newInstance:
    

    由于您显然不知道您的实例将具有哪些属性,您可以这样做:

    def __eq__(self, other):
        return isinstance(other, type(self)) and self.__dict__ == other.__dict__
    

    【讨论】:

      【解决方案3】:

      您的方法有一个主要缺陷:如果您的引用循环中的类都派生自 BaseObject,那么您的比较将永远不会完成并因堆栈溢出而死。

      此外,不同类但具有相同属性值的两个对象比较为相等。简单的例子:没有属性的BaseObject 的任何实例将与没有属性的BaseObject 子类的任何实例进行比较(因为如果issubclass(C, B)aC 的实例,那么isinstance(a, B)返回True)。

      最后,与其编写自定义的_compare 方法,不如将其称为__eq__ 并获得现在能够使用== 运算符的所有好处(包括在列表中包含测试、容器比较等) .

      不过,出于个人喜好,我会远离那种自动生成的比较,而是明确比较显式属性。

      【讨论】:

      • 不同类但具有相同属性值的两个对象比较为相等:这绝对是,显然不正确。不同类的实例永远不相等。即使是 OP 版本也先进行了isinstance() 测试,而object() 将无法通过该测试。
      • 哎呀,我的错,我错过了isinstance 检查。在喝咖啡之前不应该评论这些事情。但是,不同类的实例返回 None 而不是 0,这可能是也可能不是你想要的。
      • 您真正想要的是在这些情况下返回NotImplemented,以便Python 将查找second.__eq__(first)
      • 等等,实际上,不同类的实例可以比较相等,当且仅当一个是另一个的子类(并且都派生自BaseObject)。
      • 是的,这可能是有意的,只要它们具有相同的属性。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-21
      • 1970-01-01
      • 1970-01-01
      • 2023-02-06
      • 1970-01-01
      • 2014-05-15
      相关资源
      最近更新 更多