Yes, you can use None, but perhaps you want to use a more appropriate
sentinel that has a better repr.
There are a handful of concepts and operations that we should be able to
rely on for every object, and if they fail, that ought to be considered
a buggy object.
-
Everything in the language has a value, an identity, and a type.
-
Stringification: str(obj), repr(obj), print(obj)
-
Equality and inequality tests: obj == other
-
Containment: obj in container
(That is, everything can be in a container. Not everything is a
container.)
And I believe that interpreting objects in a boolean context should be
considered a fundamental operation too. (Yes, that implies that I think
numpy arrays are broken. So sue me.)
There are, in my opinion, only two consistent models here:
-
The strict âreal booleansâ model, where only True and False can be
used in boolean contexts. Like Pascal. Or at least a weak form of that,
where ints can be used, with 0 representing false and all other ints are
true (usually with 1 or -1 as the canonical true). -
Or the Python/Ruby/Javascript model where we test for objects that
quack like a bool rather than are bools. Everything is either truthy
or falsey, and the default inherited from object is truthy.
Python usually imposes an especially consistent and useful model on
that, often abbreviated as âsomething versus nothingâ. But other
languages have their own models which I trust makes sense to them too.
A hybrid model with â(nearly) everything is truthy or falsey, except for
this list of exceptionsâ combines the worst of both worlds. It
violates Least Surprise, because just when you get used to thinking that
everything duck-types as a bool, bang something blows up in your face
with an exception.
We canât do anything about third-party libraries like numpy, but in my
opinion we shouldnât follow them.
âTruthy, falsey or whoops I just got an unexpected exceptionâ is not
even a proper three-valued logic like SQL uses 