首页 / 资讯中心 / 文章详情

Python运算符全攻略:从基础语法到面试易错点一网打尽

Python运算符全攻略:从基础语法到面试易错点一网打尽 ★ FEATURED ARTICLE
把“运算符”这一章复习得明明白白其实比想象中更能拉开差距。很多人在学Python时觉得这个部分太基础扫两眼就过去了结果一到笔试、机试或者面试问答环节被//和%负数取模、and/or的返回值、is与的区别这些问题按在地上摩擦。这篇文章就是一份专门针对操作符的复习资料把常用的算术、比较、赋值、逻辑、成员、身份、位运算这些类别串成一条线同时配上大量习题和答案解析帮助正在复习Python、准备考试或者想自查基础的朋友把这块彻底吃透。1. 先从整体盘一遍Python运算符家族里都有谁1.1 七个大类各自的定位复习任何知识点的第一步一定是先建立起全局框架不要上来就抠某个细节。Python里的运算符按功能划分通常可以分成七大家族算术运算符、比较运算符、赋值运算符、逻辑运算符、成员运算符、身份运算符、位运算符。这七个家族里日常写代码用得最勤的是前六个位运算符相对小众但它在处理标志位、权限组合、二进制掩码时会非常方便。下面先快速过一遍每类的核心职责算术运算符、-、*、/、//、%、**负责数值计算。比较运算符、!、、、、返回布尔值True或False。赋值运算符、、-、*、/、//、%、**、、|等把右边的计算结果赋给左边变量。逻辑运算符and、or、not负责布尔逻辑组合注意它们的返回值不一定是布尔值。成员运算符in、not in判断一个值是否存在于某个容器中。身份运算符is、is not判断两个变量是否指向同一个对象。位运算符、|、^、~、、按二进制位进行计算。复习到这里我建议你顺手做一个动作打开Python交互环境把上面这些运算符挨个敲一遍不要只是看。看十遍不如敲一遍这是老生常谈但对于运算符这种语法层面的知识动手验证留下的记忆远比阅读文字深刻得多。1.2 版本更迭带来的新旧差异复习时还要注意Python版本之间的差异。最常见的是除法运算的变迁Python 2里两个整数相除如果除不尽会直接取整数部分比如5 / 2得到2所以以前的代码里经常看到有人写float(a) / b来强制转成浮点数除法。到了Python 3/统一返回浮点结果5 / 2得到2.5而整数除法交给了//运算符。这个变化影响了非常多的老代码现在很多公司内部的遗留系统里还能看到类似from __future__ import division的写法目的就是让Python 2也采用Python 3的除法语义。你复习时不需要死记这段历史但至少要明白遇到//走的是向下取整遇到/得到的是浮点数这两者在笔试里是高频出题点。我遇到过不少同学在回答“7 // 2等于多少”时自信满满写下3.5这就是没分清两个除法运算符的区别。下面这个表可以直接保存表达式Python 2行为Python 3行为5 / 22整数除法2.55 // 222-5 // 2-2-3注意最后一行Python 3里-5 // 2的答案是-3这是向下取整的结果不是向零取整稍后会具体展开。2. 算术运算和赋值运算藏在小学题里的失分点2.1 除法三兄弟/、//、%在正负数面前的脾气算术运算符看着像小学数学实际上最会“暗算”人。先说//它的完整名字叫“整除”但准确理解应该是“向下取整的除法”。很多教材里解释成“取商的整数部分”这个说法在正数范围没问题遇到负数就不准确了。7 // 2结果是3因为2进7进3次余1。-7 // 2结果是-4因为向下取整-3.5的下一个整数是-4。7 // -2结果是-4同理-3.5向下取整得到-4。有同学习惯把//理解成“丢掉小数部分”这在负数场景会翻车。丢掉小数部分其实是向零取整比如-7 // 2向零取整应该是-3但Python算出来是-4。它们的区别就体现在这里面试官特别爱拿这道题试人。再来看%取模运算符。其他多数编程语言里取模结果的符号跟着被除数走但Python不一样它遵循的规则是a % b的结果符号总是和除数b一致。举个例子print(7 % 3) # 输出 1 print(-7 % 3) # 输出 2 print(7 % -3) # 输出 -2 print(-7 % -3) # 输出 -1这里真正理解的关键是公式a (a // b) * b a % b。这个公式在Python里恒成立。比如-7 // 3 -3那么(-3) * 3 -9要让等式成立a % b就必须等于2。理解了这条公式负数取模就再也不会记反了。%的实用价值也非常高判断奇偶用的是x % 2分页时计算小标偏移用的是index % page_size循环队列里绕圈定位靠的也是取模运算。2.2 增强赋值与链式赋值写法省了坑一个没少赋值运算符里、-、*这类增强赋值用法很普遍但要对可变对象提高警惕。对于不可变对象比如整数、字符串、元组a b等价于a a b都是生成一个新对象再绑定到变量名上。但对象是可变类型时两者会出现微妙差异a [1, 2, 3] a [4] # 等价于 a.extend([4])原地修改 print(a) # [1, 2, 3, 4] b [1, 2, 3] b b [4] # 生成新列表并重新绑定 print(b) # [1, 2, 3, 4]如果只看最终打印结果这两个操作没有区别但如果你把同一个列表通过两个变量名同时引用差异就会暴露出来x [1, 2, 3] y x x [4] print(y) # [1, 2, 3, 4]x和y指向同一个列表对象原地修改后y也变了 x [1, 2, 3] y x x x [4] print(y) # [1, 2, 3]x重新绑定了新列表y不受影响这个知识点在复习时可以结合可变对象、引用的概念一起理解它也是Python入门阶段最容易出现的隐蔽bug之一。链式赋值也要注意a b 0表示的是一口气把0赋给a和b它并不会因为写成链式而产生复制对象的操作。2.3 浮点数为什么0.1加0.2不等于0.3这是算术运算里最出名的坑很多复习到运算符的人才第一次发现这个问题print(0.1 0.2) # 输出 0.30000000000000004原因在于浮点数在计算机里用二进制存储0.1和0.2转成二进制后都是无限循环小数存储时只能截取有限位误差就产生了。这是浮点数表示的本质问题不是Python独有的C、Java、JavaScript都会遇到。实际开发中需要精确计算金额时不要直接用浮点数应该用Decimal或把金额换算成最小整数单位。笔试里如果遇到“0.10.2结果是什么”这种题你要写的答案是0.30000000000000004不是0.3。复习代码时可选用round或格式化字符串来控制显示精度。3. 比较、逻辑、成员与身份运算符四个容易被轻视的角色3.1 与is值相等和对象相同是两回事比较运算符的核心返回值是布尔值但真正容易丢分的是和is的选择。比较的是两个对象的值是否相等is比较的是两个引用是否指向内存中的同一个对象。a [1, 2, 3] b [1, 2, 3] print(a b) # True值逐项相等 print(a is b) # False两个不同的列表对象这里有个经典陷阱小整数对象驻留机制。Python为了性能会把一些频繁使用的小整数提前创建好放在内存里所以x 256 y 256 print(x is y) # True x 257 y 257 print(x is y) # 因环境而异通常是False又如True 1在Python中结果也是True因为布尔值是int子类它们在数值比较上相等但用is比较就不是同一个对象。判断None时请使用is None或is not None这是Python官方推荐的风格因为None是单例对象不存在多个实例。3.2 逻辑运算符的短路机制与返回值陷阱逻辑运算符and、or在很多教程里被简单描述成“与、或、非”但它们的另一个重要特点是短路求值以及返回操作数本身。and的求值规则是如果左边为假直接返回左边对象右边的代码根本不会执行如果左边为真继续求值右边并把右边对象作为整体表达式的返回值。or相反如果左边为真直接返回左边对象如果左边为假继续求值右边并返回右边对象。看代码print(0 and 10) # 0第一个假值直接返回 print(3 and 5) # 5两边都为真时返回最后一个真值 print(0 or 7) # 7左边为假继续看右边 print(3 or 7) # 3左边为真直接返回这带来的实战好处非常明显。比如从配置里取值时name input_name or 默认值如果用户没有输入input_name为空字符串假值则返回默认值。再比如判空时data get_result() or fallback_data这就是利用短路机制写出的非常简洁的安全取值逻辑。短板效应也要注意不能用and和or返回的非布尔结果直接替代布尔判断比如a and b返回的可能是b本身不是严格的True或False如果需要严格布尔结果应该用bool()显式转换或者用all()这类函数。3.3 成员运算符和链条式比较的妙用in运算符用来判断元素是否存在于容器中它的底层调用是容器的__contains__方法。对不同容器性能差异很大把列表改成集合或字典后in的复杂度会从O(n)降到O(1)这个细节在算法题里是优化点。print(ell in hello) # True字符串子串判断 print(3 in [1, 2, 3, 4]) # True列表判断 print(name in {name: A}) # True字典默认判断键是否存在比较运算符还支持一种写法链式比较。Python允许把多个比较串起来表达数学里的区间范围。age 25 print(18 age 60) # True等价于 18 age and age 60这条特性的阅读体验远高于写成两个比较再用and连接同时也是笔试中容易忽略的语法点。链式比较里每个表达式只计算一次如果有函数调用参与会比较微妙但初学阶段先掌握最基础的区间判断用法就够了。4. 运算符优先级一张表解决九成争议4.1 从高到低速查表运算符优先级是“复习效率放大器”优先级判断对了读代码和写代码都会顺畅很多。以下是从高到低的常用优先级顺序考试时背这一列基本够用优先级运算符说明最高**幂运算高x-x~x一元正负号、按位取反中高*///%算术乘除模中高-算术加减中位移中低^低!比较更低not逻辑非再低and逻辑与很低or逻辑或最低等赋值这里面最重要的两组关系要单独记一是**优先级高于一元负号二是and的优先级高于or。4.2 三个高频翻车现场先看幂运算与负号的组合。由于幂运算优先级高于一元运算负号所以print(-2 ** 2) # -4先算2**24再取负 print((-2) ** 2) # 4括号改变顺序这个题命中率极高几乎每次复习答疑都有人问。如果你想要“负二的平方”一定要用括号否则结果会反直觉。再看逻辑运算符的混搭。因为and优先于or所以下面这个表达式result True or False and False在多数人第一反应里是从左往右算即(True or False)得到True再用True和False做and最后得到False。但Python真实计算顺序是True or (False and False)False and False为FalseTrue or False返回True。自己动手跑一遍会发现结果与直觉不同。这个翻车现场就是优先级导致的。第三个翻车点是混合使用not与比较运算符。not的优先级低于所有比较运算符所以not a b实际上表示的是not (a b)这通常符合意图。但写复杂了之后比如not a in b、not a is b这种风格容易让读代码的人脑壳疼规范做法是把否定直接放到比较符上a not in b、a is not b。4.3 我的个人建议关于优先级我的做法向来简单粗暴能加括号的地方就加括号不要跟优先级硬刚。Python里括号不会带来性能损失也不会降低代码技术含量反而能明确表达你的意图让后续维护这段代码的人少掉几根头发。考试时提前把优先级表过一遍写代码时用括号兜底这样就算记不清某几条冷门优先级也不会出错。真正需要熟练到不用查表的是本文前面提到的那几条高频规则and高于or、**高于负号、算术高于比较、比较高于逻辑。把这些记住日常代码里95%以上的表达式都能正确判断。5. 习题实战从易到难把这章真正吃透复习操作符不能只看不练题目是最好的检验方式。下面这些习题按难度递进每一道都覆盖了前面章节里的某个易错点。建议先独立写出答案再对照解析不要边看答案边做题那样无效。5.1 热身题第一题print(10 / 4) print(10 // 4) print(10 % 4)解析10 / 4是浮点数除法结果为2.510 // 4向下取整结果为210 % 4取余数结果为2。这道题只要记住Python 3里/一定是小数除法就能答对。第二题x 5 x 3 x * 2 print(x)解析先执行x 5 3得到8再执行x 8 * 2得到16。注意增强赋值的操作顺序是先把右端结果算出来再更新变量。第三题print(2 ** 3 ** 2)解析幂运算符是右结合的2 ** 3 ** 2等价于2 ** (3 ** 2)也就是2 ** 9结果为512。如果从左往右算(2**3)**2是8**264两种都有人猜但Python遵循右结合。这道题很有迷惑性建议重点标记。5.2 进阶题第四题print(5 and 0 and 8) print(0 or 4 or 9) print(not 0)解析and遇到假值就停下5 and 0时由于0是假右边结果直接返回0后面的and 8不会执行所以结果是0or遇到真值停下0 or 4返回4后面的9不再看结果是4not 0因为0为假取反后为True。第五题a [1, 2] b a b.append(3) print(a) print(a is b)解析b a让两个变量指向同一个列表对象所以b.append(3)同样会改变a指向的列表a是[1, 2, 3]两个变量指向同一个对象a is b返回True。这个题目复习的是对象引用和可变类型属于高频考核点。第六题print(1 3 5) print(5 3 5)解析第一条是链式比较等价于1 3 and 3 5True第二条等价于5 3 and 3 5后一个条件不成立False。这个题就是专门考链式比较的写法。5.3 挑战题第七题n 7 print(-n // 2) print(-n % 2)解析-7 // 2向下取整-3.5向下取整数为-4-7 % 2结果为1因为符号与除数一致正数也可以通过公式计算-7 -4 * 2 1所以余数为1。这道题把整除和取模的负数场景一次性考完出错率很高。第八题nums [0, 1, 2, 3, 4] result nums[1] or nums[2] and nums[3] print(result)解析由于and优先级高于or表达式等价于nums[1] or (nums[2] and nums[3])。先看nums[2] and nums[3]2和3都是非0真值所以返回最后一个真值3再看nums[1] or 3左边是1属于真值直接返回1。最终结果是1。第九题print(6 2) print(8 2) print(5 3) print(5 | 3)解析6 2表示二进制左移两位6的二进制是110左移两位变成11000十进制248 21000右移两位变成10十进制25 3101与011按位与结果是001十进制15 | 3101与011按位或结果是111十进制7。位运算平时用得少但笔试偶尔出现至少要知道移位和按位与或的几何意义。这些题做完后再遇到运算符相关的选择、填空、判断简化题基本都能一眼看穿出题人的考点。做题时不要只追答案要能说出每一步的求值顺序和依据。6. 复习方法论与易错点清单6.1 复习的正确姿势光看文章和例题还不够我建议复习操作符时自己动手做这样三件事第一把前面章节里提到的所有运算符写进一个脚本文件输出关键结果然后和文中对照。这个“自己敲一遍”的过程会把零散知识串联起来形成肌肉记忆。代码哪怕和示例一模一样也要自己敲因为你在键盘上犯的每一个错都是最好的老师。第二针对容易混淆的二元组做对比实验。比如把//和/分别用在正数、负数、零上观察规律把%用在正负组合的各组例子里把and、or分别接True、False、0、1、空串。做成一个小表格贴在复习笔记里比临考前翻教材高效得多。第三尝试给每一类运算符写一个“实际工作场景”。比如算术运算符用在做数据统计分析取模运算用在环形队列定位成员运算符用在白名单校验逻辑运算符用在参数默认值兜底位运算符用在权限位合并。有了场景支撑复习的枯燥感会明显下降对运算符的理解也会从“语法规则”上升到“工具手段”的层面。6.2 易错点速查清单把上面所有内容浓缩成一张速查表方便考前过一遍易错点正确答案记忆法-7 // 2向下取整结果是-4不是-3-7 % 3余数符号与除数一致结果是22 ** 3 ** 2幂运算右结合结果是512-2 ** 2幂优先于负号结果是-4True or False and Falseand优先于or结果为True0 and 8返回第一个假值03 or 8返回第一个真值3与is值相等用对象相同用is0.1 0.2浮点误差不要写0.3a [1]与a a [1]前者原地修改后者重新绑定18 age 60链式比较合法一步判断区间我个人复习时的一项经验是把每次做错的题目标记出来隔天再重做一遍而不是把整章从头再翻一遍。这样做的好处是时间都花在真正的薄弱点上效率比盲目刷题高很多。运算符这块知识本身不难难的是愿不愿意在“基础”两个字上多花一些耐心把每一个反直觉的角落都磨平。如果你复习到后面发现某几个点还是容易混那就说明练得还不够回到交互环境里把它们再跑一遍让代码告诉你答案这比反复看任何笔记都有用。
阅读完成 · 觉得有帮助?
咨询建站