我有一个具有以下布局的对象:
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)
令人惊讶的是,这让我失意。有人能指出我在这里缺少的东西吗?
答案 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的答案,因为这解释了对象相等性检查(您在类中继承)不检查任何属性值的相等性,而只是检查两者是否相同对象