__bool__
Let's say for example you are building a cache class and you want to operate on this cache class. However, you want to fetch some user from the cache, only if it's there, but you're having problems with this.
class SimpleCache:
def __init__(self):
self._data = {}
def set(self, key, value):
self._data[key] = value
def get(self, key, default=None):
return self._data.get(key, default)
…
def fetch_user(cache, user_id):
if not cache: # natural, just like a dict or list
print("Cache empty, querying DB...")
data = {\"id\": user_id, \"name\": \"Alex\"'}'}
cache.set(user_id, data)
else:
print("Using cache")
return cache.get(user_id)
One core component of idiomatic python is evaluating truthfulness of
objects in a Boolean way when using things like if,
while, and not. For lots of existing types we
see existing false groups:
- Constants such as
NoneandFalse - Zero of any type
- Empty Sequence/collections
As well as existing True objects like:
- Non-zero numbers:
1,-2,0.5,1+0j - Non-empty strings:
"0","False"," ","hello" - Non-empty collections:
[0],(None,),{0},{\"k\": 1},{1},range(1) - Non-empty bytes-like:
b"\x00",bytearray(b"\x00"),memoryview(b"x") - Objects & callables
For our custom object that we create, Python uses __bool__
(or __len__ if __bool__ doesn't exist) to determine
object truthfulness.
__bool__ is a dunder (double underscore) which basically
means it's a special function used to define your own python operations.
Other examples include the widely used __init__,
__len__, and __str__ or other operators.
To use it, we want to return True or False based
on if the instance of that class is should be empty or not a valid instance
such as in the example that a cache has no data then:
class SimpleCache:
def __init__(self):
self._data = {}
def set(self, key, value):
self._data[key] = value
def get(self, key, default=None):
return self._data.get(key, default)
def __bool__(self):
return len(self._data) > 0
# Now this function works perfectly!
def fetch_user(cache, user_id):
if not cache: # natural, just like a dict or list
print("Cache empty, querying DB...")
data = {\"id\": user_id, \"name\": \"Alex\"'}'}
cache.set(user_id, data)
else:
print("Using cache")
return cache.get(user_id)
Advantages of This Approach
- Readability: Conditions like
if not cache:are natural and concise when emptiness means "no useful state". - Simplified conditionals: You avoid sprinkling
len(cache._data) == 0ornot cache._datathroughout the codebase. - Encapsulation & consistency: One canonical definition of "empty/invalid" lives in the class, preventing ad-hoc checks that drift over time.
Questions or feedback? Feel free to reach out!