diff --git a/README.md b/README.md index e1e9dab..c56065f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1509 TILs and counting..._ +_1510 TILs and counting..._ --- @@ -888,6 +888,7 @@ _1509 TILs and counting..._ - [Access Instance Variables](python/access-instance-variables.md) - [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md) - [Dunder Methods](python/dunder-methods.md) +- [Override The Boolean Context Of A Class](python/override-the-boolean-context-of-a-class.md) - [Store And Access Immutable Data In A Tuple](python/store-and-access-immutable-data-in-a-tuple.md) - [Test A Function With Pytest](python/test-a-function-with-pytest.md) - [Use pipx To Install End User Apps](python/use-pipx-to-install-end-user-apps.md) diff --git a/python/override-the-boolean-context-of-a-class.md b/python/override-the-boolean-context-of-a-class.md new file mode 100644 index 0000000..28b46ba --- /dev/null +++ b/python/override-the-boolean-context-of-a-class.md @@ -0,0 +1,86 @@ +# Override The Boolean Context Of A Class + +Everything in Python has a truthiness that can be checked with `bool()`. An +empty list (`[]`) is falsy. A non-empty list (`[1,2,3]`) is truthy. Similar +with numbers: + +```python +>>> bool(0) +False +>>> bool(1) +True +``` + +Any instance of an object is going to be truthy by default. If you want to +control in what context an instance is considered truthy or falsy, you can +override +[`__bool__()`](https://docs.python.org/3/reference/datamodel.html#object.__bool__). +If that's not implemented, but +[`__len__()`](https://docs.python.org/3/reference/datamodel.html#object.__len__) +is, then it will fallback to that. + +Let's look at a few example classes: + +```python +class CartZero: + def __init__(self, items=[]): + self.items = items or [] + +class CartBool: + def __init__(self, items=[]): + self.items = items or [] + + def __bool__(self): + print("__bool__() override") + return bool(self.items) + +class CartLen: + def __init__(self, items=[]): + self.items = items or [] + + def __len__(self): + print("__len__() override") + return len(self.items) + +class CartBoolAndLen: + def __init__(self, items=[]): + self.items = items or [] + + def __len__(self): + print("__len__() override") + return len(self.items) + + def __bool__(self): + print("__bool__() override") + return bool(self.items) + +cart1 = CartZero() +cart2 = CartBool() +cart3 = CartLen() +cart4 = CartBoolAndLen() + +print("CartZero() -> %s" %(bool(cart1))) +print('') +print("CartBool() -> %s" %(bool(cart2))) +print('') +print("CartLen() -> %s" %(bool(cart3))) +print('') +print("CartBoolAndLen() -> %s" %(bool(cart4))) +``` + +An 'empty' `Cart` be default is truthy. However, we can override some +combination of `__bool__()` or `__len__()` to give it a boolean context that +goes `false` when "empty". + +``` +CartZero() -> True + +__bool__() override +CartBool() -> False + +__len__() override +CartLen() -> False + +__bool__() override +CartBoolAndLen() -> False +```