很多Python初学者看到&、|、^、<<、>>这些运算符时,会觉得业务代码用不上。实际上位运算在权限系统设计、颜色处理、状态标记、网络编程、数据压缩与加密中无处不在,而且比算术运算快得多。理解位运算能让你真正理解计算机如何看待数据——底层一切都是0和1。
本文从二进制基础开始,逐步掌握Python中所有位运算符的使用方法和实战场景。
- class Permission:
- """基于位运算的权限系统"""
- READ = 1 << 0 # 0b000001 = 1
- WRITE = 1 << 1 # 0b000010 = 2
- EXECUTE = 1 << 2 # 0b000100 = 4
- DELETE = 1 << 3 # 0b001000 = 8
- ADMIN = 1 << 4 # 0b010000 = 16
- @staticmethod
- def has_permission(user_perm, perm):
- return (user_perm & perm) != 0
- @staticmethod
- def grant(user_perm, perm):
- return user_perm | perm
- @staticmethod
- def revoke(user_perm, perm):
- return user_perm & (~perm)
- @staticmethod
- def toggle(user_perm, perm):
- return user_perm ^ perm
- @staticmethod
- def permission_names(perm_value):
- names = []
- for name in ['READ', 'WRITE', 'EXECUTE', 'DELETE', 'ADMIN']:
- if perm_value & getattr(Permission, name):
- names.append(name)
- return names
复制代码
二进制基础
计算机用二进制存储数据,因为只有开/关两种状态物理上最可靠。Python中用0b或0B前缀表示二进制数。
- a = 0b1010 # 二进制1010 = 十进制10
- b = 0b1111 # 二进制1111 = 十进制15
- print(a) # 10
- print(bin(10)) # 0b1010
- print(format(10, 'b')) # 1010
- print(format(255, '08b')) # 11111111
- # 手动转换:十进制→二进制
- def decimal_to_binary(n):
- if n == 0:
- return '0'
- bits = []
- while n > 0:
- bits.append(str(n % 2))
- n //= 2
- return ''.join(reversed(bits))
- print(decimal_to_binary(10)) # 1010
- # 二进制→十进制
- def binary_to_decimal(binary_str):
- result = 0
- for bit in binary_str:
- result = result * 2 + int(bit)
- return result
- print(binary_to_decimal('1010')) # 10
复制代码
一位(bit)是二进制的一位;一个字节(byte)是8个比特。位从右往左编号,权重为2的n次方。
- print((10).bit_length()) # 4
- print((255).bit_length()) # 8
复制代码
Python还支持八进制(0o)、十六进制(0x)表示。
- binary = 0b1010
- hexadecimal = 0xFF
- print(bin(255)) # 0b11111111
- print(hex(255)) # 0xff
- print(int('0xf', 16)) # 15
- # f-string格式化
- n = 42
- print(f"二进制: {n:b}, 八进制: {n:o}, 十六进制: {n:x}")
复制代码
按位与 &
运算规则:两位都为1才得1。
- a = 0b1100 # 12
- b = 0b1010 # 10
- print(a & b) # 8 (0b1000)
- # 检查某一位是否为1
- def is_bit_set(n, position):
- return (n & (1 << position)) != 0
- print(is_bit_set(0b1100, 2)) # True
- # 取低N位(掩码操作)
- def low_n_bits(n, num_bits):
- mask = (1 << num_bits) - 1
- return n & mask
- print(bin(low_n_bits(0b11010110, 4))) # 0b110
复制代码
按位或 |
运算规则:任一位为1就得1。
- a = 0b1100
- b = 0b1010
- print(a | b) # 14 (0b1110)
- # 设置某一位为1
- def set_bit(n, position):
- return n | (1 << position)
- print(bin(set_bit(0b1000, 1))) # 0b1010
- # 合并标志位:权限系统的核心
- READ = 0b001
- WRITE = 0b010
- EXECUTE = 0b100
- permission = READ | WRITE # 3 (0b011)
- print(permission)
复制代码
按位异或 ^
运算规则:两位不同得1,相同得0。
- a = 0b1100
- b = 0b1010
- print(a ^ b) # 6 (0b0110)
- # 切换某一位(toggle)
- def toggle_bit(n, position):
- return n ^ (1 << position)
- print(bin(toggle_bit(0b1010, 0))) # 0b1011
- # 不使用临时变量交换整数
- a, b = 10, 20
- a ^= b
- b ^= a
- a ^= b
- print(a, b) # 20, 10
- # 找出数组中唯一出现奇数次的数
- def find_odd_occurrence(arr):
- result = 0
- for num in arr:
- result ^= num
- return result
- arr = [1, 2, 3, 2, 1, 3, 4, 5, 4]
- print(find_odd_occurrence(arr)) # 5
- # 简易异或加密
- def xor_cipher(text, key):
- return ''.join(chr(ord(c) ^ key) for c in text)
- encrypted = xor_cipher("Hello", 42)
- decrypted = xor_cipher(encrypted, 42)
- print(decrypted) # Hello
复制代码
按位取反 ~
Python中整数是无限精度的补码表示,~n = -(n+1)。
- print(~10) # -11
- print(~(-5)) # 4
- # 固定位宽的取反需要掩码
- def bitwise_not_fixed(n, num_bits=8):
- mask = (1 << num_bits) - 1
- return (~n) & mask
- print(bin(bitwise_not_fixed(0b1100, 8))) # 0b11110011
复制代码
左移 << 与右移 >>
左移一位相当于乘以2,右移一位相当于除以2(向下取整,左侧补符号位)。
- x = 0b0001
- print(bin(x << 2)) # 0b100 (4)
- print(1 << 10) # 1024
- # 右移
- x = 0b1000 # 8
- print(x >> 2) # 2 (0b10)
- print(-16 >> 1) # -8
- print(100 >> 2) # 25
- # 提取特定位:右移+掩码
- def get_bits(n, start, count):
- return (n >> start) & ((1 << count) - 1)
- print(bin(get_bits(0b10110110, 3, 3))) # 0b110
复制代码
实战:颜色处理
- def rgb_to_hex(r, g, b):
- return f"#{(r << 16) | (g << 8) | b:06X}"
- print(rgb_to_hex(255, 128, 0)) # #FF8000
- def hex_to_rgb(hex_color):
- hex_color = hex_color.lstrip('#')
- value = int(hex_color, 16)
- r = (value >> 16) & 0xFF
- g = (value >> 8) & 0xFF
- b = value & 0xFF
- return (r, g, b)
- print(hex_to_rgb("#3498DB")) # (52, 152, 219)
复制代码
实战:状态标记与位图
用一个整数表示多种状态的组合,并通过位运算快速检查/设置。
- class UserStatus:
- ONLINE = 1 << 0
- VERIFIED = 1 << 1
- PREMIUM = 1 << 2
- BANNED = 1 << 3
- MODERATOR = 1 << 4
- @classmethod
- def is_online(cls, status):
- return (status & cls.ONLINE) != 0
- @classmethod
- def set_online(cls, status):
- return status | cls.ONLINE
- # 位图:批量追踪用户在线状态
- class UserBitmap:
- def __init__(self, max_users=1024):
- self.bitmap_size = (max_users + 63) // 64
- self.bitmap = [0] * self.bitmap_size
- def set_online(self, user_id):
- word_idx = user_id // 64
- bit_idx = user_id % 64
- self.bitmap[word_idx] |= (1 << bit_idx)
- def is_online(self, user_id):
- word_idx = user_id // 64
- bit_idx = user_id % 64
- return (self.bitmap[word_idx] & (1 << bit_idx)) != 0
- def online_count(self):
- total = 0
- for word in self.bitmap:
- total += word.bit_count() # Python 3.8+
- return total
复制代码
性能优势
位运算比乘除法快很多。例如左移6位代替乘以64,右移代替除以2的幂。下面是用timeit测速的示例:
- import timeit
- n = 1234567890
- t_multiply = timeit.timeit(lambda: n * 64, number=10_000_000)
- t_shift = timeit.timeit(lambda: n << 6, number=10_000_000)
- print(f"n * 64: {t_multiply:.4f}s")
- print(f"n << 6: {t_shift:.4f}s")
复制代码
在实践中,Python的位运算符(&, |, ^, ~, <<, >>)都是底层C实现的,效率极高。在循环次数较多的场景中代替乘除法能获得明显提升。
常用技巧速查
判断奇偶:n & 1 == 1 为奇数;清零最低位的1:n & (n-1);获取最低位的1:n & -n;计算2的幂:1 << k;掩码生成:(1 << k) - 1。
掌握这些位运算技巧,能让你写出更高效、更优雅的代码,尤其在系统编程、游戏开发、嵌入式等领域大显身手。 |