Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method to compare Python dictionaries fails with certain value types?

I can't figure this out. I have two dictionaries which are identical. I use a standard method to determine the differences, of which there should be none. But certain value types are always returned as differences, even when they are not. For example, if a value is a pymongo.bson.ObjectId, the method fails to evaluate it as the same.

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

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

d1 == d2

returns:

True

But:

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

returns:

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

So I've figured out that this is weird, no?

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

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

What the?????!?!??!!?

like image 337
MFB Avatar asked Dec 11 '25 07:12

MFB


1 Answers

ObjectId('502e232ca7919d27990001e4') creates a new object and by default != compares references. Try for example:

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

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

This will evaluate to false, because they are difference instances, even if they hold the same value. To make this work, the class must implement the eq method:

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

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

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

To fix this, you can "monkey-patch" the class:

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

Or compare them by their values directly.

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

Compare the values when possible because monkey-patching may break seemingly unrelated code.

like image 160
BoppreH Avatar answered Dec 12 '25 21:12

BoppreH