checking if a list is empty

Steven D'Aprano steve+comp.lang.python at pearwood.info
Wed May 11 09:29:38 EDT 2011


On Wed, 11 May 2011 08:26:53 -0400, Roy Smith wrote:

> Hans Georg Schaathun <hg at schaathun.net> wrote:
> 
>> li == [] is as explicit as it gets, and leaves no room for doubt.
> 
> I was about to write, "this fails if li is an instance of a subclass of
> list", but then I tried it.  I was astounded to discover that:
> 
> class MyList(list):
>     "I'm a subclass"
> 
> li = MyList()
> print li == []
> print [] == li
> 
> prints True, twice!  I expected them both to be false.  In fact, the
> docs (http://tinyurl.com/3qga3lb) explicitly say:
> 
>> If both are numbers, they are converted to a common type. Otherwise,
>> objects of different types always compare unequal

That should be understood as only applying for built-in types, not 
arbitrary types. For arbitrary types, you can decide what counts as equal 
by writing an __eq__ method, and you can do *anything*:

    def __eq__(self, other):
        if today() == "Tuesday": return True
        else: ...


To understand the behaviour you are seeing, it helps to understand that 
while li is a MyList, it is also a list:

>>> isinstance(li, list)
True

It therefore inherits the same behaviour as list, unless you override or 
overload it. Since you did neither, MyLists work just like lists, right 
down to their __eq__ method.

It is normally considered The Right Thing To Do for subclasses to be 
usable anywhere where a superclass was. That is, subclasses like MyList 
should only *add* behaviour, never *subtract* it. Since:

>>> li = list()
>>> li == []
True

applies, you should be able to replace list() with any subclass of list 
and it should still work. (This is known as the Liskov Substitution 
Principle, if you wish to google on it.)

This being Python, it's more of a guideline than a law, and you can 
violate it if you choose, but you probably shouldn't unless you have good 
reason. But if you want, just add a method:

    def __eq__(self, other):
        # untested
        if type(self) is not type(other): return False
        return super(self, MyList).__eq__(other)

to get the behaviour you are after.


So, not a bug, but a subtle point that isn't explained terribly well in 
the docs.



-- 
Steven



More information about the Python-list mailing list