Python 中数据的位运算
在 Python 中,位运算(bitwise operation) 是对整数在二进制层面进行操作的常见方式,通常用于性能优化、状态编码、底层硬件交互等。
一、位逻辑运算简介
位逻辑运算符是对 整数的二进制表示的每一位 进行操作。
运算符 | 名称 | 作用 | 示例 | ||
---|---|---|---|---|---|
& |
位与 | 同为 1 ⇒ 结果为 1 | 5 & 3 |
||
` | ` | 位或 | 任一为 1 ⇒ 结果为 1 | `5 | 3` |
^ |
位异或 | 不同为 1 ⇒ 相同为 0 | 5 ^ 3 |
||
~ |
取反 | 所有位取反(含符号位) | ~5 |
1. 位与(AND)&
a = 0b0101 # 5
b = 0b0011 # 3
print(bin(a & b)) # 0b0001 => 1
2. 位或(OR)|
a = 0b0101 # 5
b = 0b0011 # 3
print(bin(a | b)) # 0b0111 => 7
3. 位异或(XOR)^
a = 0b0101 # 5
b = 0b0011 # 3
print(bin(a ^ b)) # 0b0110 => 6
4. 位取反(NOT)~
注意:Python 中取反是按补码进行(即 ~x = -x - 1
)
a = 5 # 二进制:0000 0101
print(~a) # -6
print(bin(~a)) # -0b110
二、移位运算(shift)
运算符 | 名称 | 说明 |
---|---|---|
<< |
左移 | 相当于乘以 2 的 n 次方 |
>> |
右移 | 相当于除以 2 的 n 次方(向下取整) |
1. 左移 <<
a = 3 # 0b0011
print(a << 2) # 12
print(bin(a << 2)) # 0b1100
左移 n
位 等价于 a * 2**n
2. 右移 >>
a = 16 # 0b10000
print(a >> 2) # 4
print(bin(a >> 2)) # 0b100
右移 n
位 等价于 a // 2**n
三、常见应用实例
1. 判断奇偶数(用位与)
def is_odd(n):
return n & 1 == 1
print(is_odd(5)) # True
print(is_odd(8)) # False
2. 交换两个数(不使用临时变量)
a, b = 5, 3
a = a ^ b
b = a ^ b
a = a ^ b
print(a, b) # 3 5
3. 清零最低位的 1(如 0b10100 → 0b10000)
x = 20 # 0b10100
print(bin(x & (x - 1))) # 0b10000
4. 获取最低位的 1
x = 20 # 0b10100
print(bin(x & -x)) # 0b100
5. 统计二进制中 1 的个数(Brian Kernighan 算法)
def count_ones(n):
count = 0
while n:
n &= (n - 1)
count += 1
return count
print(count_ones(15)) # 4 (0b1111)
四、完整汇总表(逻辑运算 vs 二进制)
假设 a = 5 (0b0101)
, b = 3 (0b0011)
:
表达式 | 运算 | 结果(二进制) | 结果(十进制) | |
---|---|---|---|---|
a & b |
位与 | 0b0001 |
1 |
|
`a | b` | 位或 | 0b0111 |
7 |
a ^ b |
位异或 | 0b0110 |
6 |
|
~a |
位取反 | -0b0110 |
-6 |
|
a << 1 |
左移 1 位 | 0b1010 |
10 |
|
a >> 1 |
右移 1 位 | 0b0010 |
2 |
五、小结
运算符 | 名称 | 关键理解点 | |
---|---|---|---|
& |
与 | 两位都为 1,结果才为 1 | |
` | ` | 或 | 任意一位为 1,结果为 1 |
^ |
异或 | 两位不同,结果为 1 | |
~ |
取反 | 与符号位有关,结果为 -x - 1 |
|
<< |
左移 | 乘以 2 的 n 次方(整数部分) | |
>> |
右移 | 除以 2 的 n 次方(向下取整) |
Python 中状态编码(掩码)
Python 中的状态编码(掩码)与权限控制(二进制位模拟),这些技术常用于:
- 操作系统中的权限(读写执行)
- 嵌入式系统中的状态位
- 游戏中角色状态(如“中毒”、“冰冻”、“隐身”等)
- 8 位或 16 位“寄存器模拟器”
一、状态编码与掩码(bitmask)
掩码(mask) 是一种位标记机制,用二进制的每一位表示某种“状态”或“权限”。
1. 权限示例(类 Unix 权限)
权限 | 二进制位 | 十进制 |
---|---|---|
读(R) | 0b100 |
4 |
写(W) | 0b010 |
2 |
执行(X) | 0b001 |
1 |
一个用户有读+执行权限:0b101 = 5
2. 掩码操作函数示例
# 定义权限位
READ = 0b100
WRITE = 0b010
EXEC = 0b001
# 设置权限(或运算)
perm = 0
perm |= READ # 添加读权限
perm |= EXEC # 添加执行权限
print(f"当前权限: {bin(perm)}") # 0b101
# 检查权限(与运算)
def has_permission(p, flag):
return (p & flag) != 0
print("有写权限?", has_permission(perm, WRITE)) # False
print("有读权限?", has_permission(perm, READ)) # True
# 移除权限(与取反)
perm &= ~READ
print(f"移除读权限后: {bin(perm)}") # 0b001
二、使用枚举构建权限系统(更清晰)
from enum import IntFlag
class Permission(IntFlag):
READ = 4
WRITE = 2
EXEC = 1
# 设置权限
perm = Permission.READ | Permission.EXEC
print(f"当前权限: {perm}")
# 检查
print("有写权限?", Permission.WRITE in perm)
print("有读权限?", Permission.READ in perm)
三、8 位寄存器模拟(位标记系统)
示例:控制器状态位
位索引 | 状态名 | 说明 |
---|---|---|
0 | POWER_ON | 电源开启 |
1 | ERROR | 错误状态 |
2 | BUSY | 正在处理 |
3 | SLEEP | 休眠状态 |
4-7 | 保留 | - |
实现寄存器模拟类
class Register8:
POWER_ON = 1 << 0 # 0b00000001
ERROR = 1 << 1 # 0b00000010
BUSY = 1 << 2 # 0b00000100
SLEEP = 1 << 3 # 0b00001000
def __init__(self):
self.reg = 0 # 所有状态位初始为 0
def set(self, flag):
self.reg |= flag
def clear(self, flag):
self.reg &= ~flag
def toggle(self, flag):
self.reg ^= flag
def check(self, flag):
return (self.reg & flag) != 0
def show(self):
return f"{self.reg:08b}" # 显示为 8 位二进制
# 示例使用
reg = Register8()
reg.set(Register8.POWER_ON)
reg.set(Register8.BUSY)
print("状态位:", reg.show()) # 00000101
print("BUSY 状态?", reg.check(Register8.BUSY)) # True
reg.clear(Register8.BUSY)
print("清除 BUSY 后:", reg.show()) # 00000001
四、游戏角色状态示例(组合状态)
class Status:
POISON = 1 << 0 # 中毒
FROZEN = 1 << 1 # 冻结
INVIS = 1 << 2 # 隐身
hero = 0
hero |= Status.POISON | Status.INVIS
print("角色状态:", bin(hero)) # 0b101
# 解除隐身
hero &= ~Status.INVIS
print("解除隐身后:", bin(hero)) # 0b001
五、小结:常见操作模式
目标 | 操作符与策略 | |
---|---|---|
添加状态 | `a | = flag` |
移除状态 | a &= ~flag |
|
翻转状态 | a ^= flag |
|
检查状态 | (a & flag) != 0 |