Even though sets are unhashable, membership check in other set works:
>>> set() in {frozenset()}
True
I expected TypeError: unhashable type: 'set'
, consistent with other behaviours in Python:
>>> set() in {} # doesn't work when checking in dict
TypeError: unhashable type: 'set'
>>> {} in {frozenset()} # looking up some other unhashable type doesn't work
TypeError: unhashable type: 'dict'
So, how is set membership in other set implemented?
set_contains
is implemented like this:So this will delegate directly to
set_contains_key
which will essentially hash the object and then look up the element using its hash.If the object is unhashable,
set_contains_key
returns-1
, so we get inside thatif
. Here, we check explicitly whether the passedkey
object is a set (or an instance of a set subtype) and whether we previously got a type error. This would suggest that we tried a containment check with aset
but that failed because it is unhashable.In that exact situation, we now create a new
frozenset
from thatset
and attempt the containment check usingset_contains_key
again. And since frozensets are properly hashable, we are able to find our result that way.This explains why the following examples will work properly even though the set itself is not hashable:
The last line of the documentation for
set
s discusses this: