尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

012、运算符优先级与结合律:那些让你查半天 bug 的表达顺序

012、运算符优先级与结合律:那些让你查半天 bug 的表达顺序
📅 发布时间:2026/6/22 20:07:26

012、运算符优先级与结合律:那些让你查半天 bug 的表达顺序

上周帮同事排查一个线上数据统计的 bug,场景很简单:计算用户活跃度得分,公式是score = a + b * c > d and e or f。同事信誓旦旦说逻辑没问题,结果跑出来的数据全是 0 和 1 的极端值,完全不符合预期。我盯着这行代码看了三秒,直接说:“你少写括号了。”他不信,我让他打印中间结果,果然a + b * c先算乘法,然后和d比较,再和and/or搅在一起——整个表达式的求值顺序完全不是他脑子里想的那样。

这种坑,我敢说每个 Python 开发者都踩过,区别只是你花了多久才意识到问题出在运算符优先级上。

优先级表:不是让你背的,是让你查的

Python 的运算符优先级从高到低大致是:幂运算 > 一元运算符 > 算术运算符 > 移位运算符 > 位运算符 > 比较运算符 > 赋值运算符 > 身份/成员运算符 > 逻辑运算符。但说实话,正常人谁记得住<<和&谁优先级高?我写了十年 Python,每次遇到位运算和逻辑运算混用,第一反应还是去翻文档或者直接加括号。

真正需要刻在脑子里的,是那几个最容易出问题的优先级陷阱:

算术运算符:* / // %高于+ -,这个小学都学过,但很多人写2 + 3 * 4以为结果是 20,结果出来 14 才恍然大悟。别笑,我见过生产代码里有人写total = price + tax * quantity,结果税被乘了数量,价格反而只加了一次。

比较运算符:所有比较运算符(== != < > <= >=)优先级相同,且低于算术运算符。这意味着a + b > c + d等价于(a + b) > (c + d),这没问题。但坑在于链式比较:a < b < c在 Python 里是合法的,等价于a < b and b < c。如果你写a < b == c,它会被解释为a < b and b == c,而不是(a < b) == c。这里踩过坑的人举个手。

逻辑运算符:not>and>or。这是 Python 里最经典的优先级陷阱。not a and b等价于(not a) and b,而不是not (a and b)。a or b and c等价于a or (b and c),因为and优先级高于or。很多人写条件判断时,脑子里想的是“如果 a 为真或者 b 和 c 都为真”,结果写出来if a or b and c,实际执行的是“如果 a 为真,或者 b 和 c 都为真”。大多数情况下这恰好是你想要的,但一旦逻辑复杂起来,这就是 bug 的温床。

结合律:从左到右还是从右到左?

大多数运算符是左结合的,即从左到右计算。但有两个例外:

赋值运算符是右结合的:a = b = c = 0等价于a = (b = (c = 0)),从右往左赋值。这个好理解,因为你要先算出右边的值才能赋给左边。

幂运算符**也是右结合的:2 ** 3 ** 2等价于2 ** (3 ** 2),结果是 512 而不是 64。这里踩过坑的人应该不少,因为数学上幂运算通常是从左到右的,但 Python 选择了从右到左,和数学约定一致(因为a^{b^c} = a^{(b^c)})。

比较运算符的链式比较其实也是一种特殊的结合方式:a < b < c不是简单的从左到右或从右到左,而是展开成a < b and b < c,中间变量b只计算一次。这个特性有时候很香,比如写if 0 < x < 10比if x > 0 and x < 10优雅得多。但别滥用,a < b > c这种写法虽然合法,但可读性极差,别这样写。

那些年我查过的“表达式 bug”

案例一:条件赋值陷阱

# 别这样写result=aifconditionelseb+c

你以为else后面是b + c,实际上if-else条件表达式的优先级比+低?不对,条件表达式的优先级其实比+低,所以a if condition else b + c等价于a if condition else (b + c),这恰好是你想要的。但如果你写a + b if condition else c,它等价于(a + b) if condition else c,也没问题。真正坑的是嵌套条件表达式:

# 这里踩过坑result=aifcond1elsebifcond2elsec

这等价于a if cond1 else (b if cond2 else c),因为条件表达式是右结合的。如果你想要的是(a if cond1 else b) if cond2 else c,必须加括号。

案例二:位运算与比较运算混用

# 别这样写ifflags&0x01==0x01:

你以为这是“如果 flags 的第一位为 1”,实际上==优先级高于&,所以它等价于flags & (0x01 == 0x01),即flags & True,而True在 Python 里等于 1,所以实际上是在检查 flags 的最低位是否为 1。大多数情况下结果碰巧是对的,但一旦 flags 的值是 2(二进制 10),2 & 1结果是 0,而2 & True也是 0,所以没暴露问题。直到有一天 flags 是 3(二进制 11),3 & 1是 1,3 & True也是 1,依然没暴露。真正出问题的是 flags 是 0 的时候,0 & 1是 0,0 & True也是 0。这个 bug 能潜伏很久,直到你遇到 flags 是 4 的情况——4 & 1是 0,但4 & True是 0,还是没暴露。实际上这个 bug 几乎不可能通过测试发现,因为True等于 1,而& 1和& True在大多数情况下行为一致。但如果你写if flags & 0x02 == 0x02,0x02 == 0x02是True,等价于flags & 1,完全错了。正确写法是if (flags & 0x01) == 0x01。

案例三:逻辑运算与算术运算混用

# 别这样写result=a+bandcord

这个表达式等价于((a + b) and c) or d,因为+优先级高于and,and优先级高于or。如果你想要的是a + (b and c) or d,必须加括号。但说实话,这种写法不管加不加括号,可读性都很差,不如拆成多行。

我的个人经验

  1. 不要相信自己的记忆力。我写了十年 Python,每次遇到复杂的表达式,第一件事是加括号。括号不花钱,但查 bug 的时间很贵。如果你觉得加括号显得自己水平低,那说明你还没被坑够。

  2. 一行代码不要超过一个运算符。这不是说不能写a + b * c,而是说不要写a + b * c > d and e or f这种“一行流”。拆成多行,每行只做一件事,加上注释,三个月后的你会感谢现在的你。

  3. 善用dis模块。当你实在搞不清楚某个表达式的求值顺序时,用dis.dis('你的表达式')看看字节码,Python 解释器会告诉你它到底先算哪个。比如dis.dis('a + b * c')会显示先加载b和c做乘法,再加载a做加法,一目了然。

  4. 写单元测试时,专门测试边界表达式。比如0 and something、1 or something、not 0这些短路求值的情况,确保你的逻辑在边界条件下依然正确。

  5. 代码审查时,看到没有括号的复杂表达式直接打回。这不是吹毛求疵,这是团队规范。我所在的团队有一条不成文的规定:任何包含两个以上不同优先级运算符的表达式,必须加括号。这条规定救了我们无数次。

最后说一句,运算符优先级不是用来炫技的,是用来避免 bug 的。如果你不确定,加括号。如果你觉得加括号丑,那说明你的表达式本身就该重构了。

相关新闻

  • 3分钟上手Python弹幕神器:blivedm让B站直播数据获取变得如此简单!
  • 2026北京二手包包回收哪家价格高朝阳区国贸大厦毓典寄卖行全城上门回收 - 米諾
  • SSL页面缓存配置漏洞:原理、扫描与修复实战指南

最新新闻

  • Mermaid Live Editor:3步掌握零代码图表设计的终极神器
  • Angular NgModule 核心机制深度解析:declarations、imports、exports、providers
  • RPG Maker资源解密终极指南:解锁游戏创作新境界
  • 阿克苏甲级安全门 - 米諾
  • 从零上手高压电机控制:HVP-KV31F120M平台实战指南
  • 2026年过炉托盘加工厂选型参考:领域内代表性企业解析 - 资讯快报

日新闻

  • 2026速览惠州叛逆青少年学校前十大排名名单出炉 - 武汉中职最新信息发布
  • 2026上饶白蚁消杀哪家好?15年本土2大权威白蚁防治公司推荐(金盾虫控/青蚁卫士) - 我叫一
  • 天龙八部单机版终极数据管理工具:5个技巧快速掌握游戏数据编辑

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号