56

All I want is for bool(myInstance) to return False (and for myInstance to evaluate to False when in a conditional like if/or/and. I know how to override >, <, =)

I've tried this:

class test:
    def __bool__(self):
        return False

myInst = test()
print bool(myInst) #prints "True"
print myInst.__bool__() #prints "False"

Any suggestions?

(I am using Python 2.6)

geckon
  • 8,316
  • 4
  • 35
  • 59
Ponkadoodle
  • 5,777
  • 5
  • 38
  • 62

6 Answers6

72

Is this Python 2.x or Python 3.x? For Python 2.x you are looking to override __nonzero__ instead.

class test:
    def __nonzero__(self):
        return False
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
Joe Holloway
  • 28,320
  • 15
  • 82
  • 92
  • 1
    Thanks for this... I was looking for a way to test the `__nonzero__` class method for [testing `False` here](https://github.com/trinitronx/python_koans/commit/2fe356926fef8e615b06fe7aaaa9a844536e58b5) – TrinitronX Sep 24 '14 at 03:21
  • It would be of benefit to mention that __bool__ is python3 and code to make a class more portable across python2/3 as mentioned by John below. – Leo Ufimtsev Jun 22 '19 at 19:04
70

If you want to keep your code forward compatible with python3 you could do something like this

class test:
    def __bool__(self):
        return False
    __nonzero__=__bool__
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • The __nonzero__=__bool__ seems to how an error in python 2 because __bool__ is not defined. – Leo Ufimtsev Jun 22 '19 at 19:11
  • @LeoUfimtsev have you moved "\_\_nonzero\_\_=\_\_bool\_\_" to a smaller line number than "def \_\_bool\_\_(self):" ? in that case it is undefined, written order matters here. – Zhang Fan Nov 10 '20 at 03:37
  • Wouldn't this create a class variable instead of an instance variable? – LMCuber Nov 12 '21 at 18:42
10

If your test class is list-like, define __len__ and bool(myInstanceOfTest) will return True if there are 1+ items (non-empty list) and False if there are 0 items (empty list). This worked for me.

class MinPriorityQueue(object):
    def __init__(self, iterable):
        self.priorityQueue = heapq.heapify(iterable)
    def __len__(self):
        return len(self.priorityQueue)

>>> bool(MinPriorityQueue([])
False
>>> bool(MinPriorityQueue([1,3,2])
True
IceArdor
  • 1,961
  • 19
  • 20
6

Similar to John La Rooy, I use:

class Test(object):
    def __bool__(self):
        return False

    def __nonzero__(self):
        return self.__bool__()
tknickman
  • 4,285
  • 3
  • 34
  • 47
  • 1
    `__nonzero__ = __bool__` is the preferable way of aliasing `__bool__` because it's less code (quicker to read, less to maintain), less likely to hide a bug (what happens if `__bool__` later becomes an async function?), but more importantly 1 less stack frame for a frequently called function that's also implicit! The difference here is whether you're defining 2 functions or just 1 function that's referenced twice. – IceArdor Jan 11 '19 at 09:38
4

test.__nonzero__()

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
2

[this is a comment to the answer from @john-la-rooy but I cannot comment yet :) ]

For Python3 compatibility you can do (I was looking for this)

class test(object):
    def __bool__(self):
        return False

    __nonzero__=__bool__

only problem is that you need to repeat the __nonzero__ = __bool__ everytime you change __bool__ in subclasses. Otherwise __nonzero__ will be kept from the superclass. You can try

from builtins import object  # needs to be installed !

class test(object):
    def __bool__(self):
        return False

    __nonzero__=__bool__

which should work (not confirmed) or write a metaclass :) yourself.

jhp
  • 519
  • 3
  • 13
  • 1
    Or use the approach from tknickman to avoid this issue. It will add another function call though! – jhp Jan 11 '17 at 10:13