Search code examples
pythonsethashable

Confused with Python sets adding same object twice


If I add an integer to a Python set object twice, Python will only add it once.

a = set()
a.add(5)
a.add(5)
print(a)
>> {5}

However, in my app I am am trying to add coroutines to a set, because I can't find a better way to keep track of which coroutines are already in the event_loop. I was surprised by the following behaviour:

async def foo(something):
    await asyncio.sleep(1)
    print(something)

a = set()
coro_obj = foo("hi") 
a.add(coro_obj)
coro_obj = foo("hi") 
a.add(coro_obj)
print(a)
{<coroutine object foo at 0x7f36f8c52888>, <coroutine object foo at 0x7f36f8c52360>}

I'm not really sure what I've done here. Am I right in thinking if the coroutine object wasn't hashable, it wouldn't get added to the set? So it is hashable, right?

Then if its hashable, why do we get two distinct hashes with the same method/argument?


Solution

  • Sets are using hash for comparing objects, so two objects would be consider equal if both objects' __ hash __() methods will return the same value. In your example, it would be something like this:

    a = set()
    coro_obj = foo("hi") 
    a.add(coro_obj.__hash__())
    coro_obj = foo("hi") 
    a.add(coro_obj.__hash__())
    print(a)
    {-9223363267847141772, 8769007586508}
    

    As you can see hashes of both objects are diffrent, this all depend on inner coroutine __ hash __ method implementation

    ADDITION: And obj1.__ eq__(obj2) also supposed to be True