在Python中检查两个对象是否已更改?

时间:2014-07-03 06:16:46

标签: python

我有一个具有以下布局的对象:

class Obj1(object):
    def __init__(self, user, password, items=None):
        self._user = user
        self._password = password
        self._items = items

    def add_items(self, item):
        self._items.append(item)

    def has_changed(self, obj2):
        return self != obj2

现在我执行以下操作:

obj1 = Obj1('me', '1234')
obj1.add_item({'name':'george', 'progress':'70'})
#obj2 = obj1 #wont work since they would point to same object
obj2 = copy.copy(obj1)
obj1.add_item({'name':'monica', 'progress':'86'})
print obj2.has_changed(obj1)

令人惊讶的是,这让我失意。有人能指出我在这里缺少的东西吗?

2 个答案:

答案 0 :(得分:6)

您可以覆盖__eq__ method of the object。当您只是仅比较对象identities are compared时(它们不是同一个对象,因此==将导致False):

  

默认情况下,用户定义的类具有__eq__()__hash__()方法;与他们一起,所有对象比较不等(除了他们自己)x.__hash__()返回id(x)

这是一个小例子:

>>> class A(object):
...     def __init__(self, i):
...         self.i = i
...
>>>
>>> a = A(1)
>>> b = A(1)
>>> c = A(2)
>>> a == b
False
>>> a == c
False

但如果你覆盖比较,你就会得到你需要的东西:

>>> class B(object):
...     def __init__(self,i):
...         self.i = i
...     def __eq__(self,o):
...         return self.i == o.i
...     def __ne__(self,o):
...         return self.i != o.i
...
>>> d = B(1)
>>> e = B(1)
>>> f = B(2)
>>> d == e
True
>>> d == f
False
>>>

同样比较目录"深度比较" (所以你可以直接比较字典):

>>> d1 = {1:2, 3:4}
>>> d2 = {}
>>> d2[1] = 2
>>> d2[3] = 4
>>> d3 = {5:6, 3:4}
>>> d1 == d2
True
>>> d1 == d3
False

另请注意,在实施丰富比较方法时,您应遵循一些规则 [1] [2] ,例如:

  

比较运营商之间没有隐含的关系。 x==y 的真实性并不意味着 x!=y是错误的。因此,在定义__eq__()时,还应定义__ne__(),以便运算符按预期运行。

     

丰富的比较方法的论据是从不强制。

     

覆盖__eq__()但未定义__hash__()的类会将其__hash__()隐式设置为None


请求更新:

从不强制参数coercion in python glossary)表示检查输入参数(我的示例中为o)是您的责任,请尝试:

>>> d == 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __eq__
AttributeError: 'int' object has no attribute 'i'

甚至可以比较不同类别的对象:

>>> d == a
True

__hash__设置为None表示hash(obj)失败:

>>> hash(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'B'

每个需要散列的集合也都失败了:

>>> set((d,))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'B'

虽然它适用于A

>>> set((a,))
{<__main__.A object at 0x7f8a85fe4668>}

答案 1 :(得分:0)

这是您的代码的工作版本。我包含了copy模块的必需导入,并添加了冒号以使其成为有效的代码。

import copy

class Obj1(object):
    def __init__(self, user, password, items=None):
        self._user = user
        self._password = password
        self._items = [] if items==None else items

    def add_item(self, item):
        self._items.append(item)

    def has_changed(self, obj2):
        return self != obj2

obj1 = Obj1('me', '1234')
obj1.add_item({'name':'george', 'progress':'70'})
#obj2 = obj1 #wont work since they would point to same object
obj2 = copy.copy(obj1)
obj1.add_item({'name':'monica', 'progress':'86'})
print(obj2.has_changed(obj1))
print(obj1.has_changed(obj1))

似乎可以正常工作,但并不是真的(见下文)。请注意,我添加了一个进一步的测试,以确保比较在True和False时都有效......但到目前为止测试还不够。

但是,您应该查看@Viktor的答案,因为这解释了对象相等性检查(您在类中继承)不检查任何属性值的相等性,而只是检查两者是否相同对象