ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Python运算符全解析:从入门避坑到优先级实战

Python运算符全解析:从入门避坑到优先级实战 如果你刚开始学Python,翻来覆去地啃语法教程,我建议你先花点时间把“运算符”这一层打牢。原因很简单:代码里那些看似不起眼的、-、、and、,几乎决定了程序每一步怎么走。我见过太多入门学员,逻辑想明白了,但一写就报错,居然是卡在和用混、优先级看错、整除和取余分不清这些细节上。这篇就把Python运算符一次性讲透,从分类到细节,从原理到避坑,学完顺手敲几行代码,你的Python基础就能扎实一大半。1. 学前准备与运算符家族1.1 为什么说运算符是你绕不开的第一课很多人觉得运算符太简单,无非就是加减乘除,不用专门学。但实际写代码时你会发现,运算符其实是“逻辑表达”的浓缩:判断一个数是否在某个范围、两种条件同时满足、累加计数、判断奇偶、权限位判断……全都离不开运算符。可以说,运算符是用Python描述世界规则的基础语法单元。举个最直白的例子:你想让程序根据年龄判断能否进入网吧,逻辑是“满18岁才放行”。翻译成Python就是age 18。这里是比较运算符;如果要加一个“并且是成年人”,就要用and逻辑运算符。如果这两类运算符不懂,哪怕你背熟了if语法,也写不出一个能跑通的条件判断。所以我的建议是:入门阶段花两三个小时专攻运算符,收益远超你想象。后面学字符串操作、列表切片、循环嵌套、函数返回值,你会发现到处都在用运算符,提前啃透能让后续学习顺畅不少。1.2 一张表认清Python的7类运算符Python里的运算符不止算术那一小撮,官方文档把常用的运算符分成几大类。入门期至少要把前五类混个脸熟:类别常见符号一句话说明算术运算符 - * / // % **做数学计算比较运算符 ! 比较大小,结果是True或False赋值运算符 - * / // % **把右边的值赋给左边逻辑运算符and or not处理布尔逻辑位运算符 | ^ ~ 按二进制位运算成员运算符in not in判断元素是否在序列里身份运算符is is not判断两个对象是否是同一个在这个表里,in你学列表和字符串时会频繁碰到,比如a in abc返回True;is主要用来判断对象身份,新手阶段不用深挖,知道有这个东西即可。1.3 动手前的环境准备如果你还没安装Python,我建议直接去官网(python.org)下载当前稳定的3.x版本。Windows用户在安装时一定要勾选“Add Python to PATH”,这是新手最容易漏的一步,漏了之后在命令行敲python就会提示“不是内部或外部命令”。装好之后打开命令行,输入python,看到提示符就说明环境OK了。或者用VS Code装好Python插件,新建一个.py文件边写边跑。我个人喜欢先在命令行里用交互模式试小表达式,确认结果对了再写进文件,这样学运算符特别方便——敲一行,出结果,立刻反馈。2. 算术运算符全解析:从加减乘除到整除取余2.1 加、减、乘、除:最基础的符号也有细节算术运算符里, - *和数学里用法基本一致,但/要特别注意。在Python 3中,/永远做“真除法”;即使两个整数相除,结果也是浮点数:print(10 / 3) # 3.3333333333333335 print(8 / 4) # 2.0 注意结果不是整数2,而是浮点2.0我遇过不少从C语言或Java转过来的朋友,习惯性以为8 / 4会得到整数2,但Python 3不是这样。如果你确实想得到整数结果,得用整除运算符//。还有一点,不仅能做数字加法,还能拼接字符串、合并列表。比如Hello Python得到Hello Python,[1, 2] [3]得到[1, 2, 3]。这是运算符重载的体现,同一个符号在不同类型上表现不同。但注意不要做“数字字符串”这种操作,比如1 2会直接抛出TypeError,新手经常在这里翻车。2.2 取余和整除:两个看似简单却极其常用的运算符取余运算符%在入门阶段的重要性被严重低估。判断一个数是奇数还是偶数,最基本的写法就是x % 2 0;处理循环队列、日期换算、数字分离时,%都是主力。print(10 % 3) # 1 print(-10 % 3) # 2 注意结果不是-1!有人会问,-10 % 3为什么是2?这是因为Python取余遵循“结果符号与除数相同”的规则,实际计算时先做整除:-10 // 3的结果是-4(向下取整),然后-10 - (-4 * 3) 2。这和C、Java的取余行为不一样,是Python一个很容易让新手懵的点。整除运算符//同样是向下取整,而不是向零取整。7 // 2得到3,-7 // 2得到-4。如果你需要向零取整,可以用int(7 / 2)这种转换方式,但要注意浮点数转换的精度问题。幂运算符**也很实用,2 ** 10就是1024。在写计算面积、复利、指数相关的代码时比pow(2, 10)更直观。2.3 浮点数精度:那个让你怀疑人生的0.10.2我打赌每个Python初学者都敲过这行代码:print(0.1 0.2)结果不是0.3,而是0.30000000000000004。这不是Python的Bug,而是所有用二进制浮点数表示十进制的语言共有的问题。计算机内部用二进制存小数,很多十进制小数无法被精确表示,只能取近似值。解决办法有几个:一是用round()控制显示精度,round(0.1 0.2, 2);二是做金额计算时用decimal.Decimal;三是在比较浮点数时,不要直接写if a b,而是判断差值是否小于一个极小值,比如abs(a - b) 1e-9。这块内容算不上难,但对刚入门的人来说非常“劝退”。我的建议是先知道“为什么”,然后记住“怎么绕开”,等以后学到浮点数原理再回头看,会理解得更深。3. 比较运算符与赋值运算符:入门期最容易混淆的组合3.1 比较运算符:所有比较的结果只有True或False比较运算符包括 ! 这六个。必须牢记:它们返回的一定是布尔值,要么True,要么False。是比较“值是否相等”,而是赋值,两者天差地别。x 5 # 赋值:把5交给x x 5 # 比较:x的值是否等于5,结果是True一个特别容易踩的坑是,新手会把if x 5:写出来,这在Python里会直接报语法错误,因为条件表达式里的不是表达式。写条件判断时,心里默念“一个等号是给东西,两个等号是问问题”,能避免一大半低级错误。还有一个!代表“不等于”,代表“小于等于”,这些符号中间没有空格,不要写成! 或 。字符串也能比较,比较的是Unicode码点顺序,例如abc abd返回True。3.2 赋值运算符全家桶:到底比快在哪赋值运算符除了最基础的,还有一堆复合赋值运算符: - * / // % **,甚至位运算也有 | ^ 。它们的核心用法是一样的:count 0 count 1 # 等价于 count count 1,结果count变成1 total 10 total * 3 # 等价于 total total * 3,结果total变成30为什么推荐用?一方面代码更简洁,另一方面在Python内部,对于列表这类可变对象,list [item]比list list [item]执行的效率更高——前者是原地扩展,后者会先创建新列表再赋值。入门阶段体会可能不深,但养成写的习惯确实是一件好事。注意不要连续赋值出歧义。Python支持a b 0,这会让a和b都指向同一个0;但不建议在复杂场景下滥用,容易让读代码的人产生疑问。3.3 链式比较:Python独有的优雅写法很少有语言支持链式比较,但Python支持,这非常实用。比如判断一个数是否在区间[10, 20]内,经典写法是:if x 10 and x 20: passPython允许直接写:if 10 x 20: pass这行代码内部其实等价于(10 x) and (x 20),但读起来自然多了。我在很多教程里都把链式比较当成卖点讲,因为它确实能让你感受到Python“符合直觉”的设计哲学。不过要留意,链式比较中的中间变量会被求值一次还是多次?实际是多次,但这里面的差别在新手阶段可以忽略。你只需要记住:如果你发现and连接的两个比较表达式在同一个变量上,大概率可以改写成链式比较。4. 逻辑运算符详解:and、or、not到底怎么用4.1 布尔逻辑与真值表逻辑运算符and or not对应数学里的“且、或、非”。理解它们的标准方法是看真值表:ABA and BA or Bnot ATrueTrueTrueTrueFalseTrueFalseFalseTrueFalseFalseTrueFalseTrueTrueFalseFalseFalseFalseTrueand是“两个都真才真”,or是“只要一个真就真”,not是“取反”。写条件判断时,数据库查询里常见的age 18 and age 60,翻译过来就是“年龄在18到60之间”;用or写“周末或节假日休息”这类业务规则,非常贴合直觉。4.2 短路求值:Python里一个隐蔽但强大的特性Python的and和or有短路求值特性:对于A and B,如果A已经是False,那么B根本不会被求值;对于A or B,如果A已经是True,那么B也不会被求值。这个特性在实战中很有用。比如你要判断user不是空且user[name]存在,可以放心写:if user and user[name] admin: pass如果user是None,Python根本不会去访问user[name],也就不会抛出TypeError。这在很多语言里需要写一堆嵌套判断,Python用短路求值一行就搞定了。但反过来也要小心:如果你在and右边放了一个有副作用的函数调用,而左边的条件为假,那个函数不会执行。这不是Bug,是特性,得心里有数。4.3 逻辑运算符的返回值:不只是True和False初学者最容易被坑的一点是:and和or返回的并不一定是True或False,它们返回的是“决定结果的那个值”。print(0 and 10) # 0 print(1 and 10) # 10 print(0 or 10) # 10 print(1 or 10) # 1规则很简单:对A and B,如果A是假值,返回A;如果A是真值,返回B。对A or B,如果A是真值,返回A;如果A是假值,返回B。这里的“真值”“假值”指所有对象:0、空字符串、空列表、None等都被当成False,其余大多数对象都是True。这个特性常被用来写默认值,比如name user_input or 默认用户。如果user_input是空字符串(假值),就取默认用户。这种写法在Python代码里很常见,但新手一开始容易懵。我的建议是:平时写条件判断时,不要依赖这个特性去“炫技”,先用if写清楚,等你真正理解了再简化。5. 位运算符深入:二进制世界的高效操作5.1 按位与、或、异或、取反:Python里也能直接操作二进制位位运算符是对整数的二进制位进行操作的运算符,包括(按位与)、|(按位或)、^(按位异或)、~(按位取反)、(左移)、(右移)。虽然入门阶段用得不多,但它们在权限控制、状态标识、图形计算、底层算法中非常常见。先看概念。两个数按位对齐,是“同1才为1”,|是“有1就为1”,^是“不同才为1”。举个例子,5的二进制是101,3的二进制是011:print(5 3) # 1 (101 与 011 按位与,结果001) print(5 | 3) # 7 (101 或 011,结果111) print(5 ^ 3) # 6 (101 异或 011,结果110)新手常问:为什么我要用位运算?直接写数学公式不好吗?答案是位运算快、省内存,而且能在一个整数里塞进多个布尔状态。比如用0b01表示“已启用读权限”,用0b10表示“已启用写权限”,那么permission 2是否非0就能判断“是否有写权限”。这在大型项目里是常见的降本增效手段。5.2 移位运算的本质:左移就是乘2,右移就是整除2左移运算符把二进制位整体向左移动,右边补0;右移运算符把位向右移动,左边补符号位或0。最直观的效果:print(3 2) # 12,3的二进制11,左移两位变成1100 print(16 2) # 4,16的二进制10000,右移两位变成100简单记:x n相当于x * 2^n,x n相当于x // 2^n。老程序员喜欢用移位代替乘除,因为理论上更快。但在Python这种解释型语言里,移位的性能优势远没有C语言那么明显,代码可读性反而是更大的考量。所以我的建议是:知道这个对应关系,但不要为了“炫酷”把x * 4写成x 2,除非你在写对性能极其敏感的底层模块。5.3 位运算的实战场景:权限标志与奇偶判断位运算最常见的实战场景之一就是权限组合。设计一个整数perm,最低位表示读权限,倒数第二位表示写权限:READ 1 # 0b01 WRITE 2 # 0b10 perm READ | WRITE # 3,同时拥有读写权限 print(perm READ) # 1,非0说明有读权限 print(perm WRITE) # 2,非0说明有写权限另一种简单应用是判断奇偶:x 1等于0说明是偶数,等于1说明是奇数。因为任何整数的最低位只有0或1两种情况。x % 2 0当然也能判断,但位运算的写法在部分场景下会更快。如果你以后接触量化交易策略或者高性能计算,位运算还能用在大量的状态压缩和并行计算场景。我的建议是,入门阶段理解概念、跑通例子就足够了,不必强行背各种位运算口诀,等真实需求出现时你能看懂调用方的意图才是关键。6. 运算符优先级速查与程序员的避坑指南6.1 一张优先级表,解决90%的歧义Python的运算符有明确的优先级,从高到低大致是这样(只列常用部分):优先级运算符说明高()括号永远最高**幂运算x -x ~x正负号、按位取反* / // %乘、除、整除、取余 -加、减 移位按位与^按位异或|按位或 ! 比较运算符not逻辑非and逻辑与低or逻辑或这张表不用背得滚瓜烂熟,但至少要记住几个容易出错的地方:幂运算优先级高于正负号,所以-2 ** 2结果是-4,不是4;and优先级高于or,所以True or True and False的结果是True,因为先算True and False得到False,再算True or False得到True。这些细节靠“背”容易忘,靠“踩坑”才能长记性。6.2 结合性:从左到右,还是从右到左大多数运算符都是左结合,也就是从左往右算,例如100 / 10 * 5先算100 / 10得到10,再乘5得到50。但幂运算符**是右结合,所以2 ** 3 ** 2等价于2 ** (3 ** 2),也就是2 ** 9,结果是512。如果你写成(2 ** 3) ** 2,结果就是64,差异很大。赋值运算符也是右结合,a b c 1会把1依次赋给c、b、a。理解“右结合”对读懂别人代码很有帮助,但自己写代码时,遇到可能产生歧义的地方,我的原则是“能加括号就加括号”。括号不是示弱,而是把意图写清楚,让同事和自己三个月后再看时都能一眼读懂。6.3 三条黄金法则,写出更好读的表达式第一条,别让优先级替你“背锅”。如果你要表达“两个数之和的平方”,直接写(a b) ** 2,而不要写a b ** 2,后者完全是另一个意思。用显式括号消除一切歧义,不仅是对自己负责,也是Python社区推崇的写法。第二条,把复杂判断拆到变量里。比如if a 1 and b 2 and c ! 3:这种长条件,读起来费劲;不如先定义condition a 1 and b 2 and c ! 3,再写if condition:。代码行数没多多少,但逻辑清晰度提升一大截。第三条,注意比较运算符的连续写法。a b c是链式比较,合法且直观;但如果你写a b c,语法上合法,语义却是“(a小于b)且(b大于c)”,非常反直觉。遇到这种情况,拆成两个条件再写,别创造“一行谜题”为难别人。7. 常见问题排查与实战建议7.1 新手最常见的运算符错误Top 3第一个错误是和混用。我在教学里把这个称为“入门第一大Bug”,不少人在写if条件时顺手写了个等号,Python直接报SyntaxError。解决方式很简单:心里默念“一个等号是给东西,两个等号是问问题”。第二个错误是整除和取余符号搞反。//是整除,%是取余,英文里分别是floor division和modulo。做题时,想取余数却写了/,结果自然是浮点数和预期对不上。第三个错误是忘记负数的取余规则。常见场景是“处理数组下标回绕”时,比如把-1取余n,在Python里得到的是正数,而不是某些语言里的负数。如果你从其他语言转过来,一定要亲自验证一次-1 % 5的输出。7.2 运算符相关的常见报错速查表报错信息常见原因解决办法SyntaxError: invalid syntax用在条件判断里改成TypeError: unsupported operand type(s) for : int and str数字和字符串混加法先类型转换str(1) 2或1 int(2)TypeError: not supported between instances of str and int字符串和数字直接比较用int()或str()统一类型ZeroDivisionError: division by zero除数为0先判断除数是否为0IndentationError条件语句或循环没缩进确认代码块对齐遇到这些报错,不要慌。Python的报错信息其实挺友好,先读最后一行,再往上看是哪一行代码触发,基本能定位。拿不准运算符优先级时,就拆成多行多变量,程序立刻就能跑通。7.3 练习建议:用一张图也能训练运算符学运算符最忌讳“看会了”但“手不会”。我建议你找几道非常基础的计算题练手:比如输入一个秒数,把它换算成“时:分:秒”,这需要用到整除//和取余%;再比如判断一个年份是不是闰年,条件里需要and、or、和%的组合。这类小练习虽然简单,但能让你把算术、比较、逻辑运算符全部串起来。等你写完,再试着用链式比较简化条件,然后思考如果年份是负数会发生什么。逐步加需求,运算符的理解就会越来越深。结尾:我的实际体会我从带新人的经验里得到一个结论:运算符学得好不好,不看你能背多少符号,而看你遇到报错之后,能不能顺着运算符的执行顺序快速定位问题。我自己最初学Python时,也栽过and和or返回值不是布尔值的坑,浪费了不少时间才想明白。后来养成了一个习惯:凡是拿不准的表达式,就开一个交互式命令行,先把结果打出来,再往项目里写。这个方法我一直沿用到现在,也推荐给你。运算符是Python里最小但最关键的“零件”,花点耐心把它们磨透了,后面无论学函数、学面向对象、还是做数据处理,你都会比别人走得更顺。
返回列表