Back to Blog
Python

Python Right Shift: Bitwise Behavior and Common Pitfalls

python right shift: Explains Python's right shift operator: bitwise behavior on integers, negative handling, __rshift__ overloading, and common edge cases.

bitwise-operatorspython-operatorsinteger-arithmeticoperator-overloadingbinary-data
Illustration of a binary integer being shifted right by two positions with bits falling off the right edge.

python right shift requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

What the Right Shift Operator Does

Python's right shift operator, >>, moves every bit of the left operand to the right by the number of positions specified by the right operand. Bits that fall off the right edge are discarded, and new bits are introduced on the left. For positive integers, this is equivalent to floor division by a power of two, but the behavior on negative numbers and the operator's role in custom classes deserve closer attention.

value = 0b101100 # 44 in decimal shifted = value >> 2 print(shifted) # 11, which is 0b1011

The two low-order bits (00) were dropped, and the remaining four bits moved two positions to the right. The operator only accepts integers on both sides, and it can be redefined for custom classes through __rshift__.

How >> Behaves on Positive Integers

For any non-negative integer x, x >> n is equivalent to x // (2**n). This holds for every non-negative integer n.

print(16 >> 0) # 16 print(16 >> 1) # 8 print(16 >> 2) # 4 print(16 >> 3) # 2 print(16 >> 4) # 1 print(16 >> 5) # 0

Once the shift count exceeds the number of significant bits, the result becomes zero and stays zero. Because Python integers have arbitrary precision, there is no upper bound on the number of bits; the shift simply keeps producing zeros.

The equivalence with floor division is useful when reading code. x >> 3 means "divide by eight and round down." When the intent is arithmetic, x // 8 is usually clearer. When the intent is bit manipulation, x >> 3 communicates that directly.

Why Negative Numbers Shift Toward Negative Infinity

Python represents negative integers as if they had an infinite string of 1 bits on the left, which is two's complement with infinite sign extension. A right shift therefore preserves the sign: new bits on the left are 1, not 0.

print(-5 >> 1) # -3

The value -5 in infinite two's complement is ...11111011. Shifting right by one produces ...11111101, which is -3. The result is the floor of -5 / 2, which is -3, not -2. This differs from languages where a right shift on a signed integer is implementation-defined, and it is one of the reasons Python's >> is safe to use with negative operands.

ExpressionResultEquivalent floor division
8 >> 228 // 4
-8 >> 2-2-8 // 4
-5 >> 1-3-5 // 2
16 >> 3216 // 8

The practical consequence is that x >> n and x // (2**n) agree for every integer x, positive or negative. If you need truncation toward zero instead, use int(x / (2**n)) or apply a sign correction explicitly.

Extracting Bits From Binary Data

A common use of the right shift is extracting a range of bits from a packed integer. File formats, network protocols, and color values frequently store several small fields in a single machine word.

pixel = 0x7F3A2B # an RGB value packed into 24 bits red = (pixel >> 16) & 0xFF green = (pixel >> 8) & 0xFF blue = pixel & 0xFF print(hex(red), hex(green), hex(blue)) # 0x7f 0x3a 0x2b

Each shift moves the desired byte into the low eight bits, and the mask 0xFF discards everything above it. The same pattern works for arbitrary bit fields: shift by the field's offset and mask by (1 << width) - 1.

This pattern also appears when implementing hash functions, checksums, or custom serialization formats, where individual bits must be packed and unpacked without external libraries.

Overloading >> With rshift

The >> operator can be overloaded for custom classes by defining __rshift__. Python calls this method when the object appears on the left side of the operator.

class Version: def __init__(self, major, minor): self.major = major self.minor = minor def __rshift__(self, other): if isinstance(other, int): return Version(self.major >> other, self.minor >> other) return NotImplemented def __repr__(self): return f"Version({self.major}, {self.minor})" v = Version(8, 16) print(v >> 1) # Version(4, 8)

Returning NotImplemented for unsupported operand types lets Python fall back to the reflected operation or raise a TypeError with a standard message. If the class needs to support other >> self, define __rrshift__ as well.

Overloading >> is appropriate when the operation genuinely means "shift" in the domain model, such as moving a cursor, advancing a state machine, or shifting a bitmask-backed configuration. Using it for unrelated semantics makes the code harder to read.

Common Mistakes and Edge Cases

A negative shift count raises ValueError rather than shifting in the opposite direction.

value = 8 try: result = value >> -1 except ValueError as exc: print(exc) # negative shift count

A float shift count raises TypeError; the operator only accepts integers on both sides.

Operator precedence is another source of confusion. >> binds more tightly than &, ^, and |, but less tightly than + and -.

result = 1 + 2 >> 1 # (1 + 2) >> 1, which is 1

If the intent is 1 + (2 >> 1), parentheses are required. Python does not have a logical right shift operator like JavaScript's >>>; >> always preserves the sign for negative integers.

Performance Considerations for Bit Shifts

A right shift is a single operation on the integer's internal representation, whereas // performs general division. For powers of two, the shift avoids the division path entirely, so x >> n is the cheaper operation when the divisor is a known power of two.

That difference matters in hot loops that repeatedly divide by the same power of two, such as index calculations in a binary heap or a chunked data structure.

parent_index = (child_index - 1) >> 1

Here the shift expresses the halving operation directly and avoids the general division machinery. The readability gain is secondary; the operation itself is what the algorithm intends.

For one-off computations, the performance difference is rarely significant. Choose >> when the code is about bits and // when it is about arithmetic. Mixing them without reason obscures intent and makes the code harder to maintain.

When working with very large integers, the shift cost scales with the number of machine words that must be moved. Shifting by a count larger than the integer's bit length produces zero.

python right shift: Practical Usage and Code Examples | RYUSLOG DEV