76

Why doesn't this work as one may have naively expected?

class Foo(object):
    def __init__(self):
        self.bar = 3
    def __bool__(self):
        return self.bar > 10

foo = Foo()

if foo:
    print 'x'
else:
    print 'y'

(The output is x)

wim
  • 266,989
  • 79
  • 484
  • 630

3 Answers3

74

For Python 2-3 compatibility, just add this to your example:

Foo.__nonzero__ = Foo.__bool__

or expand the original definition of Foo to include:

__nonzero__ = __bool__

You could of course define them in reverse too, where the method name is __nonzero__ and you assign it to __bool__, but I think the name __nonzero__ is just a legacy of the original C-ishness of Python's interpretation of objects as truthy or falsy based on their equivalence with zero. Just add the statement above and your code will work with Python 2.x, and will automatically work when you upgrade to Python 3.x (and eventually you an drop the assignment to __nonzero__).

PaulMcG
  • 56,194
  • 14
  • 81
  • 122
  • Where would these insertions go? I'm guessing the first could go immediately after the line `return self.bar > 10` (indented 0 spaces) and that the second could go immediately before the line `def __init__(self):` (indented 4 spaces). Is that correct? Or would the second have to go _after_ the `__bool__` definition? – Beetle Sep 22 '15 at 11:24
68

The __bool__ method is used in Python 3. For Python 2, you want __nonzero__.

Noel Evans
  • 6,837
  • 7
  • 44
  • 54
Cat Plus Plus
  • 113,388
  • 26
  • 185
  • 215
  • 1
    right, strange but true. good to see they changed implementation to the 'one obvious way to do it' – wim Nov 22 '11 at 06:18
  • 6
    @wim: Not too strange. The `__nonzero__()` method name considerably predates the introduction of the type `bool` in Python. Before `bool`, the just use the integers `0` and `1`. – Sven Marnach Nov 22 '11 at 23:02
  • 1
    @SvenMarnach: You guys had `0` and `1`? [Dilbert](http://dilbert.com/strips/comic/1992-09-08/) ;-) – JS. Oct 17 '14 at 00:57
27

Because the corresponding special method is called __nonzero__() in Python 2, and not __bool__() until Python 3.

Cody Piersall
  • 7,154
  • 2
  • 36
  • 52
Sven Marnach
  • 483,142
  • 107
  • 864
  • 776