How to Get the Logical Xor of Two Variables in Python

How do you get the logical xor of two variables in Python?

If you're already normalizing the inputs to booleans, then != is xor.

bool(a) != bool(b)

Is there a neat way to perform XOR operation on two conditions in IF statement?

^ will work just fine if you use parentheses:

if (firstvalue[0] == "-") ^ (secondvalue[0] == "-"):

You can also use != in the place of ^. It works the exact same way here, but may be a little more clear.

Python XOR preference: bitwise operator vs. boolean operators

One of the alternative way to achieve it is using any() and all() like:

if any([a, b]) and not all([a, b]):
print "Either a or b is having value"

But based on the performance, below are the results:

  1. Using any() and all(): 0.542 usec per loop

    moin@moin-pc:~$ python -m "timeit" "a='a';b='b';" "any([a, b]) and not all([a, b])"
    1000000 loops, best of 3: 0.542 usec per loop
  2. Using bool(a) ^ bool(b): 0.594 usec per loop

    moin@moin-pc:~$ python -m "timeit" "a='a';b='b';" "bool(a) ^ bool(b)"
    1000000 loops, best of 3: 0.594 usec per loop
  3. Using (not a and b) or (a and not b): 0.0988 usec per loop

    moin@moin-pc:~$ python -m "timeit" "a='a';b='b';" "(not a and b) or (a and not b)"
    10000000 loops, best of 3: 0.0988 usec per loop

Clearly, your (not a and b) or (a and not b) is more efficient. Approximately 6 times efficient then others.


Comparison between few more flavors of and and or:


  1. Using a and not b or b and not a (as pointed by TemporalWolf): 0.116 usec per loop

    moin@moin-pc:~$ python -m "timeit" "a='a';b='b';" "a and not b or b and not a"
    10000000 loops, best of 3: 0.116 usec per loop
  2. Using (a or b) and not (a and b): 0.0951 usec per loop

    moin@moin-pc:~$ python -m "timeit" "a='a';b='b';" "(a or b) and not (a and b)"
    10000000 loops, best of 3: 0.0951 usec per loop

Note: This performance is evaluated for the value of a and b as str, and is dependent on the implementation of __nonzero__ / __bool__ / __or__ functions as is mentioned by viraptor in comment.

Example of XOR Operator in Python

This is a fair enough implementation:

def xor(a:bool, b:bool)->bool:
return (not a) == (b)

Python XOR behavior with a mix of positive/negative number

If python's integers were fixed-width (eg: 32-bit, or 64-bit), a negative number would be represented in 2's complement form. That is, if you want -a, then take the bits of a, invert them all, and then add 1. Then a ^ b is just the number that's represented by the bitwise xor of the bits of a and b in two's complement. The result is re-interpreted in two's complement (ie: negative if the top bit is set).

Python's int type isn't fixed-width, but the result of a ^ b follows the same pattern: imagine that the values are represented as a wide-enough fixed-with int type, and then take the xor of the two values.

Although this now seems a bit arbitrary, it makes sense historically: Python adopted many operations from C, so xor was defined to work like in C. Python had a fixed-width integer type like C, and having a ^ b give the same result for the fixed-width and arbitary-width integer types essentially forces the current definition.

Back to a worked example: 1 ^ -2. 8 bits is more than enough to represent these two values. In 2's complement:

 1 = 00000001
-2 = 11111110

Then the bitwise xor is:

   = 11111111

This is the 8-bit 2's complement representation of -1. Although we've used 8 bits here, the result is the same no matter the width chosen as long as it's enough to represent the two values.

Using Logical Operators On Integers

Decimal 1000 is binary 11 1110 1000. Decimal 255 is binary 1111 1111. First, they are converted to signed int, which is usually 32 bits wide.

Taking & of them sets the bit at all positions where both bits of the operands are set:

  0000 0000 0000 0000 0000 0011 1110 1000
0000 0000 0000 0000 0000 0000 1111 1111
& ---------------------------------------
0000 0000 0000 0000 0000 0000 1110 1000

This is decimal 232. Taking | would have set the bit at all positions where at least one bit is set, i.e. would have produced binary 11 1111 1111, which is decimal 1023. Taking ^ would have set the bit at all positions where exactly one of the bits is set, i.e.

  0000 0000 0000 0000 0000 0011 1110 1000
0000 0000 0000 0000 0000 0000 1111 1111
^ ---------------------------------------
0000 0000 0000 0000 0000 0011 0001 0111

&& is not a binary operation. It simply returns 1 if and only if both operands are non-zero. || returns 1 if and only if at least one of the operands is non-zero. In other cases, they return 0, respectively.



Related Topics



Leave a reply



Submit