Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do the binary operators mean when applied to logicals?

Tags:

python

My understanding is that & is the bitwise AND operator. So I would expect it to have no meaning when applied to logicals. However, I see that:

>>> False & False
False
>>> False & True
False
>>> True & True
True

and so on. Likewise for the other bitwise operators.

So, why do these operators even accept logical operands? And where can I find the documentation that explains this? I searched for it but could not find an explanation.

like image 392
David Heffernan Avatar asked Feb 18 '23 04:02

David Heffernan


1 Answers

So, why do these operators even accept logical operands?

bool subclasses int, and overrides __and__() etc to return bool for bool operands.

For details, see PEP 285.

Specifically:

      6) Should bool inherit from int?

       => Yes

       In an ideal world, bool might be better implemented as a
       separate integer type that knows how to perform mixed-mode
       arithmetic.  However, inheriting bool from int eases the
       implementation enormously (in part since all C code that calls
       PyInt_Check() will continue to work -- this returns true for
       subclasses of int).  Also, I believe this is right in terms of
       substitutability: code that requires an int can be fed a bool
       and it will behave the same as 0 or 1.  Code that requires a
       bool may not work when it is given an int; for example, 3 & 4
       is 0, but both 3 and 4 are true when considered as truth
       values.

and

    class bool(int):

        def __and__(self, other):
            if isinstance(other, bool):
                return bool(int(self) & int(other))
            else:
                return int.__and__(self, other)

        __rand__ = __and__

        def __or__(self, other):
            if isinstance(other, bool):
                return bool(int(self) | int(other))
            else:
                return int.__or__(self, other)

        __ror__ = __or__

        def __xor__(self, other):
            if isinstance(other, bool):
                return bool(int(self) ^ int(other))
            else:
                return int.__xor__(self, other)

        __rxor__ = __xor__

Note how bool & bool returns a bool whereas bool & non-bool inherit's int's behaviour (i.e. returns an int).

Here are some examples demonstrating these properties:

In [12]: isinstance(True, int)
Out[12]: True

In [13]: True & True
Out[13]: True

In [14]: True & 1
Out[14]: 1

The above behaviour does not apply to arithmetic operators. Those just use int's behaviour:

In [15]: True + 0
Out[15]: 1

In [16]: True + False
Out[16]: 1
like image 107
NPE Avatar answered Feb 20 '23 16:02

NPE