
学 Python 的人大多都有过这样一段经历语法规则背得滚瓜烂熟一到刷题反而被0.1 0.2 0.3这类操作符问题卡住。我接触过不少刚起步的 Python 学习者聊下来发现大家并不是不会用操作符而是从来没有系统地把这个模块盘一遍。这篇内容就是一次面向 Python 常用操作符的完整复习顺手配上一组习题帮你把零散的知识点串起来。不管你是刚学完基础语法准备刷题的新手还是想快速回顾知识点的在职开发者都能直接把它当成一份复习手册来用。1. 操作符全景图先弄清楚有哪些再谈怎么用1.1 常用操作符分类速览Python 的操作符数量不算少但真正高频使用的也就那么几类。复习的第一步不是急着做题而是把整个家族先摆出来看一眼。分类常见操作符典型用途算术操作符-*///%**数值运算比较操作符!比较大小、是否相等赋值操作符-*///%**给变量绑定新值逻辑操作符andornot组合多个条件位操作符|^~二进制位的操作身份操作符isis not判断是不是同一个对象成员操作符innot in判断某项是否在容器里这张表看完你至少有了一个总印象操作符不只是“加减乘除”它还负责比较、赋值、逻辑组合、位运算、对象身份判断、容器成员判断。平时写代码时真正出问题的地方往往不是算术而是身份、成员、逻辑这几类在混合场景里的隐性规则。1.2 为什么写代码时总在操作符上翻车操作符本身语法简单难的是它背后隐藏的求值规则。我总结常见的翻车原因有三个。第一个是隐式类型转换。Python 是动态类型但不同操作符对类型的要求完全不同。1 1会直接抛TypeError而1 1.0却返回True。同一个用在数字上叫加法用在字符串上叫拼接用在列表上还叫拼接但类型不对就立刻报错。第二个是返回值不总是你直觉里的那个类型。and和or返回的不一定是布尔值可能是参与运算的某个原对象//和%在负数场景下的结果也很有迷惑性。这个下面会重点展开。第三个是操作符优先级记不住却又不肯加括号。多个操作符混在一起比如2 ** 3 ** 2你到底是从左算还是从右算很多报错和隐形 bug 就是这么来的。所以我一直建议复习操作符时别只看单个操作符的说明要主动去把它放到表达式里观察结果。这也是后面那组练习题存在的原因。2. 算术和比较运算天天用但可能没想明白的细节2.1 算术运算符的隐藏规则大多数人对-*/的理解没问题但//、%、**这几个需要额外记忆。/永远返回浮点数。即使8 / 4结果也会是2.0不是2。如果需要整数结果就要显式用//。很多人一开始把//当成“整除后自动转 int”严格地说它是“向下取整除法”不是“截断除法”。负数场景就是重灾区。-7 // 3在 Python 里等于-3因为向下取整结果会取小于等于精确商的最小整数。精确商是-2.333...向下取整就是-3。在其他某些语言里这个结果可能是-2所以千万别用别的语言的习惯去猜 Python。%取模运算的结果符号和除数保持一致。想看一个实例-7 % 3结果是2而7 % -3结果是-2。它的定义公式是a % b a - (a // b) * b用-7 % 3验证一下-7 - (-3 * 3) -7 9 2。这个公式不需要背但建议你在做题时亲手代入一次能极大减少对负号取模的恐惧。**是幂运算注意它和负号的关系。-2 ** 2在 Python 里结果是-4不是4。因为幂运算优先级高于一元负号实际计算的是-(2 ** 2)。如果就是想表达(-2) ** 2必须写括号。另外浮点精度问题必须重视。0.1 0.2 0.3结果为False这是无数人掉过的坑。原因在于浮点数在计算机内部是以二进制存储的0.1和0.2无法被二进制精确表示计算结果是0.30000000000000004。实战中如果要比较浮点数建议用round()设置精度或者用一个很小的误差范围来比较。print(0.1 0.2) # 0.30000000000000004 print(round(0.1 0.2, 1) 0.3) # True2.2 比较运算符与链式比较比较运算符看着简单但 Python 有一种独特的写法容易让人懵链式比较。例如1 2 True很多人的第一反应是(1 2) True也就是True True最终结果是True。但 Python 实际把它当成链式比较处理等价于1 2 and 2 True2 True显然是False所以整个表达式的最终结果是False。这是一个很经典的坑出在选择题里几乎一踩一个准。链式比较的好处是代码更接近数学表达。比如判断一个数是否在某个区间可以写成score 85 if 60 score 100: print(达标)这是 Python 非常实用的特性。但在复习阶段一定要记住链式比较中间的每个比较表达式是两两组合而不是“从左往右算完之后再跟下一个比”。3. 逻辑运算符返回值不只是 True 和 False3.1 and、or、not 到底返回什么逻辑运算符and和or是布尔运算里最容易出题的知识点。它们不是简单地返回True或False而是遵循短路求值规则返回某个操作数本身。规则如下and如果第一个操作数为假值返回第一个操作数否则返回第二个操作数。or如果第一个操作数为真值返回第一个操作数否则返回第二个操作数。not总是返回布尔值把原结果反转。看起来抽象用代码看就很直观print(3 and 4) # 4 print(0 and 4) # 0 print(0 or 5) # 5 print(3 or 5) # 3 print(not hello) # False3 and 4为什么是4因为3是真值and继续判断第二个操作数于是返回4。0 or 5为什么是5因为0是假值or需要看第二个操作数于是返回5。这里还有一个经常被忽略的点Python 的假值不只是False和0还包括None、空字符串、空列表[]、空字典{}、空集合set()等。只要是“空”的东西在逻辑判断中都被当作假值处理。3.2 短路求值的实战意义短路求值不只是理论概念代码里处处都在用。def check(): print(check 被调用) return True False and check() # check 不会被执行 True or check() # check 不会被执行因为第一个操作数已经决定了整体结果Python 就不再求值第二个操作数。这在性能上有意义在代码健壮性上更有意义。最常见的实用写法是防御式访问比如判断一个列表不为空再取最后一个元素不写嵌套 if而是直接用anddata [1, 2, 3] last data and data[-1] # 结果是 3如果data是空列表data and data[-1]会直接返回空列表不会执行data[-1]因此不会报IndexError。这种写法很 Pythonic但前提是你真正理解了短路求值否则读到别人的代码会一头雾水。4. 赋值与身份运算理解变量到底是什么4.1 赋值运算符与变量的本质赋值运算符本身没太多可说把右侧对象绑定到左侧变量名。复合赋值运算符则是先计算后赋值x 10 x 5 # 等价于 x x 5结果是 15 x // 2 # 等价于 x x // 2结果是 7 x ** 2 # 等价于 x x ** 2结果是 49但真正值得关注的是绑定的不是“值”而是“对象引用”。一个变量名只是一个指向对象的标签。看下面这段a [1, 2, 3] b a b.append(4) print(a) # [1, 2, 3, 4]b和a指向同一个列表对象所以b.append(4)修改的是a也在引用的那个列表。初学者很容易以为“我只是复制了一份 b怎么 a 也变了”原因就在这。如果确实想要一个独立的副本应该用切片或copy()b a[:] # 或 b a.copy() b.append(4) print(a) # [1, 2, 3]不受影响基本类型如整数、字符串、浮点数不存在这个问题因为它们是不可变对象任何操作产生新对象。但列表、字典、集合这类可变对象就要特别小心。4.2 海象运算符赋值表达式:是 Python 3.8 引入的赋值表达式通常叫“海象运算符”。它的意义是在表达式中同时完成赋值和返回值两个动作。典型场景是把“先计算再判断”的代码简化# 不用海象运算符 while True: line input(输入内容) if line : break print(line) # 用海象运算符 while (line : input(输入内容)) ! : print(line)海象运算符最大的坑是很多人不知道该加括号。while line : input(...)这种写法在某些场景会语法错误或改变优先级的解析方式。我的建议是在while和if的条件里使用:一定用括号把整个表达式包起来既保证语法正确也让读者一眼看到“这里既赋值又判断”。4.3 is 和 的区别这是面试和刷题里的高频考点。简单说比较的是内容是否相等is比较的是两个变量是否指向同一个对象。a [1, 2, 3] b [1, 2, 3] print(a b) # True内容相同 print(a is b) # False两个不同对象看起来很简单但有个特殊情况会干扰判断。CPython 解释器对小整数有缓存机制范围一般在-5到256之间这些常用整数在内存中只有一份所以x 100 y 100 print(x is y) # True因为 100 被缓存了 m 257 n 257 print(m is n) # False 或 True取决于解释器对常量的处理不能依赖当你比较变量和某一个具体数值时就算结果恰好是True也不能依赖is来判断整数是否相等。规范写法永远是m n或者直接m is n只在需要判断单例对象时使用比如if result is None: passNone在 Python 里是单例对象所以用is None判断是标准且高效的做法。5. 位运算与成员运算冷门功能也有实战价值5.1 位操作符的使用逻辑位操作符在日常业务代码中出现频率不算高但在算法题、底层开发、图像处理、权限设计等领域相当有用。它操作的是整数的二进制位。按位与、|按位或、^按位异或、~按位取反、左移、右移各有各的规律。拿12 10来说12的二进制是110010的二进制是1010按位与结果是1000也就是十进制的8。12 | 10结果是1110也就是14。12 ^ 10结果是0110也就是6。~x的结果是-x - 1。所以~5是-6~0是-1。这个规则很多初学者会懵但记住公式就行~x -x - 1。左移和右移最直觉的使用是快速乘除 2 的幂print(3 2) # 3 乘以 4结果是 12 print(16 3) # 16 除以 8结果是 2在算法题中位运算常用来做状态压缩和权限标志位。比如一个用户有三种权限可以用三个二进制位表示READ 1 # 0b001 WRITE 2 # 0b010 EXECUTE 4 # 0b100 permission READ | WRITE # 0b011 print(permission READ) # 非 0说明有读权限 print(permission EXECUTE) # 0说明没有执行权限这种写法在配置系统里很常见理解判断是否包含某个位|追加某个位就够了。5.2 成员操作符 in 与 not inin用在字符串、列表、元组、字典、集合中判断某个元素是否存在。print(py in python) # True print(3 in [1, 2, 3]) # True print(a in (b, c)) # False字典的in有个非常重要的细节它判断的是键不是值。info {name: tom, age: 18} print(name in info) # True print(tom in info) # False print(tom in info.values()) # True需要明确访问值这个细节在操作字典时特别容易踩坑。你想判断一个值是否在字典里千万记得用values()而不是直接在字典对象上用in。在列表里使用in的时间复杂度是 O(n)如果数据量大还是应该优先用集合或字典来判断是否存在。6. 操作符优先级让括号成为你的朋友6.1 常用优先级表很多人在刷题时看答案能懂自己一写就错问题多半出在优先级。这里给出一张从高到低排列的常用优先级表建议把它当作复习材料保存。优先级高低操作符高()[]{}、属性访问、函数调用较高**中高一元操作符x-x~x中*///%中低-低较低更低^低|很低!、isis not、innot in极低not极低and最低or注意not的优先级在比较操作符和and之间and高于or。所以not a b等价于not (a b)而不是(not a) b。6.2 优先级误用实例优先级带来的陷阱很多举两个最常见的。第一个是**的右结合性。2 ** 3 ** 2不是从左往右算而是从右往左算等价于2 ** (3 ** 2)结果是2 ** 9 512。如果它真的是从左往右算那就是(2 ** 3) ** 2 8 ** 2 64完全不一样。第二个是not和比较符号混在一起。not 1 1其实结果是False它等价于not (1 1)而不是(not 1) 1。第二种写法里的(not 1) 1是False 1也是False结果虽然一样但内部逻辑完全不同别记混。我的习惯是只要是涉及三种以上的操作符混用的表达式一律写括号。括号不丢人反而是在保护自己和阅读代码的人。很多所谓“一行代码装杯”的写法对维护就是一种负担。你写的是项目不是谜语。7. 十道容易做错的操作符练习题带答案解析7.1 基础题测一测操作符的底线知识题目 17 // 2的结果是多少结果3。解析向下取整除法7 / 2 3.5向下取整得到3。没有坑。题目 27 % -3的结果是多少结果-2。解析取模结果符号与除数一致。除数-3是负数所以结果是负数。用公式7 - (7 // -3) * -37 // -3 -3所以7 - (-3 * -3) 7 - 9 -2。题目 30.1 0.2 0.3的结果是什么结果False。解析二进制无法精确表示部分十进制小数计算结果其实是0.30000000000000004。直接比较浮点数是复习操作符时必踩的第一个坑。题目 41 2 True的结果是什么结果False。解析这是链式比较等价于1 2 and 2 True。2 True为False所以整式为False。如果按(1 2) True算就会错误得到True。题目 52 or 3 and 4的结果是什么结果2。解析优先级上and高于or原式等价于2 or (3 and 4)。2是真值or短路直接返回第一个操作数2。7.2 进阶题混合场景判断题目 63 and abc的结果是什么结果abc。解析3是真值and继续求值第二个操作数返回abc。注意这里返回的是字符串对象不是布尔值。题目 72 ** 3 ** 2的结果是什么结果512。解析幂运算符是右结合等价于2 ** (3 ** 2)等于2 ** 9结果是512。题目 812 10 | 5的结果是什么结果13。解析按优先级高于|先算12 10结果为8再算8 | 5结果为13。注意千万别从左往右直接算否则会得到错误结果。题目 9-2 ** 2的结果是什么结果-4。解析**的优先级高于一元负号等价于-(2 ** 2)结果是-4。如果需要正数结果必须写(-2) ** 2。题目 10下面代码的输出是什么a [] b a c [] print(a is b, a is c, a c)结果True False True。解析b a让b和a指向同一个列表对象所以a is b为True。c []创建了一个新对象所以a is c为False。但两边内容都是空列表所以a c为True。7.3 做题后的复盘思路题目本身不是目的做完之后要能说出“为什么”。我一般建议做三件事。第一把每道错题改成“我能给别人讲明白”的形式。能讲清楚才算真会。第二对所有结果不直观的题目直接在交互式环境里敲一遍看输出是否符合你的预期。如果不符合就把计算拆成多行逐步打印中间结果。比如2 ** 3 ** 2你可以分别打印2 ** 9和(2 ** 3) ** 2看看差异。第三把每道题涉及的优先级、返回类型和对象身份三个维度标出来。and返回对象是维度一**右结合是维度二is与的区别是维度三。刷题刷到最后看的不是单个题目而是这几个维度的交叉组合。8. 复习方法怎么把操作符真正变成自己的东西8.1 用“随手实验法”代替死记硬背操作符规则靠背是背不牢的我的做法是随手实验。打开命令行里的 Python 交互环境像写日记一样把每个操作符配一个奇怪的表达式输进去观察输出。pythonprint(5 // -2) print(-5 % 2) print(abc * 3) print([0] * 3) print({1, 2} {2, 3})这种练习不需要思考“有没有用”重点是让大脑建立“表达式到输出”的直接反射。刷题前先用 10 分钟做这种操作算是对知识点的热脑运动。8.2 实战代码里的三个自查习惯在实际项目里操作符问题往往隐藏得很深。我踩过几次坑之后总结出三个自查习惯。第一浮点数比较一律做精度处理。不要在业务逻辑里写两个 float 的直接相等比较。钱、分数、比例这类数据的比较要么用整数表示要么用round()要么直接用精度更高的方式处理。第二赋值对象可变时立刻想到引用共享。只要把列表或字典赋给新变量并做修改操作就要停下来想想原变量会不会受影响如果不想受影响就用复制而不是直接赋值。第三条件表达式里优先用括号划分层次。if (not a) and (b or c):这种写法看起来啰嗦但绝对比让人猜优先级安全得多。协作开发中代码可读性比“少写两个括号”重要多了。8.3 后续复习可以再扩展的方向操作符复习完以后可以往两个方向继续深入。一个是把操作符和数据结构结合起来复习比如列表的、*、in操作字典的in操作集合的、|、-运算这些都属于操作符知识在容器类型上的延伸。另一个是进入流程控制复习因为条件判断本质上是把比较运算符、逻辑运算符和隐式真假值转换组合在一起。我个人在实际操作中还有一个体会操作符的很多坑只有在你替别人调试代码的时候才记忆最深。看到别人写了一行if a is 1或者value False or 你会本能地觉得不对劲这时候翻开文档查一下印象就真正留住了。所以复习操作符别只刷题多去读读别人的代码试试猜输出再验证这个习惯会让你成长得非常快。