Example: If __len__ is defined on an object x, and __nonzero__ (Py2) or __bool__ (Py3) is not defined, then "not x" will test if x.__len__() == 0.
Similarly, __contains__ interacts with "foo in x", and __eq__ and __hash__ are expected to play well together for hashable objects (e.g. unique members of a set).
The double underscores are a useful code smell that indicates you're changing how an object interacts with Python's syntax.
Why use x.__len__() rather than len(x)?