10

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?

NPE
  • 486,780
  • 108
  • 951
  • 1,012

3 Answers3

16

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

"The choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program."

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.

shang
  • 24,642
  • 3
  • 58
  • 86
  • (+1) for the link and the quote. – NPE Jun 06 '11 at 13:59
  • +1, you was totally right in your comment i was mislead by the equality of two object and other comparison operator , thank you for figuring out my mistake – mouad Jun 06 '11 at 14:19
1

I'm not exactly sure, but maybe someone can correct me on this.

When you compare objects, it compares their memory address, think of comparing 2 cstrings in C. If you take a look, the sorting sorted the objects from the lowest memory address to the highest memory address (or pointer location).

Pwnna
  • 9,178
  • 21
  • 65
  • 91
  • Indeed, but doesn't this seem a bit arbitrary and therefore rather un-Pythonic? – NPE Jun 06 '11 at 13:36
  • Well, in the underlying C code, when you compare 2 object, it's simply comparing 2 integer, which points to the memory that the object is stored, and we all know how integer comparison works. – Pwnna Jun 06 '11 at 13:58
0

Look at the values when you print it. Notice the hex number next to the "Object C at"? That is a pointer reference. It can roughly be equated to creation order. If you iterate through that list, you'll see that it has sorted the objects using that as the standard.

As a side note, I remember being confused by Python 2.x comparisons... but I don't know if this, in particular, was fixed in Py3k.

Community
  • 1
  • 1
cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
  • Yes, I've noticed that. But what's the rationale? – NPE Jun 06 '11 at 13:34
  • 1
    @aix See the edit. Python < 3 made comparison almost annoyingly easy. See http://stackoverflow.com/questions/4266918/why-is-int50str5-in-python-2-x – cwallenpoole Jun 06 '11 at 13:42
  • The rationale is that variables in python are references to objects in the heap. Ordering by the memory address was probably the easiest to implement default behavior the python developers could think of. – Zhehao Mao Jun 06 '11 at 13:45