【问题标题】:Is there a way to check if two object contain the same values in each of their variables in python?有没有办法检查两个对象在 python 中的每个变量中是否包含相同的值?
【发布时间】:2011-06-21 10:27:59
【问题描述】:

如何检查是否存在两个实例

class FooBar(object):
    __init__(self, param):
        self.param = param
        self.param_2 = self.function_2(param)
        self.param_3 = self.function_3()

是一样的吗?相同是指它们在所有变量中具有相同的值。

a = FooBar(param)
b = FooBar(param)

我想到了

if a == b:
    print "a and b are identical"!

这样做会没有副作用吗?

我的问题的背景是单元测试。我想达到以下目标:

self.failUnlessEqual(self.my_object.a_function(), another_object)

【问题讨论】:

    标签: python object match


    【解决方案1】:

    如果您希望== 起作用,请在您的类中实现__eq__ 方法以执行丰富的比较。

    如果您只想比较 所有 属性的相等性,您可以通过比较每个对象中的 __dict__ 来简洁地做到这一点:

    class MyClass:
    
        def __eq__(self, other) : 
            return self.__dict__ == other.__dict__
    

    【讨论】:

    • 请注意__dict__-比较__eq__ 可能会返回True,即使other 是一个完全不同的类,只要它具有相同的属性。这是人为的,我知道。如果您想防范它,请先插入if self.__class__ != other.__class__: return False
    • @AJ:如果我在课堂上实现了__eq__,并且我有一个实例列表L_1 = [obj_1, obj_2, obj_3] 和另一个列表L_2 = [obj_1, obj_2, obj_3]L_1 == L_2 会按预期工作吗?
    • 简而言之,是的。请注意,它们不必是相同的对象,因为您已经定义了要包含的两个示例列表。它们可以是两个列表,每个列表包含不同的对象并且仍然相等,如果列表中的对象被比较为相等按顺序。请注意,序列确实很重要。
    【解决方案2】:

    对于任意对象,== 运算符仅在两个对象是同一个对象(即它们引用内存中的相同地址时)才会返回 true。

    要获得更多“定制”行为,您需要覆盖丰富的比较运算符,在本例中特别是 __eq__。尝试将此添加到您的课程中:

    def __eq__(self, other):
        if self.param == other.param \
        and self.param_2 == other.param_2 \
        and self.param_3 == other.param_3:
            return True
        else:
            return False
    

    (所有参数的比较可以在这里整理,但为了清楚起见,我把它们留在了里面)。

    请注意,如果参数本身是您定义的对象,则这些对象必须以类似的方式定义 __eq__ 才能正常工作。

    另外一点需要注意的是,如果你尝试按照我上面所做的方式将 FooBar 对象与另一种类型的对象进行比较,python 将尝试访问另一种类型的对象的 param、param_2 和 param_3 属性将抛出一个 AttributeError。您可能需要先检查要比较的对象是 FooBar 的实例,其中 isinstance(other, FooBar) 首先。默认情况下不这样做,因为在某些情况下您可能希望返回 True 以在不同类型之间进行比较。

    查看 AJ 的回答,以更简洁的方式简单地比较所有不应引发属性错误的参数。

    有关丰富比较的更多信息,请参阅the python docs

    【讨论】:

      【解决方案3】:

      对于 python 3.7 以后的版本,您还可以使用dataclass 来非常轻松地准确检查您想要的内容。例如:

      from dataclasses import dataclass
      
      @dataclass
      class FooBar:
          param: str
          param2: float
          param3: int
      
      a = Foobar("test_text",2.0,3)
      b = Foobar("test_text",2.0,3)
      
      print(a==b)
      

      会返回True

      【讨论】:

        【解决方案4】:

        为避免向模型添加或删除属性并忘记对您的__eq__ 函数进行适当更改的可能性,您可以将其定义如下。

        def __eq__(self, other):
            if self.__class__ == other.__class__:
                fields = [field.name for field in self._meta.fields]
                for field in fields:
                    if not getattr(self, field) == getattr(other, field):
                        return False
                return True
            else:
                raise TypeError('Comparing object is not of the same type.')
        

        这样,所有的对象属性都会被比较。现在您可以使用object.__eq__(other)object == other 来检查属性是否相等。

        【讨论】:

          【解决方案5】:

          根据 Lutz 的 Learning Python,“==”运算符测试值等价,递归地比较所有嵌套对象。 “is”运算符测试两个对象是否是同一个对象,即内存中的相同地址(相同的指针值)。 除了缓存/重用小整数和简单字符串外,x = [1,2] 和 y = [1,2] 等两个对象在值上是相等的“==”,但y“是”x 返回假。两个浮点数 x = 3.567 和 y = 3.567 也是如此。这意味着它们的地址不同,或者换句话说,hex(id(x)) != hex(id(y))。

          对于类对象,我们必须重写方法 __eq__() 来生成两个 A 类对象,例如 x = A(1,[2,3]) 和 y = A(1,[2,3]) "==" in内容。默认情况下,class object "==" 在这种情况下只比较 id 和 id(x) != id(y),所以 x != y。 总之,如果x“是”y,那么x == y,但反之则不成立。

          【讨论】:

            【解决方案6】:

            如果这是您想在测试中使用的东西,您只想验证简单对象的字段是否相等,请查看来自 testfixtures 的 compare

            from testfixtures import compare
            
            compare(a, b)
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-07-21
              • 2010-12-06
              • 1970-01-01
              • 1970-01-01
              • 2021-03-22
              相关资源
              最近更新 更多