From the docs the requirement are that it must be hashable and can be compared:
An object is hashable if it has a hash value which never changes
during its lifetime (it needs a hash() method), and can be
compared to other objects (it needs an eq() or cmp() method).
Hashable objects which compare equal must have the same hash value.
Hashability makes an object usable as a dictionary key and a set
member, because these data structures use the hash value internally.
All of Python’s immutable built-in objects are hashable, while no
mutable containers (such as lists or dictionaries) are. Objects which
are instances of user-defined classes are hashable by default; they
all compare unequal (except with themselves), and their hash value is
their id().
You can see from the last part that user defined classes (emphasis is mine) are hashable by default
There is no mention in the docs about mutability requirements for set
:
class set([iterable]) class frozenset([iterable]) Return a new set or
frozenset object whose elements are taken from iterable. The elements
of a set must be hashable. To represent sets of sets, the inner sets
must be frozenset objects. If iterable is not specified, a new empty
set is returned.)
For a dict
again the requirement is that the key is hashable:
A mapping object maps hashable values to arbitrary objects. Mappings
are mutable objects. There is currently only one standard mapping
type, the dictionary. (For other containers see the built in list,
set, and tuple classes, and the collections module.)