0

I have read overriding bool() for custom class and it doesn't answer my question, "how to implement a list subclass that evaluates as False if its items evaluate as False". Specifically, it doesn't address:

  • subclassing a list
  • evaluating as False in a boolean context if its items evaluate as False in a boolean context

Motivation

One might have a data-model requires deeply nested lists of lists, and one might require an easier solution than recursing through the list of lists to determine if it has accumulated something that evaluates as True in a boolean context.

The Context

In Python an empty list evaluates as False

>>> l = list()
>>> l
[]
>>> bool(l)
False

But a list with an empty list, (or some other 0 or empty container) in it evaluates as True because the len of the containing list is > 0.

>>> l.append([])
>>> l
[[]]
>>> bool(l)
True

Question:

Can I subclass a list such that it is an instance of a list but that if it contains empty lists or other things that evaluate as empty or False will return False? i.e.:

>>> l = MagicList((None, 0, {}, MagicList([0, False])))
>>> isinstance(l, list)
True
>>> bool(l)
False
Community
  • 1
  • 1
Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • possible duplicate of [overriding bool() for custom class](http://stackoverflow.com/questions/2233786/overriding-bool-for-custom-class) – jonrsharpe Jan 01 '14 at 18:49
  • The answer given, overriding `__nonzero__`, is applicable here too and is specifically used in the current top-rated(/only) answer. – jonrsharpe Jan 01 '14 at 18:57
  • Many general concepts are used to answer questions. The question was not how to implement __nonzero__. The question was how to subclass a list that evaluates False when its items evaluate as False. I think you're objectively wrong here. As for the other downvotes, Stackoverflow does recommend explaining them. – Russia Must Remove Putin Jan 01 '14 at 19:53
  • 2
    (I didn't downvote) Regarding the other downvotes, a reason could very well be that you asked an off-topic question. There is nothing in your question that demonstrates an attempt to solve this problem yourself. Just because you have a pretty good reputation score and happened to answer this question yourself doesn't mean that you can ask an improper question (although I think that -4 is kinda harsh). –  Jan 01 '14 at 20:24

1 Answers1

3

Python Data Model for Containers

Python lists check for self.__len__(), in a boolean context, which we learn from the Python 2 documentation:

... an object that doesn’t define a __nonzero__() method and whose __len__() method returns zero is considered to be false in a Boolean context.

And the __nonzero__ documentation tells us:

Called to implement truth value testing and the built-in operation bool(); should return False or True, or their integer equivalents 0 or 1. When this method is not defined, __len__() is called ...

So if we implement a __nonzero__ method, it will shortcut the check for len when evaluating as a boolean, and we can then then if the items in it evaluate boolean:

Demonstration

class MagicList(list):
    def __bool__(self): # Python 3 uses __bool__ instead of __nonzero__
        return any(self)
    __nonzero__=__bool__ # ensure Python 2 <-> 3 compatibility

and instantiate, and we can demonstrate that it is an instance of a list, and since it is empty, evaluates as False:

>>> l = MagicList()
>>> l
[]
>>> isinstance(l, list)
True
>>> bool(l)
False

and if we extend our list with some empty items, and it continues to return False

>>> l.extend([None, 0, {}])
>>> l
[None, 0, {}]
>>> len(l)
3
>>> bool(l)
False

And if append an element that evaluates as True, it returns True (here we append another MagicList with a 0 that evaluates False, but also a tuple with len = 1 that evaluates as True)

>>> l.append(MagicList([0, (0,)]))
>>> l
[None, 0, {}, [0, (0,)]]
>>> bool(l)
True

Conclusion

This answers the motivation of seeking a deeply nested list of lists, as long as the lists are instances of the subclassed list created here.

It's probably better to use the built-in datatypes and inspect them recursively if necessary. This demonstrates a possibility, not necessarily a best practice.

If you did do this, you would have to explicitly check for len > 0, if that is your point of interest.

>>> len(l) > 0
True
>>> len(l)
4
Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
  • This does not meet "*One might have a data-model requires deeply nested lists of lists, and one might require an easier solution than recursing through the list of lists to determine if it has accumulated something that evaluates as True in a boolean context.*" – Jon Clements Jan 01 '14 at 22:08
  • If used for each of the lists, instead of the built-in lists, it does answer. – Russia Must Remove Putin Jan 01 '14 at 22:15