Sets can only contain immutable elements. For convenience, mutable Set objects are automatically copied to an ImmutableSet before being added as a set element.
The mechanism is to always add a hashable element, or if it is not hashable, the element is checked to see if it has an __as_immutable__() method which returns an immutable equivalent.
Since Set objects have a __as_immutable__() method returning an instance of ImmutableSet, it is possible to construct sets of sets.
A similar mechanism is needed by the __contains__() and remove() methods which need to hash an element to check for membership in a set. Those methods check an element for hashability and, if not, check for a __as_temporarily_immutable__() method which returns the element wrapped by a class that provides temporary methods for __hash__(), __eq__(), and __ne__().
The alternate mechanism spares the need to build a separate copy of the original mutable object.
Set objects implement the __as_temporarily_immutable__() method which returns the Set object wrapped by a new class _TemporarilyImmutableSet.
The two mechanisms for adding hashability are normally invisible to the user; however, a conflict can arise in a multi-threaded environment where one thread is updating a set while another has temporarily wrapped it in _TemporarilyImmutableSet. In other words, sets of mutable sets are not thread-safe.
See About this document... for information on suggesting changes.