尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python3运算符与条件结构:AI开发必备基础与练习题精讲

Python3运算符与条件结构:AI开发必备基础与练习题精讲 1. 为什么AI课程要从运算符和条件结构练起带过几期AI入门班之后我越来越确信一件事很多同学后期学不动神经网络、学不懂PyTorch问题基本都出在Python基础没打牢尤其是运算符和条件结构这两个关卡。你可能觉得“不就是加减乘除、if else吗”但真正写代码的时候数值比较的边界条件写错、逻辑运算符短路导致报错、多重条件分支排列混乱这些坑几乎每个人都会踩一遍。这一篇是【AI人工智能第3次课-Python3基础系列】的005篇练习题专门针对Python3的运算符与条件结构。我会把这两块内容拆开揉碎配上大量可运行的练习题和逐行解析再结合AI开发中常见的判断场景比如模型输出阈值的过滤、数据清洗时的条件筛选、循环训练中的状态切换让你不光会做题还能知道这些语法在以后学AI时到底用在哪里。练习题不是目的建立“运算优先级”和“条件分支”的肌肉记忆才是目的。所以这篇文章适合三类人刚学Python3想巩固基础的新手、准备转行AI开发但基础不牢的学员以及想找高质量练习题带解析的自学党。看完之后你不需要再去网上零散地搜“python运算符练习题”直接跟着我给的题量刷两遍基本就能把这块焊死在脑子里。2. 运算符全景不只是加减乘除那些事2.1 七类运算符逐个过一遍Python3中的运算符可以分成七大类每一类在AI开发中都有它的用武之地。先看分类表类别运算符典型使用场景算术运算符 - * / // % **数值特征计算、归一化处理比较运算符 ! 判断模型预测值是否符合预期赋值运算符 - * / // % **累加损失、更新计数器逻辑运算符and or not组合多个筛选条件成员运算符in not in检查某个类别是否在标签集合中身份运算符is is not比较对象是否指向同一内存地址位运算符 | ^ ~ 图像处理、二进制掩码操作很多教材把这七个类别列出来就完了但从来不告诉你它们之间的优先级关系。我见过不少学员在写if score 60 and score 90时犹豫要不要加括号其实Python的优先级规则是算术运算符 比较运算符 赋值运算符 逻辑运算符。这意味着score 60 and score 90这个表达式里两个比较会先执行and最后执行所以不加括号也完全没问题。但这里有一个反直觉的坑逻辑运算符内部的优先级是not最高and次之or最低。所以not a or b实际等价于(not a) or b而不是not (a or b)。我建议无论如何都显式加括号因为别人读你代码的时候不需要去查优先级表你自己过一个月回来看也不会糊涂。2.2 算术运算符里的隐藏细节算术运算符最容易出问题的不是加减乘除而是整除//和取余%尤其在涉及负数的时候。比如-7 // 2在Python3里的结果是-4而很多从C语言或Java转过来的同学会以为结果是-3。原因在于Python的整除执行的是向下取整也就是地板除结果永远不大于真正的商。-7 // 2的真实商是-3.5向下取整得到-4。与之配套的取余运算-7 % 2结果是1因为Python保证a (a // b) * b a % b这个公式永远成立。代入验证-4 * 2 1 -7刚好对上。这个特性对数据分桶、图像切块、环形队列下标计算非常重要。举个例子在强化学习里经常要做“周期性策略切换”比如每100个回合换一种探索参数你会写episode % 100 0来判断。如果episode是负数某些环境从负值开始计数这个判断依然符合直观预期因为Python的取余结果始终非负这比C语言友好得多。再说说幂运算**和乘法*的区别。很多人写特征交叉时会把x * y和x ** y搞混前者是逐元素相乘后者是乘方。在Python里2 ** 3 ** 2是有歧义的它的实际计算方式是右结合即2 ** (3 ** 2)结果是512而不是64。同理赋值运算符里的**也是右结合的不过这种情况很少出现知道有这回事就够了。2.3 比较运算符与连续比较的特殊写法Python3支持链式比较比如0 x 1这个表达式在Java或C里面必须写成0 x x 1。链式比较不仅简洁更重要的是它严格符合数学直觉而且只计算一次x。比如判断一个坐标是否落在区间里直接写if 0 x width and 0 y height:即可。比较运算符里最容易翻车的是浮点数相等判断。直接0.1 0.2 0.3会返回False因为浮点数在计算机里是二进制近似存储0.1 0.2实际得到的是0.30000000000000004。在AI开发中判断loss是否收敛、accuracy是否达到目标值时千万不要用去比较浮点数应该用abs(a - b) 1e-6或者math.isclose(a, b)。练习题里我会专门出一道这种陷阱题。2.4 赋值运算符与不可变对象的坑赋值运算符看起来很简单但有一个隐蔽的行为差异取决于对象是可变的还是不可变的。对于整数、浮点数、字符串、元组这类不可变对象a b等同于a a b会创建一个新对象并让a指向它。但对于列表、字典这类可变对象a b实际上调用的是extend方法会在原列表上直接追加元素而不是创建新列表。很多人在写代码时会把列表当作函数参数传递然后在函数内部执行lst [1]结果发现外部列表也被修改了一脸懵。这个知识点在AI的数据预处理中特别关键因为DataLoader、Dataset这些组件经常涉及列表的原地修改。如果你想去重而不影响原列表需要写成new_lst lst [1]或者lst lst [1]明确告诉Python你要创建新对象。2.5 逻辑运算符的短路求值and和or最实用的特性是短路求值a and b中如果a已经是False整个表达式不可能为真所以b根本不会执行a or b中如果a是Trueb也不会执行。这个特性常被用来做默认值设置比如name user_input or unknown当user_input是空字符串、None或0时or后面的默认值就会生效。这个写法在配置参数、环境变量读取中极其常用。但要注意or返回的不是布尔值而是第一个为真的操作数或者最后一个操作数。所以0 or False or default的结果是default1 or default的结果是1。很多新手以为逻辑运算的结果只能是True或False这是不对的。短路的另一个实用场景是防止除零错误if b ! 0 and a / b 10: print(ratio too high)如果写成if a / b 10 and b ! 0:那么当b 0时第一条先执行直接就报ZeroDivisionError了。这就是条件的先后顺序对程序正确性的影响做题和写业务代码都要留意。2.6 成员运算符与身份运算符的区别in在AI里用得太多了判断类别标签在不在集合里、检查文件名后缀、过滤空值到处都有。not in则适合做反向过滤比如if item not in blacklist:。这里有一个性能相关的建议如果你要频繁用in检查一个大列表最好先把这个列表转成set因为列表的in是O(n)遍历集合的in是O(1)哈希查找。is和的区别是必考题。is比较的是两个变量是否指向同一个对象内存地址比较的是两个对象的内容是否相等。对于小整数Python有缓存机制a 256; b 256; a is b是True但a 257; b 257; a is b是False。字符串也有类似的驻留机制但规则更加复杂。我在练习题里专门准备了一道关于is的陷阱题你可以先猜一下结果再运行验证。3. 条件结构让程序学会做选择3.1 if/elif/else的执行顺序条件结构是程序从顺序执行走向“智能决策”的第一步。Python的条件结构只有一种标准形式if从句然后按需加0个或多个elif最后加0个或1个else。执行顺序是从上到下依次判断一旦某个条件为真执行对应的代码块然后跳出整个if-elif-else结构后面的elif和else都不再判断。这里有一个非常典型的误区很多新手会把多个完全无关的条件写成一长串if忘了用elif导致程序重复执行多个分支。比如判断成绩等级时score 75 if score 60: grade 及格 if score 85: grade 优秀这段代码在score 75时没问题但score 90时先执行第一个if得到“及格”紧接着又被第二个if覆盖成“优秀”。虽然最终结果凑巧对但逻辑上是有隐患的如果第二个if的条件是score 60那么score 90时两个分支都会执行产生逻辑冲突。正确的做法是if score 85: grade 优秀 elif score 60: grade 及格 else: grade 不及格注意elif的顺序也很重要范围大的条件要放在后面具体的条件要放在前面。比如上面先判断85再判断60才能保证85分以上的不会落进“及格”分支。如果你写反了先判断60那么90分就会直接进入“及格”分支后面的elif score 85根本没有机会执行。3.2 布尔值转换与条件判断的隐式规则Python在条件判断时会对表达式做隐式布尔转换。除了False本身None、0、0.0、空字符串、空列表[]、空元组()、空字典{}、空集合set()都会被当作False其余绝大多数对象都当作True。这个规则让代码可以写得很简洁if data: # 列表或字典非空时才执行 if not error_msg: # 错误消息为空时执行但隐式转换也容易掩盖bug。比如你期望data是一个整数但它是0那么if data就不会执行你可能根本没有意识到data是合法的数值。所以在处理数值时必须写明确的条件比如if data is not None:而不是if data:否则当data 0时就会被错误地跳过。练习题中我会设计一道题专门考察bool([])、bool( )、bool(0.0)这类边界情况。3.3 嵌套条件与代码缩进的纪律Python用缩进表示代码块这种设计让代码强制对齐但同时也带来缩进错误的高发。最常见的缩进问题是Tab和空格混用就算在IDE里看着对齐了运行时也会报IndentationError。我的建议是永远使用4个空格并且把编辑器配置成“Tab键自动转空格”。嵌套条件是指if内部再套if通常用来表达“先满足外层条件再满足内层条件”的逻辑。例如判断一个数据点是否参与训练先看它是否在有效范围内再看它的标签是否为空。嵌套太深会降低代码可读性所以Python社区有“扁平优于嵌套”的风格建议。如果一个函数里出现了三层以上的缩进你应该考虑用and合并条件或者把内部逻辑抽成一个函数。3.4 三元表达式与条件表达式的简洁写法Python的三元表达式语法是x if 条件 else y注意它的顺序跟英文直觉有点不一样结果是x条件是if后面那段否则结果是y。三元表达式适合写简单的赋值比如mode train if is_training else eval但不适合嵌套使用一旦嵌套三层以上可读性急剧下降。比如a if x else b if y else c这种写法虽然语法上合法但几乎没人能一眼看懂。遇到复杂判断哪怕多写几行if语句也比秀技巧更重要。除了三元表达式Python还有一个match语句是从3.10开始支持的类似于其他语言里的switch-case。在AI开发中match可以用于根据字符串配置分发不同的模型训练策略但目前大部分老项目还在用Python3.8或3.9所以这块内容我不会作为重点你知道有这回事后面版本升级时再补即可。4. 练习题精选与逐题解析4.1 基础热身算术与赋值运算符第1题以下代码输出什么a 10 b 3 print(a / b) print(a // b) print(a % b) print(a ** b)输出顺序是3.3333333333333335、3、1、1000。第一行是浮点除法永远返回浮点数哪怕能整除10 / 2也会输出5.0。第二行是地板除法针对正数就是简单的取整数部分。第三行取余数。第四行是10的三次方。易错点10 / 3的结果不是3.33而是一长串浮点数这是二进制浮点数的正常表现。如果你希望保留两位小数不要用round硬截而是用字符串格式化f{a/b:.2f}。第2题连续赋值与复合赋值x 5 x 3 x * 2 x // 4 x ** 3 print(x)逐步计算x 8、x 16、x 4、x 64。复合赋值不会自动改变运算优先级比如x * 2 3等价于x x * (2 3)右侧表达式永远会被完整计算。所以第2题的x // 4是先用16 // 4得到4再执行幂运算得到64。4.2 条件判断陷阱题花式踩坑第3题看看下面这段代码哪里错了score 85 if score 60: print(及格) elif score 85: print(优秀)这段代码永远不会输出“优秀”因为85同时满足60和85两个条件但if分支一旦命中后面的elif就自动跳过了。这是故意设计的陷阱用来强调条件分支的排他性。正确做法是把范围大的条件放后面也就是我前面说的“先窄后宽”。第4题浮点数比较的坑a 0.1 0.2 b 0.3 print(a b) print(round(a, 1) b)第一行输出False第二行输出True。在AI中比较预测概率是否等于某个阈值时绝对不能直接用应该用abs(a - b) 1e-6。我建议在工程代码里封装一个is_close函数def is_close(a, b, tol1e-6): return abs(a - b) tol这样语义明确而且还方便统一调整容忍度。第5题逻辑运算符短路陷阱def check(): print(check called) return True result False and check() print(result)输出是False且控制台不会打印check called因为and左侧已经为False右侧根本没执行。这个特性常被用来做条件前置校验但也会导致一种隐蔽bug如果check()函数里除了返回值之外还有副作用比如更新计数器、写入日志那它的副作用在短路时不会发生。所以在写and或or表达式时不要依赖于右侧表达式的副作用。第6题身份运算符与相等运算符a [1, 2, 3] b a c a.copy() print(a is b) print(a c) print(a is c)a is b为True因为b就是a的别名a c为True因为内容相同a is c为False因为copy()创建了一个新列表内存地址不同。这道题在AI中的数据传入传出中很重要你修改b实际上就是在修改a但如果修改c不会影响a。很多同学在写函数参数时由于不知道这个区别会无意中污染原始数据。4.3 综合实战题写一个成绩等级判断器第7题要求输入一个百分制成绩输出等级90分及以上为A80到89为B70到79为C60到69为D60以下为F。如果输入的数据不在0到100范围内打印“无效分数”。参考实现score float(input(请输入成绩)) if score 0 or score 100: print(无效分数) elif score 90: print(A) elif score 80: print(B) elif score 70: print(C) elif score 60: print(D) else: print(F)这里顺序是先排除非法范围再逐级判断。注意score 0 or score 100用了逻辑或来组合两个异常条件比写两个if更简洁。另外float(input(...))会直接把输入的字符串转成浮点数这意味着输入“85.5”也能正确分级。如果你想限制必须输入整数可以改用int()但如果输入带小数就会报错所以用float更稳健。第8题拓展把成绩等级判断扩展到AI模型预测结果的解释。假设模型输出的是0到1之间的概率值你要把它映射成“高置信度”“中置信度”“低置信度”三个档位。该怎么改很简单把边界条件改一下就行prob 0.87 if prob 0.9: level high elif prob 0.7: level medium else: level low这里的核心思想是条件结构可以用来做阈值过滤器。在图像分类、目标检测、文本分类的后处理中模型输出的原始分数往往需要经过一个阈值筛选只保留置信度较高的结果。这个逻辑本身不复杂但边界值的确定往往需要结合业务需求反复调整。4.4 实战题嵌套条件实现多条件筛选第9题筛选满足以下条件的数据点特征值x大于0类别标签在集合{0, 2, 5}中置信度conf大于0.6。用多种方式实现。第一种嵌套条件if x 0: if label in {0, 2, 5}: if conf 0.6: print(accept)第二种合并条件if x 0 and label in {0, 2, 5} and conf 0.6: print(accept)你以为两种写法完全等价吗不完全等价。如果x不满足条件第一种写法根本不会去检查label和conf第二种写法则会按顺序从左到右依次判断同样是短路但可读性明显更高。对于面试和代码评审第二种写法更受欢迎。嵌套条件适合不同条件之间有优先级关系比如必须先通过安全检查才能读取数据这种场景下嵌套能让逻辑更清晰。第10题拔高用三元表达式实现以下逻辑如果epoch大于等于10学习率设为0.001否则保持0.01。这题太简单我就不给代码了你自己写。写完后思考如果学习率还要根据更早的epoch分三段设置三元表达式还合适吗答案显然是否定的这时候就该老老实实写if语句。5. 常见错误与排查技巧实录5.1 我在带学员时遇到的真实报错总结在批改作业的过程中我发现下面几个错误反复出现几乎每个班都有同学中招。这里整理成一张速查表方便你以后排查问题错误类型错误示例报错信息解决方案赋值等于比较if x 5:SyntaxError: invalid syntax改成x 5缩进不一致混用Tab和空格IndentationError: unexpected indent统一用4个空格忘记冒号if score 60SyntaxError: expected :条件末尾加冒号超出范围比较0到100判断先写score 60逻辑错误不报错调整elif顺序短路副作用False and func()不报错但func没执行不要在逻辑表达式中依赖副作用is比较内容用is比较两个相等但不同地址的列表False但结果不符合预期内容比较用地址比较用is5.2 调试条件结构的三板斧第一板斧打印中间变量。当你不知道条件为什么没进去就在判断前打印所有参与判断的变量和它们的类型。比如print(fscore{score}, type{type(score)})很多次学员发现score其实是字符串型的85和整数型的85比较时虽然85 60在Python里不会报错但在有些Python版本中字符串与整数比较的结果是固定的False或抛出类型错误这属于隐蔽的类型陷阱。要避免这种问题务必在做数值比较前先做类型转换。第二板斧用else兜底。在调试阶段可以临时给每一个elif分支后面加上else: print(未匹配)这样就能知道哪些值没有进入预期分支。这个方法比断点调试更直观。第三板斧做最小化测试。如果把一个长条件拆成多个独立if然后分别传入已知输入看每个条件单独的表现就能快速定位到是哪个子条件出了问题。这本质上就是单元测试的思路在AI项目的数据处理代码里同样适用。5.3 光看不练等于白学怎么有效刷题我之前发现有些同学喜欢把练习题答案背下来这是完全没用的。运算符和条件结构的重点在于“为什么要这么写”而不是“答案是什么”。我建议的刷题流程是先不看答案自己写一遍再对照答案找出差异然后故意把代码改错观察报错和输出变化最后脱离题目自己设计一个生活场景或AI场景用条件结构实现。比如“模拟一个无人车在遇到行人和红灯时的决策逻辑”这种自创练习能快速提升代码直觉。把每道题的代码都手敲一遍敲的过程中你会自然记住冒号和缩进比看十遍书都管用。如果是在手机上学习也可以用在线Python解释器验证结果但最终一定要回到电脑上实际操作。6. 这些基本功如何接轨真正的AI开发6.1 数据清洗中的运算符应用在真实AI项目中你写的第一行代码往往不是模型结构而是数据预处理。比如从日志中筛掉异常值特征值必须大于0置信度必须在0到1之间标签不能是未知类。这些逻辑全部是运算符和条件结构的组合。再比如对缺失值填充会用到if value is None or value ! value:其中!用于检查NaN以及or做默认值兜底。如果你对运算符的短路规则不熟悉很容易写出“看似正确但数据一出错就崩溃”的预处理代码。6.2 模型训练时循环中的条件控制训练神经网络时你经常需要根据当前epoch数调整学习率、决定是否早停、切换训练模式。这些策略几乎全部依赖条件结构。一个典型的例子是学习率预热前5个epoch用较小的学习率中间用正常学习率最后10个epoch做衰减。实现方案无非是if判断当前epoch落在哪个区间然后返回对应的学习率。不要小看这个逻辑它在PyTorch的LambdaLR回调函数里比比皆是。6.3 从练习题到工程习惯的进阶之路学完运算符和条件结构你接下来会遇到函数、列表推导式、字典操作这些内容本质上都是在更高层级上组合你已知的规则。比如列表推导式里的if其实就相当于一个条件过滤器而or默认值技巧在配置解析、命令行参数处理中随处可见。我的建议是不要因为觉得练习题太简单就跳过把这些基础操作做到闭着眼都能写后面学习Numpy、Pandas时才能把注意力集中在数据形状和计算逻辑上而不是被Python语法绊住。我自己在带课和写代码的过程中最深刻的体会就是容易出错的地方往往不是那些复杂的语法而是最基础的运算符陷阱和条件分支顺序。每次看到学员花几个小时排查一个因为写成导致的问题我都想说这就是老老实实刷练习题的意义。练习题的每一道错题都是未来真实项目debug经验的预演。你把这些坑在练习阶段踩过一遍后面写业务代码就会形成本能的警惕一眼瞄过去就知道哪里有风险。这组练习做完之后你可以接着挑战更复杂的循环和函数题或者试着用列表推导式重构这些条件逻辑。等你在Python基础上有了足够的肌肉记忆再回过来看那些AI框架的源码你会发现很多地方都能看得懂了。
返回列表