2012-11-20 40 views
3

我無法弄清楚這一點。我有兩本相同的字典。我使用標準方法來確定差異,其中應該沒有差異。但某些值類型總是作爲差異返回,即使它們不是。例如,如果值爲pymongo.bson.ObjectId,則該方法無法將其評估爲相同。用於比較Python字典的方法在某些值類型中失敗?

d1 = {'Name':'foo','ref1':ObjectId('502e232ca7919d27990001e4')} 

d2 = {'Name':'foo','ref1':ObjectId('502e232ca7919d27990001e4')} 

d1 == d2 

回報:

True 

但是:

set((k,d1[k]) for k in set(d1) & set(d2) if d1[k] != d2[k]) 

回報:

set([('ref1',Objectid('502e232ca7919d27990001e4'))]) 

所以我已經想通了,這是奇怪的,不是嗎?

d1['ref1'] == d2['ref1'] # True 

d1['ref1'] != d2['ref1'] # False 

什麼是?!?!?? !!?

+0

你的兩個ObjectId值是否引用同一個對象,或者它們是不同的對象? ObjectId類是否適當地實現了__eq__?我試圖用一個虛擬的'ObjectId'重現,但我得到了預期的結果(一個空集)。 – Blckknght

+0

這是一個很好的問題,因爲根據[文檔](http://docs.python.org/2/reference/expressions.html#comparisons),「映射(字典)比較等於當且僅當它們的排序鍵,值)列表比較相等。「所以'd1 == d2'應該暗示'd1 [k] == d2 [k]'。 – unutbu

+0

'ObjectId'可能是一個bug類,其中'hash(o)'基於,例如'o.value',但'o1 == o2'不是。但是,如果平等和哈希都不以價值爲基礎,這是完全合理的行爲。 – abarnert

回答

2

ObjectId('502e232ca7919d27990001e4')創建一個新對象,默認!=比較引用。例如:

class Obj: 
    def __init__(self, value): 
     self.value = value 

print Obj(1234) == Obj(1234) # False 

這將評估爲false,因爲它們是差異實例,即使它們具有相同的值。爲了使這項工作,這個類必須實現EQ方法:

class Obj: 
    def __init__(self, value): 
     self.value = value 

    def __eq__(self, other): 
     return self.value == other.value 

print Obj(1234) == Obj(1234) # True 

爲了解決這個問題,你可以在「猴子補丁」類:

class Obj: 
    def __init__(self, value): 
     self.value = value 

print Obj(1234) == Obj(1234) # False 

Obj.__eq__ = lambda a, b: a.value == b.value 

print Obj(1234) == Obj(1234) # True 

或者由它們的值直接對它們進行比較。

print Obj(1234).value == Obj(1234).value 

比較可能的值,因爲猴子修補可能會破壞看起來不相關的代碼。

+0

在這種情況下,你應該加一個'__hash__'方法來保證返回相同的值對於相同的對象,例如'def __hash __(self):return hash(self.value)',以防止問題中的行爲發生。 – glglgl

+0

謝謝,你讓我進入測試模式,幫助我找到bug – MFB