Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

list equal to subclass of list?

20 views
Skip to first unread message

Roy Smith

unread,
May 12, 2011, 8:23:04 AM5/12/11
to
I have a vague feeling this may have been discussed a long time ago, but
I can't find the thread, so I'll bring it up again.

I recently observed in the "checking if a list is empty" thread that a
list and a subclass of list can compare equal:

----------------------------
class MyList(list):
"I'm a subclass"

l1 = []
l2 = MyList()

print type(l1), type(l2)
print type(l1) == type(l2)
print l1 == l2
----------------------------

when run, prints:

<type 'list'> <class '__main__.MyList'>
False
True

The docs say:

[http://docs.python.org/library/stdtypes.html]
Objects of different types, except different numeric types and different
string types, never compare equal

[http://docs.python.org/release/2.7/reference/expressions.html#notin]
objects of different types (emphasis)always compare unequal

In the test code above, l1 an l2 are different types, at least in the
sense that type() returns something different for each of them. What's
the intended behavior here? Either the code is wrong or the docs are
wrong.

Ethan Furman

unread,
May 12, 2011, 12:43:23 PM5/12/11
to Roy Smith, pytho...@python.org
Roy Smith wrote:
> I recently observed in the "checking if a list is empty" thread that a
> list and a subclass of list can compare equal:
>
> ----------------------------
> class MyList(list):
> "I'm a subclass"
>
> l1 = []
> l2 = MyList()
>
> print type(l1), type(l2)
> print type(l1) == type(l2)
> print l1 == l2
> ----------------------------
>
> when run, prints:
>
> <type 'list'> <class '__main__.MyList'>
> False
> True
>
> The docs say:
>
> [http://docs.python.org/library/stdtypes.html]
> Objects of different types, except different numeric types and different
> string types, never compare equal

This part of the documentation is talking about built-in types, which
your MyList is not.


> [http://docs.python.org/release/2.7/reference/expressions.html#notin]
> objects of different types *always* compare unequal

Should probably have the word 'built-in' precede 'types' here, since
constructed objects can do whatever they have been told to do.

> In the test code above, l1 an l2 are different types, at least in the
> sense that type() returns something different for each of them.

--> MyList.__mro__
(<class '__main__.MyList'>, <type 'list'>, <type 'object'>)

MyList is a list -- just a more specific kind of list -- as can be seen
from its mro; this is analogous to a square (2 sets of parallel lines
joined at 90 degree angles, both sets being the same length) also being
a rectangle (2 sets of parallel lines joined at 90 degree angles).

> What's the intended behavior here? Either the code is wrong or the docs
> are wrong.

The code is correct.

~Ethan~

PS
Yes, I know my square/rectangle definitions are incomplete, thanks. ;)

Ethan Furman

unread,
May 12, 2011, 2:29:54 PM5/12/11
to pytho...@python.org
Roy Smith wrote:
> On May 12, 2011, at 11:30 AM, Eric Snow wrote:
>>
>> That definitely makes it unclear.
>
> I don't think it's unclear at all. It's very clear. Clearly wrong :-)

While it is wrong (it should have 'built-in' precede the word 'types'),
it is not wrong in the way you think -- a subclass *is* a type of its
superclass.


>> A little further down it says that you can customize comparison with
>> the __cmp__ special method.
>
> I read that as saying that if you implement __eq__(), you must make sure
> that it returns False if self and other have different types (and
> likewise, __ne__() should return True for that case).

Your understanding is flawed. If your object does not know how to
compare itself to some other object, it should return NotImplemented --
at that point Python will follow the rules outlined in the docs. By
returning NotImplemented you are allowing the other object a chance to
perform the comparison -- after all, it might know how! :) If the
other object also returns NotImplemented then (drum-roll please) they
won't compare equal.


> The same way that it says that obj1.__lt__(obj2) must return a consistent
> result for all types of obj1 and obj2.

Where do you see that? I couldn't find it.

The point of being able to write your own rich comparison methods is so
you can control what happens -- there is no "must" about it. This is
Python -- do what you want! :)

~Ethan~

PS
I have a broken sense of humor -- sometimes it works, sometimes it
doesn't. My apologies in advance if my attempt at humor was not funny.

Thomas 'PointedEars' Lahn

unread,
May 12, 2011, 4:40:55 PM5/12/11
to
Ethan Furman wrote:

> PS
> I have a broken sense of humor -- sometimes it works, sometimes it
> doesn't. My apologies in advance if my attempt at humor was not funny.

Now that was very unpythonic. Know where your roots are! :)

--
PointedEars

Bitte keine Kopien per E-Mail. / Please do not Cc: me.

Roy Smith

unread,
May 12, 2011, 4:49:00 PM5/12/11
to
On May 12, 2:29 pm, Ethan Furman <et...@stoneleaf.us> wrote:

> While it is wrong (it should have 'built-in' precede the word 'types'),
> it is not wrong in the way you think -- a subclass *is* a type of its
> superclass.

Well, consider this:

class List_A(list):
"A list subclass"

class List_B(list):
"Another list subclass"

a = List_A()
b = List_B()
print a == b

It prints "True". Neither a nor b are a type of the other:

print isinstance(List_A, List_B)
print isinstance(List_B, List_A)

False
False

Ethan Furman

unread,
May 12, 2011, 5:48:20 PM5/12/11
to Roy Smith, pytho...@python.org

Okay, considering:
List_A is a user-defined type.
List_B is a user-defined type.
Both are sub-classes of list.
Corrected documentation (which says 'built-in types' etc, etc) says
nothing about user-defined types not being able to be equal to each other
neither List_A nor List_B have overridden the __eq__ method, so
list.__eq__ will be used...

conclusion:
if they have equal elements in the same order, they will compare
equal since they are, in fact, list's

Do you not get the same conclusion?

~Ethan~

Steven D'Aprano

unread,
May 12, 2011, 8:18:01 PM5/12/11
to
On Thu, 12 May 2011 09:43:23 -0700, Ethan Furman wrote:

> MyList is a list -- just a more specific kind of list -- as can be seen
> from its mro; this is analogous to a square (2 sets of parallel lines
> joined at 90 degree angles, both sets being the same length) also being
> a rectangle (2 sets of parallel lines joined at 90 degree angles).

Possibly the worst analogy ever! *wink*

http://en.wikipedia.org/wiki/Circle-ellipse_problem

Also known as the square-rectangle problem.

A better analogy might be, Lassie is a dog, and Flipper is a dolphin, so
they are different types of animal. But both dogs and dolphins are
mammals, so in that sense, Lassie and Flipper are both mammals and
therefore the same type of animal. It depends on what you mean by "type".

--
Steven

Ethan Furman

unread,
May 12, 2011, 9:04:20 PM5/12/11
to pytho...@python.org

I thought about using the mammal analogy instead, but geometry seemed
simpler. *sigh* Oh, well, can't win 'em all!

~Ethan~

Roy Smith

unread,
May 12, 2011, 9:53:05 PM5/12/11
to
In article <mailman.1479.1305217...@python.org>,
Ethan Furman <et...@stoneleaf.us> wrote:

> > [http://docs.python.org/library/stdtypes.html]
> > Objects of different types, except different numeric types and different
> > string types, never compare equal
>
> This part of the documentation is talking about built-in types, which
> your MyList is not.
>
>
> > [http://docs.python.org/release/2.7/reference/expressions.html#notin]
> > objects of different types *always* compare unequal
>
> Should probably have the word 'built-in' precede 'types' here, since
> constructed objects can do whatever they have been told to do.

Changing the docs (in numerous places) to make it clear that this is
only true of built-in types would indeed resolve the problem. As it
reads now, it's a general statement about ALL types, built-in or
user-defined.

0 new messages