__bool__

Added in v3.x · Updated March 19, 2026 · Dunder Methods
python dunder-methods truthiness magic-methods

Overview

__bool__ is a Python magic method (dunder method) that lets you define custom truthiness behaviour for objects. Python calls it whenever it needs to convert an object to True or False — in conditionals, loops, bool(), logical operators, and more.

If you don’t define __bool__, Python falls back to __len__. If neither is defined, the object is always truthy.

Signature

def __bool__(self) -> bool:

Python invokes __bool__ automatically — you never call it directly. The return type should be bool in Python 3. Returning a non-zero integer like 1 works (non-zero ints are truthy) but violates the type contract and produces a DeprecationWarning — always return True or False.

When Python Calls __bool__

ContextExample
Explicit conversionbool(obj)
Conditional statementif obj:
while loopwhile obj:
assert statementassert obj
not operatornot obj
Logical and / orobj and other, obj or other
Comprehension filter[x for x in items if obj]

__bool__ vs __len__

If __bool__ is not defined but __len__ is, Python uses len(self) > 0 as the truth value:

class Empty:
    def __len__(self):
        return 0

print(bool(Empty()))  # False — uses __len__
# Output: False

If neither method is defined, the object is always True:

class Nothing:
    pass

print(bool(Nothing()))  # True — no __bool__ or __len__
# Output: True

This is why empty containers like [], {}, and "" are falsy — they all implement __len__.

Return Type

Python 3 requires __bool__ to return a bool. Returning a non-zero integer works due to Python’s truthiness rules, but it produces a DeprecationWarning:

class Bad:
    def __bool__(self):
        return 1  # Works, but wrong type — produces DeprecationWarning

print(bool(Bad()))  # True
# DeprecationWarning: __bool__ should return bool, not int

Returning non-bool types like strings or lists is also technically possible but raises a stronger warning and is never correct:

class VeryBad:
    def __bool__(self):
        return "yes"  # Wrong — don't do this

# DeprecationWarning: __bool__ must return bool, not str

Always return True or False.

Built-in Types and Truthiness

All built-in Python types use __len__ for truthiness when no custom __bool__ is defined:

TypeFalsy when
int0
float0.0
str"" (empty string)
list[] (empty list)
dict{} (empty dict)
tuple() (empty tuple)
NoneAlways False

This is why checking if somelist: works — Python calls __len__ as a fallback.

Code Examples

Custom Database Connection

class DatabaseConnection:
    def __init__(self, connected=False):
        self.connected = connected

    def __bool__(self):
        return self.connected

conn = DatabaseConnection(connected=True)
if conn:
    print("Executing query...")  # Runs

conn = DatabaseConnection(connected=False)
print(bool(conn))
# Output: False

Task List with Custom Empty State

class TaskList:
    def __init__(self, tasks=None):
        self.tasks = tasks or []
        self.completed = set()

    def __bool__(self):
        return len(self.incomplete()) > 0

    def incomplete(self):
        return [t for t in self.tasks if t not in self.completed]

todo = TaskList(tasks=["buy milk", "walk dog"])
while todo:
    task = todo.incomplete().pop()
    print(f"Doing: {task}")  # buy milk, then walk dog
    todo.completed.add(task)

print(bool(todo))
# Output: False — all tasks done

Order Status Validator

class OrderStatus:
    PENDING = "pending"
    CONFIRMED = "confirmed"
    CANCELLED = "cancelled"

    def __init__(self, status):
        if status not in (self.PENDING, self.CONFIRMED, self.CANCELLED):
            raise ValueError(f"Invalid status: {status}")
        self.status = status

    def __bool__(self):
        return self.status in (self.PENDING, self.CONFIRMED)

order = OrderStatus(OrderStatus.PENDING)
assert order  # Passes — truthy

order = OrderStatus(OrderStatus.CANCELLED)
print(bool(order))
# Output: False

Gotchas

NumPy Arrays

NumPy arrays with multiple elements cannot be converted to a single boolean:

import numpy as np

arr = np.array([1, 2, 3])
bool(arr)       # ValueError: truth value of array is ambiguous
arr > 0          # array([ True,  True,  True]) — use element-wise

Use element-wise comparisons instead of bool() on NumPy arrays.

__len__ Fallback Can Hide Intent

If you define __len__ to return 0 for “empty” but also want a separate __bool__ concept, be explicit. Python will always prefer __bool__ over __len__ — but if you only define __len__, len(obj) == 0 becomes the falsy condition even if that wasn’t your intent.

See Also

  • __eq__ — equality comparison
  • __str__ — string representation
  • __hash__ — hash value and __eq__ relationship