Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object equallity in python collections.Counter

I have and instance of collections.Counter class, also i have some objects like:

p1 = Person(name='John')
p2 = Person(name='John')
p3 = Person(name='Jane')

I want to hold the counts for this person objects in a instance of Counter, taking into account that person objects with same names must increment the same person count, so if i have a list with all person objects:

people = [p1, p2, p3]

and i populate my counter with it:

c = Counter(people)

i want to get the following:

c[p1] #prints 2
c[p2] #prints 2
c[p3] #prints 1

My first attempt was to implement a new __eq__ method for person objects

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

I thought that this could work because counter objects seems like increment the counts for keys based on the equality of the key objects, like in:

c = Counter(['A', 'A', 'B'])
c['A'] #prints 2
c['B'] #prints 1

Another attempt could be inherit from Counter and override the underlying method that Counter uses for measure the equality between objects , i am not sure but i think Counter uses __contains__ method for that.

My question is if there are any way to gets this behavior without using inheritance and if not, what could be the best way to do it?.

like image 924
angvillar Avatar asked Dec 26 '22 10:12

angvillar


1 Answers

You also have to implement __hash__:

class Person(object):
    def __init__(self, name=None, address=None):
        self.name = name
        self.address = address

    def __eq__(self, other):
        return self.name == other.name and self.address == other.address

    def __hash__(self):
        return hash((self.name, self.address))

Now your code works:

>>> Counter(people)
Counter({<__main__.Person object at 0x24a7590>: 2, <__main__.Person object at 0x24a75d0>: 1})
like image 85
Blender Avatar answered Jan 19 '23 00:01

Blender