PYTHON LESSON 034
位运算灯光师
理解位运算的含义,会用 &、|、^、<<、>> 对二进制位进行精准操控。
00 · 学习目标
这一课要解决什么?
学完后,你应该能够
- a & b 按位与:都为 1 才是 1
- a | b 按位或、a ^ b 按位异或
- a << 1 左移乘 2、a >> 1 右移除 2
01 · 核心概念
位运算 & | ^ ~ << >>
位运算 & | ^ ~ << >>:8 盏灯的亮灭可以用 8 个二进制位表示:1 亮 0 灭。0b10101010 就是“亮灭亮灭亮灭亮灭”。位运算让我们用一次计算同时操控所有位,比一盏一盏去按快得多。
GESP Python 3 级 · 位运算GESP Python 3 级 · 数据编码浮点数遵循 IEEE 754 的实现细节,不使用本章的普通整数进制模型直接推导。
02 · 语法与规则
先记住这 3 条,再开始写程序
a & b 按位与:都为 1 才是 1先准确读出这条写法的结构与作用。
a | b 按位或、a ^ b 按位异或换一组最小数据,手工推演一次结果。
a << 1 左移乘 2、a >> 1 右移除 2再用边界值或反例确认它的适用条件。
03 · 完整实例
代码、运行结果和解释放在一起看
# 位运算灯光控制台:8 盏灯装在一个字节里
lights = 0b10101010 # 1 表示亮,0 表示灭
print("初始灯阵:", bin(lights))
# 按位与:只留下对应位置都是 1 的灯
mask = 0b11110000
print("和 11110000 按位与:", bin(lights & mask))
# 按位或:把低四盏灯全部点亮
print("点亮低四位:", bin(lights | 0b00001111))
# 按位异或:把低四盏灯翻转
print("翻转低四位:", bin(lights ^ 0b00001111))
# 左移一位,相当于乘以 2;右移一位,相当于除以 2
print("左移一位:", lights << 1)
print("右移一位:", lights >> 1)初始灯阵: 0b10101010 和 11110000 按位与: 0b10100000 点亮低四位: 0b10101111 翻转低四位: 0b10100101 左移一位: 340 右移一位: 85
0b 开头的写法让你直接在代码里“摆出”二进制,所见即所得。
04 · 逐步理解
每一步只解决一个问题
- 01
一个字节就是一个灯阵
8 盏灯的亮灭可以用 8 个二进制位表示:1 亮 0 灭。0b10101010 就是“亮灭亮灭亮灭亮灭”。位运算让我们用一次计算同时操控所有位,比一盏一盏去按快得多。
lights = 0b10101010 - 02
按位与 &:共同才保留
& 逐位比较:两个对应位都是 1,结果才是 1。和“面具”0b11110000 做与运算,低四位全被 0 盖掉,高四位原样保留——这就是“掩码”的用法:只想看哪几位,就把哪几位设为 1。
print(bin(0b10101010 & 0b11110000)) - 03
按位或 |:有一个就点亮
| 逐位比较:只要有一个是 1,结果就是 1。和 0b00001111 做或运算,低四位被强制点亮,高四位不受影响。想“设置某些位为 1”,用或。
print(bin(0b10101010 | 0b00001111)) - 04
按位异或 ^:不同就变 1
^ 的规则是“相同得 0,不同得 1”。和 0b00001111 异或,低四位全部翻转(亮变灭、灭变亮),高四位不变。想“翻转某些位”,用异或。还有 ~ 按位取反,会把所有位翻转(结果带符号,初学阶段了解即可)。
print(bin(0b10101010 ^ 0b00001111)) - 05
移位:最快速的乘除法
<< 把所有位往左挪,右边补 0:10101010 左移一位相当于 ×2 得 340。>> 往右挪,右边溢出丢弃:相当于 ÷2 得 85。左移 n 位 = ×2 的 n 次方,这是计算机做乘法的“高速通道”。
print(5 << 2) print(80 >> 2) - 06
设计你的灯光秀
试试组合技:先 | 0b00001111 点亮低四位,再 ^ 0b11110000 翻转高四位,观察最终灯阵。位运算看似抽象,其实每一步都能用 bin() 看得清清楚楚。
05 · 练习与检验
自己写出来,才算真正学会
- 1运行程序,看懂每种运算对灯阵的影响
- 2把初始灯阵改成 0b11001100 再观察
- 3用异或翻转高四位试试
- 4验证 5 << 2 是不是等于 5 × 4
06 · 完整知识
继续理解定义、规则和适用边界
第一次学习先完成上面的六个步骤;需要查定义、核对规则、分析误区或理解“为什么”时,再展开对应知识章。
计算机基础进制、整数表示与位运算从位权理解二、八、十六进制,准确使用补码模型、移位、掩码和 Python 大整数。+
正式定义
b 进制数按位权 b⁰、b¹…表示数值。进制只是同一个整数的书写方式;位运算直接处理整数的二进制位。Python 整数精度只受可用内存限制,负数位运算按无限长二进制补码语义定义。
必须掌握
- bin/oct/hex 生成带前缀字符串,int(text, base) 按指定进制解析;0b、0o、0x 是整数字面量前缀。
- 手工转十进制用位权展开,十进制转其他进制可连续除基取余并逆序。
- & 取共同为 1 的位,| 合并置位,^ 标记不同位,~x 等于 -x-1。
- x << k 相当于 x * 2**k;对非负整数 x >> k 相当于 x // 2**k。
- 掩码可检测、设置、清除或翻转特定位;位编号通常从最低位 0 开始。
- 固定字长语言的溢出和 Python 大整数行为不同,题目必须明确字长和有无符号。
常见误区
- 把进制字符串当成不同数值类型
- 忘记位编号从 0 开始
- 照搬固定 32 位溢出结论到 Python
- 对负数右移套用无符号模型
适用边界
- 浮点数遵循 IEEE 754 的实现细节,不使用本章的普通整数进制模型直接推导。
- 字符编码把字符映射到整数,但编码知识与整数进制书写是两个不同层次。
Python 基础运算符、表达式与优先级完整区分算术、比较、逻辑、成员、身份和位运算,并用优先级表消除歧义。+
正式定义
表达式求值得到一个值。运算符规定如何组合操作数;当一个表达式含多个运算符时,优先级和结合方向决定求值顺序,括号可以明确改变顺序。
必须掌握
- / 总是得到浮点结果;// 是向负无穷方向取整的整除;% 与 // 满足 a == (a // b) * b + a % b。
- 比较可以链式书写,如 0 <= x < 10;and/or 会短路并返回最后求值的操作数,不一定返回 bool。
- == 比较值是否相等,is 比较是否为同一个对象;判断 None 应写 is None。
- in/not in 做成员测试;对 dict 测试的是键。
- 位运算作用于整数的二进制位;负整数按无限长二进制补码语义理解。
- 复杂表达式即使能靠优先级正确运行,也应使用括号表达意图。
常见误区
- 把 // 当成简单截断
- 用 is 比较数字或字符串的值
- 忘记 and 的优先级高于 or
- 连续位移、比较和逻辑运算却不加括号
适用边界
- 浮点数比较受二进制表示误差影响,需要按问题选择容差。
- 运算符可由自定义类重载,因此相同符号对不同类型可能有不同语义。
编码与文本ASCII、Unicode 与字符编码完整表完整查阅标准 ASCII 0–127,并理解 Unicode、编码方案与 Python 字符串之间的关系。+
正式定义
标准 ASCII 是 7 位字符编码,只定义十进制 0–127:0–31 与 127 是控制字符,32 是空格,33–126 是可打印字符。Unicode 为字符分配码点,UTF-8/UTF-16 是把码点编码成字节的方案;Unicode 的前 128 个码点与 ASCII 一致。
必须掌握
- 数字字符 '0'–'9' 是 48–57,大写字母 'A'–'Z' 是 65–90,小写字母 'a'–'z' 是 97–122。
- ord(ch) 返回单个 Unicode 字符的码点;chr(n) 返回对应码点的字符,它们不限于 ASCII。
- 字符串比较按 Unicode 码点逐项进行;大小写转换应优先使用 lower()/upper(),不要把“相差 32”推广到所有文字。
- str 是字符序列,bytes 是 0–255 的字节序列;encode() 从文字得到字节,decode() 从字节恢复文字。
- 所谓“扩展 ASCII”没有唯一标准,128–255 的含义取决于代码页,不能当成标准 ASCII 表的一部分。
- 换行符 LF 是 10,回车符 CR 是 13;Windows 文本常见 CRLF,跨平台读写要让文本模式正确处理。
常见误区
- 把 ASCII 说成所有字符的统一编号
- 认为 ord() 只能处理 ASCII
- 把字符个数等同于 UTF-8 字节数
- 把某个代码页的 128–255 当成统一的扩展 ASCII
适用边界
- 本页给出完整标准 ASCII 0–127;Unicode 有十多万个已分配字符,不适合平铺成一张儿童课程长表,应按码点和字符数据库检索。
- “扩展 ASCII”没有唯一标准,128–255 的解释必须同时注明代码页;字符显示还依赖字体,有合法码点也不等于当前字体一定有对应字形。
工程能力异常、文件、测试与调试读懂报错、缩小问题、设计测试,并安全地打开、读取和关闭文本文件。+
正式定义
异常是在运行期间表示错误或特殊情况的对象。调试是用可复现输入和证据定位实际行为与预期行为差异的过程;文件对象连接程序与持久化字节数据。
必须掌握
- 先读 traceback 最后一行的异常类型与消息,再从最靠近自己代码的栈帧向上追踪。
- try 只包可能失败的最小代码;except 捕获具体异常;else 处理成功路径;finally 做必需清理。
- raise 主动报告不满足的前置条件;assert 用于开发期内部假设,不用于校验不可信用户输入。
- with open(...) as file 会在退出代码块时可靠关闭文件。文本模式必须明确编码,本站统一推荐 encoding='utf-8'。
- 测试至少包含正常值、边界值、空数据、极端值和反例;每个测试只应有明确目的。
- 定位错误时一次只改一个假设,保留能稳定复现问题的最小输入。
常见误区
- 使用 except: 吞掉所有错误
- 只测题目样例就认为程序正确
- 文本文件不写 encoding
- 修复报错表象却不验证根因
适用边界
- 在线判题的学生代码由独立 Worker 执行;文件系统、网络和资源权限必须受平台限制。
- 二进制文件、JSON/CSV 和数据库各有专门格式与错误处理方式,不能按普通文本随意拆分。
完成检查