Python’s ** bitwise NOT** operator

`~x`

inverts each bit from the binary representation of integer `x`

so that 0 becomes 1 and 1 becomes 0. This is semantically the same as calculating `~x == -x-1`

. For example, the bitwise NOT expression `~0`

becomes `-1`

, `~9`

becomes `-10`

, and `~32`

becomes `-33`

. As you go over the article, you can watch my explainer video here:

In this example, you apply the ** bitwise NOT **operator to integer 32:

>>> ~32 -33

The expression `~32`

operates on the bit representations `"0100000"`

(decimal 32) and performs ** bitwise NOT** resulting in binary

`"1011111"`

. This corresponds to the negative decimal number -33. `x` | 0 | 1 | 0 | 0 | 0 | 0 | 0 |

`~x` | 1 | 0 | 1 | 1 | 1 | 1 | 1 |

How do you transform the binary “1011111” to a decimal number again? By using the following steps:

- Flip each bit back to
`0100000`

. - Get the corresponding decimal number
`32`

. - Increase it by one to
`33`

. - Prefix it with the negative symbol
`-33`

.

To understand this inverse method from a negative binary to an integer, you need to learn some background first. But don’t worry, it’s just a couple of minutes! ?

Table of Contents

## Representing Negative Integers in Binaries

Python uses so-called ** complementary binaries** to represent negative integers. The first bit of a complementary binary is the sign (0: positive, 1: negative). All remaining bits encode the number. You write a negative number

`-x`

as the bit pattern for `(x-1)`

and flip all bits from 1 to 0 and from 0 to 1 (complement). Here are two simple examples:

- To represent
`x = -1`

using 8 bits you first calculate`(1-1) = 0`

and then flip all bits to calculate`"11111111"`

. - To represent
`x = -10`

using 8 bits you first calculate`(10-1) = 9`

which is`"00001001"`

in binary format. Then, you complement all bits to determine the negative (complementary) binary`"11110110"`

.

? In fact, Python uses ** signed integers** for its bitwise operators. You may ask:

*what are signed integers?*- A
**signed integer**, for example using 32 bits, encodes an integer in the range`[-2147483648 to 2147483647]`

. - An
**unsigned integer**encodes a positive integer in the range`[0 to 4294967295]`

. The signed integer is represented in twos complement notation.

## Python Bitwise NOT Operator Example

Here’s the result of the ** bitwise NOT **operator

`~x`

when applied to a couple of example integer operands `x`

:x (int) | x (binary) | ~x (binary) | ~x (int) |
---|---|---|---|

`0` | `'00'` | `'11'` | `-1` |

`1` | `'01'` | `'10'` | `-2` |

`3` | `'011'` | `'100'` | `-4` |

`9` | `'01001'` | `'10110'` | `-10` |

`11` | `'01011'` | `'10100'` | `-12` |

`256` | `'0100000000'` | `'1011111111'` | `-257` |

You can see those examples in the following Python script:

>>> ~0 -1 >>> ~1 -2 >>> ~3 -4 >>> ~9 -10 >>> ~11 -12 >>> ~256 -257

Let’s use this knowledge in a couple of examples to showcase the working of the *bitwise NOT operator* on negative integers:

## Python Bitwise NOT Examples on Negative Integers

Here’s the result of the *bitwise NOT* operator `~x`

when applied to a negative integer operand `x`

:

x (int) | ~x (int) |
---|---|

`-0` | `-1` |

`-1` | `0` |

`-3` | `2` |

`-9` | `8` |

`-11` | `10` |

`-256` | `255` |

You can see those examples in the following script:

>>> ~-0 -1 >>> ~-1 0 >>> ~-3 2 >>> ~-9 8 >>> ~-11 10 >>> ~-256 255

## Python Bitwise NOT Overloading

You can define your own ** bitwise NOT **operator on a custom class by overloading the

`__invert__`

method (*dunder method*,

*magic method*) with a reference to

`self`

as an argument. This allows the expression `~x`

on your custom objects without raising an error.Here’s an example:

class Data: def __init__(self, data): self.data = data def __invert__(self): return Data(~self.data) x = Data(3) res = ~x print(res.data) # -4

**Note**: if you forget to overwrite the `__invert__`

method and still try to use the expression `~x`

, Python will raise a `TypeError: bad operand type for unary ~`

. You can fix it by defining the dunder method `__invert__(self)`

in your class definition.

class Data: def __init__(self, data): self.data = data x = Data(3) res = ~x print(res.data)

Output:

Traceback (most recent call last): File "C:\Users\xcent\Desktop\code.py", line 8, in res = ~x TypeError: bad operand type for unary ~: 'Data'

To fix this `TypeError`

, simply define the `__invert__`

method as shown in the previous working example.

## Bitwise Operators

Bitwise operators perform operations on the binary (bit) representation of integers. The following table gives a short overview of all existing bitwise operators. Note that we also provide the binary representation `100`

for the decimal integer `4`

, and `101`

for the decimal integer `5`

as a comment in the right column.

Operator | Name | Description | Example |
---|---|---|---|

`x = 4, y = 5` | |||

& | Bitwise AND | Performs logical AND on a bit-by-bit basis | `x & y` |

| | Bitwise OR | Performs logical OR operation on a bit-by-bit basis | `x | y` |

~ | Bitwise NOT | Performs logical NOT on a bit-by-bit basis, inverting each bit so that 0 becomes 1 and 1 becomes 0. Same as `-x-1` . | `~x` |

^ | Bitwise XOR | Performs logical “exclusive or” operation on a bit-by-bit basis | `x ^ y` |

>> | Bitwise right shift | Shifts binary of left operand to the right by the number of positions specified in right operand | `x >> 2` |

<< | Bitwise left shift | Shifts binary of left operand to the left by the number of positions specified in right operand | `x << 2` |

Here’s a short overview of the Bitwise operators’ magic methods:

Bitwise Operator | Magic “Dunder” Method |
---|---|

`&` | `__and__(self, other)` |

`|` | `__or__(self, other)` |

`^` | `__xor__(self, other)` |

`~` | `__invert__(self)` |

`<<` | `__lshift__(self, other)` |

`>>` | `__rshift__(self, other)` |

Here’s an example of how to accomplish these bitwise operators on a custom class `Data`

. We marked this respective operator in the code:

class Data: def __init__(self, data): self.data = data def __and__(self, other): return Data(self.data & other.data) def __or__(self, other): return Data(self.data | other.data) def __xor__(self, other): return Data(self.data ^ other.data) def __invert__(self): return Data(~self.data) def __lshift__(self, other): return Data(self.data << other.data) def __rshift__(self, other): return Data(self.data >> other.data) x = 2 y = 3 print('Operands: \n', 'x =', x, '\n', 'y =', y) print() print('Bitwise AND: ', x & y) print('Bitwise OR: ', x | y) print('Bitwise XOR: ', x ^ y) print('Bitwise NOT: ', ~x) print('Bitwise LEFT-SHIFT: ', x << y) print('Bitwise RIGHT-SHIFT: ', x >> y)

The output is:

Operands: x = 2 y = 3 Bitwise AND: 2 Bitwise OR: 3 Bitwise XOR: 1 Bitwise NOT: -3 Bitwise LEFT-SHIFT: 16 Bitwise RIGHT-SHIFT: 0

While working as a researcher in distributed systems, Dr. Christian Mayer found his love for teaching computer science students.

To help students reach higher levels of Python success, he founded the programming education website Finxter.com. He’s author of the popular programming book Python One-Liners (NoStarch 2020), coauthor of the Coffee Break Python series of self-published books, computer science enthusiast, freelancer, and owner of one of the top 10 largest Python blogs worldwide.

His passions are writing, reading, and coding. But his greatest passion is to serve aspiring coders through Finxter and help them to boost their skills. You can join his free email academy here.