Being Basic and Python Bitwise Operators
It's hard for me to write about the basics of programming in Python for a couple reasons. First, I'm old — or, older than the average programmer according to big media. Second, I've been using Python for close to a decade. It feels a little immature and regressive, but all things considered, it's necessary. At least, so I feel more knowledgable when asked a question.
Initially, I was excited to talk about bitwise operators and binary numbers, but, as I dove deeper it became clear that the world of binary is quite complex. Since we're talking about Python, I can at least narrow the focus down to that. However, If you want to read up on signed and unsigned integers, binary representation, and the math behind the operand, there are plenty of resources. I'll list a couple at the bottom of the article. For now, know that the info below is specific to Python and it's just scratching the surface of a wider field.
Separately, It's hard to think of a future in which I'd have to use any of Python's bitwise operators, but I still found them to be one of the most interesting parts of the entry-level Python Certification. And, after all, there are real-world problems that can be solved with bitwise ops — compression, encryption, network communications, and I'm sure you could find a use for them in the IoT world. I probably won't be the one solving these problems, but someone is/will. Really though, I'm not even sure that Python is the best tool to use to solve these problems, but that's something for someone else to deal with.
In reality, these operators are all performing a basic, non-complex, function. Conceptually, most of them operate in a similar manner as their identically named logical counterparts — the difference being that they compare individual bits. Unknowingly, at first glance, you might expect
0b100100 & 0b101010 to equal
False, and that's okay. But, you'd be wrong.
I'll go over four of Python's bitwise operators and the shift operators by outlining their basic functions.
The operators are:
^ XOR (exclusive OR)
<< Left Shift
>> Right Shift
The bitwise AND operator
& performs logical conjunction on the bit pairs of both operands. For each pair of bits at the same position, a one is returned when both bits are one (or when both bits are on). For example:
1 0 1 0 1 0 1 1 0 0 1 1 0 0 -------------- 1 0 0 0 1 0 0
result = 0b1010101 & 0b1001100 print(bin(result)) # 0b1000100
See how we end up with a new binary number? Except now, we have 1 in the same position as each pair of bits that are both set to 1. For the pairs that are both 0, or only one bit is set to 1, they result in a 0.
The bitwise OR operator
| performs logical disjunction. For each pair of bits, if at least one bit is set to 1, the result is 1. For example:
1 0 1 0 1 0 1 1 0 0 1 1 0 0 -------------- 1 0 1 1 1 0 1
result = 0b1010101 | 0b1001100 print(bin(result)) # 0b1011101
The binary number returned now has a 1 at each position in which the corresponding pair of bits had at least one bit set to 1.
The bitwise XOR, exclusive OR, operator
^operates similarly to OR
| with a notable exception. When comparing two bits that are both set to 1, XOR will return 0, while AND and OR would both return 1. With XOR
^, each bit in a pair must be the opposite of the other. Two 1s don't make a 1.
1 0 1 0 1 0 1 1 0 0 1 1 0 0 -------------- 0 0 1 1 0 0 1
result = 0b1010101 ^ 0b1001100 print(bin(result)) # 0b11001 (the leading 0s are dropped)
Each bit pair must be the opposite of the other, if they're the same then a 0 is returned.
x = 5 y = ~x print(y) # -6
The last bitwise operator NOT
~, in Python, returns the complement of the argument minus the number you get by switching all the bits to their opposite, or,
-x - 1. There's a whole bunch of math and logic behind NOT and logical negation, but for now, know that NOT
-x - 1.
Bitwise Left Shift
The left shift operator
<< moves all the bits of the first operand to the left by the number of positions specified in the second operand. To compensate for the shift, a 0 bit will be added on the opposite side.
x = 0b101 x <<= 2 # or x = x << 2 print(bin(x)) #0b10100
Visually, you'll see it operate like this:
0 b 1 0 1 << 2 = 0b10100.
Bitwise Right Shift
The right shift operator
>> moves all the bits of the first operand to the (you guessed it) right by the number of positions specified in the second operand.
x = 0b101 x >>= 2 # or x = x >> 2 print(bin(x)) #0b1
If you try to shift more bits than the number has, you'll end up with 0 (or 0b0).
>> will operate like this:
0 b 1 0 1 >> 2 = 0b1.
Now that you've gotten to the end of my article, if you're interested in bitwise operators and how Unix file permissions take advantage of them, Alex Hyett has an article on just that topic.
For a real solid, thorough, explanation of Bitwise operators, Binary representation, and more, see this article from RealPython.
See something wrong? Email [email protected].