In Python 2.7, I define an empty new-style class:
In [43]: class C(object): pass
....:
then create a list of instances of the new class:
In [44]: c = [C() for i in xrange(10)]
then attempt to sort the list:
In [45]: sorted(c)
Out[45]:
[<__main__.C object at 0x1950a490>,
<__main__.C object at 0x1950a4d0>,
...
<__main__.C object at 0x1950aad0>]
What’s surprising is that the sort doesn’t complain, even though I haven’t defined a way to compare instances of C:
In [46]: dir(C())
Out[46]:
['__class__',
'__delattr__',
'__dict__',
'__doc__',
'__format__',
'__getattribute__',
'__hash__',
'__init__',
'__module__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__']
What exactly is happening there, and what’s the rationale for this — arguably surprising — behaviour?
I think the only rationale is that it is convenient that objects can be sorted and e.g. used as dictionary keys with some default behavior. The relevant chapter in the language definition is here: https://docs.python.org/2/reference/expressions.html#not-in
So the fact that objects are currently compared using the memory address is just an implementation detail that cannot be counted upon. The only guarantee is that the ordering stays consistent during execution.