In Python, every object has a logical truth value. This means that any object can be evaluated in a Boolean context.
You can directly check an object’s truth value (also known as truthiness) by passing it to the bool() constructor.
By default, all objects evaluate to True. The main exceptions are:
- Empty containers, such as „”, (), [], {}, set(), frozenset(), bytes(), bytearray(), and range(0).
- The zero value of any numeric type, such as 0, 0.0, 0j, or 0e0.
- The constants None and False, as well as expressions that evaluate to them.
- Custom objects whose definitions explicitly make them evaluate to False by implementing the __bool__ method.
Having truth values associated with objects is useful because they:
- enables shorter and more readable conditional expressions,
- allows different data types to be handled consistently in conditional checks,
- simplifies the use of logical operations,
- contributes to the concise and readable coding style that Python is known for.
As a result, less code needs to be written while the program’s intent remains clear.
To demonstrate this, consider an example that models the summarization of order data in an online store. The following code illustrates the approach.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
class Cart: """Shopping cart class. The cart stores its items in a list.""" def __init__(self, items: list): self.items = items def __str__(self): return str(self.items) def __len__(self): return len(self.items) # Customer data. customers = [{"name": "Adam", "nickname": "", "email": "adam@example.com", "discount": 4, "cart": Cart(["apple", "pear"])}, {"name": "", "nickname": "", "email": "", "discount": 0, "cart": Cart([])}, {"name": "Eva", "nickname": "", "email": "eva@dummymail.com", "discount": 5.5, "cart": Cart([])}, {"name": "Alexander", "nickname": "Alex", "email": "", "discount": 0, "cart": Cart(["bread"])} ] for customer in customers: # Only customers with non-empty carts will have their orders processed. if len(customer["cart"]) > 0: # Display the nickname in the summary if available; otherwise use the regular name. if customer["nickname"] != "": display_name = customer["nickname"] else: display_name = customer["name"] print(f"Customer: {display_name}") # Display information about the cart contents. print(f"Cart: {len(customer['cart'])} item(s): {str(customer['cart']).strip('[]')}") # Display the discount only if it is greater than zero. if (discount := customer["discount"]) > 0: print(f"Available discount: {discount} EUR") # Display the email address as well if provided, for order confirmation. if customer["email"] != "": print(f"Notification email address: {customer['email']}") print() # Output: # Customer: Adam # Cart: 2 item(s): 'apple', 'pear' # Available discount: 4 EUR # Notification email address: adam@example.com # # Customer: Alex # Cart: 1 item(s): 'bread' |
The program processes customers one by one and displays the following information whenever it is available:
- the customer’s name (preferably a nickname, if one is provided),
- information about the contents of the customer’s shopping cart,
- any discount they are eligible for based on previous purchases,
- the email address that can be used for notifications.
In this version, we do not take advantage of object truth values. As you can see, the conditional checks involve logical operators, parentheses, function calls, and selection statements.
If we leverage the truthiness of objects, the loop body can be rewritten as follows.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
class Cart: """Shopping cart class. The cart stores its items in a list.""" def __init__(self, items: list): self.items = items def __str__(self): return str(self.items) def __len__(self): return len(self.items) # Customer data. customers = [{"name": "Adam", "nickname": "", "email": "adam@example.com", "discount": 4, "cart": Cart(["apple", "pear"])}, {"name": "", "nickname": "", "email": "", "discount": 0, "cart": Cart([])}, {"name": "Eva", "nickname": "", "email": "eva@dummymail.com", "discount": 5.5, "cart": Cart([])}, {"name": "Alexander", "nickname": "Alex", "email": "", "discount": 0, "cart": Cart(["bread"])} ] for customer in customers: # Only customers with non-empty carts will have their orders processed. if customer["cart"]: # Display the nickname in the summary if available; otherwise use the regular name. display_name = customer["nickname"] or customer["name"] print(f"Customer: {display_name}") # Display information about the cart contents. print(f"Cart: {len(customer['cart'])} item(s): {str(customer['cart']).strip('[]')}") # Display the discount only if it is greater than zero. if discount := customer["discount"]: print(f"Available discount: {discount} EUR") # Display the email address as well if provided, for order confirmation. if customer["email"]: print(f"Notification email address: {customer['email']}") print() # Output: # Customer: Adam # Cart: 2 item(s): 'apple', 'pear' # Available discount: 4 EUR # Notification email address: adam@example.com # # Customer: Alex # Cart: 1 item(s): 'bread |
In this version, the conditional checks no longer require logical operators, parentheses, or function calls, and even the selection statement can be replaced with a logical expression. As a result, the code focuses more on expressing the business logic and less on the technical details of validation and checking. Object truth values therefore do more than save keystrokes—they make programs easier to read by allowing them to be expressed at a higher level of abstraction.
At this point, you may wonder why the statement if customer['cart'] works even though we did not define a __bool__ method in the Cart class. The answer lies in Python’s truth-value determination rules.
When Python evaluates the truth value of an object, it follows this sequence:
- If the object defines a __bool__ method, Python calls it and uses the returned value.
- If __bool__ is not defined but __len__ is, Python calls __len__. If the return value is 0, the object evaluates to False; otherwise, it evaluates to True.
- If neither __bool__ nor __len__ is implemented, the object evaluates to True by default.
Since the Cart class implements the __len__ method, its return value is used when determining the object’s truth value.
For a more detailed discussion of overriding the __bool__ method, see chapter “Implementing Containers” in the e-book Python Knowledge Building Step by Step From The Basics To The First Desktop Application.