David Heffernan
David Heffernan

Reputation: 612814

What do the binary operators mean when applied to logicals?

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.

Upvotes: 4

Views: 142

Answers (3)

NPE
NPE

Reputation: 500207

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

Upvotes: 8

Silas Ray
Silas Ray

Reputation: 26150

"Logicals", aka booleans, just represent a single bit either on or off, so of course bitwise operations work on them. What would make you expect bitwise operations not work on single bits?

You're inverting the inheritance of logical operations. The base case of bitwise operations is on single bit variables such as booleans. Bitwise operations on larger values are just an extended application of the single bit operation.

Upvotes: 0

Fyre
Fyre

Reputation: 1180

In Python 3.x True and False are keywords and will always be equal to 1 and 0.

Under normal circumstances in Python 2, and always in Python 3:

False object is of type bool which is a subclass of int:

 object
  |
 int
  |
 bool

Upvotes: 0

Related Questions