Python 中数据的位运算和状态编码(掩码)详解
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 == 1print(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 = 0while n:n &= (n - 1)count += 1return countprint(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) != 0print("有写权限?", has_permission(perm, WRITE)) # False
print("有读权限?", has_permission(perm, READ)) # True# 移除权限(与取反)
perm &= ~READ
print(f"移除读权限后: {bin(perm)}") # 0b001
二、使用枚举构建权限系统(更清晰)
from enum import IntFlagclass Permission(IntFlag):READ = 4WRITE = 2EXEC = 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 # 0b00000001ERROR = 1 << 1 # 0b00000010BUSY = 1 << 2 # 0b00000100SLEEP = 1 << 3 # 0b00001000def __init__(self):self.reg = 0 # 所有状态位初始为 0def set(self, flag):self.reg |= flagdef clear(self, flag):self.reg &= ~flagdef toggle(self, flag):self.reg ^= flagdef check(self, flag):return (self.reg & flag) != 0def show(self):return f"{self.reg:08b}" # 显示为 8 位二进制# 示例使用
reg = Register8()
reg.set(Register8.POWER_ON)
reg.set(Register8.BUSY)print("状态位:", reg.show()) # 00000101print("BUSY 状态?", reg.check(Register8.BUSY)) # Truereg.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 |