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.
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. ;)
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.
> 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.
> 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
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~
> 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
I thought about using the mammal analogy instead, but geometry seemed
simpler. *sigh* Oh, well, can't win 'em all!
~Ethan~
> > [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.