One reason why Python doesn't let you overload the boolean AND and OR operations
Recently I read Kurt Rose's DISappearing and (via
Planet Python), where Kurt noted that Python doesn't have
methods that let you override boolean
or operations on
your class objects. As it happens, there's a really good reason for
this, which is that Python would require a new fundamental data type
in order to make it really work.
or have the extremely valuable property of
short-circuiting evaluation, where if you write, say, '
a() evaluates to false, Python will not even call
Let's imagine a hypothetical world in which Python allows you to
do this overriding and the boolean operators still preserve this
short circuiting. As usual, if you write '
a and b', this will (at
least some of the time) translate into a call to the override method
a, let's call it
__band__, and the
__band__ method will
receive an additional argument that represents the right hand side:
class AClass: def __band__(self, right): ....
Now here is the big question: what's the type of
right in this
right is the value we get from evaluating
the right hand side expression; if you write '
a & b()', this is
roughly the same as
a.__and__(b()). However this can't be the
__band__, because that would mean no more short-circuiting;
a had a
__band__ method, writing
a and b() would call
b() all of the time. To preserve short-circuiting,
to be some type that represents the right hand side expression in
an un-evaluated form.
However, Python has no such type today. Closures sort of come close,
but they create additional effects and do things like appear in Python
exception backtraces. This means that adding override methods for
boolean operations would require either discarding short-circuiting (and
right be the evaluation result) or figuring out and introducing
a new, relatively complex type in Python just to support this.
(Continuations are sort of what you'd need but I think they're not quite what you want, or at least you need a continuation that captures only the right side expression.)
The other problem of such a
right type is that you'd want to be
able to peer inside it relatively easily. After all, the entire
purpose of implementing your own
__band__ method is so that you
can do something different from a plain boolean
and when the right
hand side is some special thing. If all you're going to do is:
def __band__(self, right): if not bool(self): return False else: return right.eval()
then there's not really any point in having a
__band__ at all,
especially given the general complexity involved in Python as a
(This is of course not necessarily the only reason for Python to fence off boolean operations as things that you absolutely can't override. You can certainly argue that they should be inviolate and not subject to clever redefinitions simply as a matter of principle.)