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

Python入门:掌握流程控制与函数编程,告别代码混乱

Python入门:掌握流程控制与函数编程,告别代码混乱 ★ FEATURED ARTICLE
很多学 Python 的朋友都有过这种体验变量会定义、print 会用看教程时每个语法点都感觉懂了但一脱离教程自己写就卡在到底该怎么组织代码上。说白了就是从零开始学 Python 这条路上真正拉开差距的不是记住了多少个语法点而是有没有把流程控制和函数编程这两块地基真正想明白。这篇文章我会结合这些年实际写代码、带新人的经验把环境搭建、基础语法铺垫、流程控制、函数编程、常见坑和排查思路一次讲透适合刚入门想系统夯实基础的同学也适合学了一半觉得代码混乱、想回头补课的人。我先把话说在前面Python 语法本身不复杂复杂的是你脑子里没有一套先做什么、再做什么、哪些逻辑需要拆开复用的思维框架。流程控制解决的是代码如何做出选择和重复执行函数编程解决的是如何把反复用到的逻辑做成可复用的零件。这两块掌握好了后面学 numpy、pandas、爬虫、自动化办公都只是往这个架子上挂工具罢了。1. 环境准备先把电脑变成能跑 Python 的机器学 Python 之前第一件事是装环境。这个环节很简单但恰恰是很多新手被劝退的地方。我见过太多人卡在我明明装了 Python但一运行却提示不是内部或外部命令这种问题上然后开始怀疑自己是不是不适合学编程。其实不是你不行是环境配置里的几个细节没搞清楚。1.1 版本选择与安装过程的细节打开 Python 官网下载页你会发现有一堆版本号。我建议新手直接选最新的稳定版目前已经到了 3.11、3.12 这个阶段不要再去看那些教 Python 3.8 的老教程了。版本太老会导致新语法特性用不了比如现在很常用的类型提示增强、字典合并运算符|在老版本上可能直接报错。下载安装包时第一个关键点是一定要勾选安装界面底部的 Add Python to PATH 选项。这个选项的作用是把 Python 的可执行文件路径写进系统的 PATH 环境变量里勾选之后你在命令行输入python才能直接启动解释器。很多人的python 不是内部或外部命令报错90% 是因为这里没勾选。如果你已经装完了才发现没勾选也不用重装去系统设置里手动把 Python 安装目录加到 PATH 即可或者重新运行一次安装包选择 Modify。第二个细节是安装完成之后码上验证一下。打开命令行工具输入python --version如果输出了类似Python 3.12.2的版本号说明解释器已经可用。接着再输pip --versionpip 是 Python 的包管理工具后面学 numpy、sklearn、cv2 这些库全都靠它。顺便提一句如果你后续要装数据分析或者深度学习相关的库建议新建一个虚拟环境再装不要一股脑全部装进系统 Python 里。虚拟环境就是给项目独立隔离的依赖空间避免 A 项目需要 numpy 1.x、B 项目需要 numpy 2.x 时互相打架。创建方式很简单python -m venv myenv然后激活环境Windows 下运行myenv\Scripts\activatemacOS 或 Linux 下运行source myenv/bin/activate。激活后命令行前面会多出一个(myenv)前缀这时候你再pip install任何库都只装进这个环境里。安装过程中还有一个小技巧国内网络环境下直接pip install大一点的库会很慢甚至超时。建议把 pip 源换成国内镜像源比如清华源或阿里源一次性配置好pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple路径里实际用的镜像域名以大家在社区里常见的稳定镜像为准。换完源之后再装库速度可以说是肉眼可见的提升。1.2 编辑器选择为什么推荐 VSCode环境装好之后还需要一个写代码的地方。我推荐 VSCode免费、跨平台、插件生态好Python 开发体验不输专业 IDE。装完 VSCode 后在扩展商店里搜 Python 官方插件安装然后打开一个.py文件右下角就能看到你当前选中的解释器。这里有一个特别容易踩的坑你明明在终端里pip install numpy成功了但 VSCode 运行脚本却报ModuleNotFoundError。原因几乎肯定是 VSCode 选中的解释器和你安装库的 Python 不是同一个。解决办法是在 VSCode 里按CtrlShiftP输入 Python: Select Interpreter手动选择那个你在终端激活的虚拟环境。判断是不是同一个环境最直接的办法是运行import sys; print(sys.executable)看输出路径和你pip install时用的解释器路径是否一致。VSCode 里写好脚本后先熟悉几个操作左上角三角形按钮运行当前文件、右键菜单里也可以直接运行、终端里可以用python 脚本名.py运行。这三种方式本质一样区别只在于工作目录和解释器来源不同。我个人习惯是先在终端里自己跑命令因为这样能更直观地理解当前环境的 Python 到底是谁。2. 基础语法铺垫变量、类型与切片这些地基进入正题之前先把流程控制和函数编程依赖的基础语法理一理。不是要从头讲一遍完整语法而是挑几个后续写逻辑时高频使用、又特别容易出错的点。2.1 变量与动态类型别被动态迷惑Python 里的变量定义非常直观直接写名字和值就行name 张三 age 26 price 3.5不需要像 C 或 Java 那样写int age; String name;。这背后是因为 Python 采用动态类型机制——变量本身只是名字指向内存中的对象你给变量重新赋另一个类型的值也完全合法。这给新手带来方便的同时也埋了一个隐患很容易忘记当前变量到底是什么类型导致后面调用方法时报错。有个经典例子用户输入年龄age_str input(请输入年龄) age int(age_str)input()返回的永远是字符串如果你忘了转成int后面拿age去做比较age 18时Python 虽然不会直接报错但如果你拿它和整数做运算比如age * 2字符串会重复而不是翻倍逻辑就错了。所以养成一个习惯拿到外部输入或从列表、字典取出来的数据先用type()看一眼类型再决定要不要转换。写复杂脚本时一个好的习惯是变量名里体现类型name_str、age_int、score_list这样代码读起来不容易糊涂。字符串拼接也是新手容易踩坑的地方。用拼字符串时数字必须先转成字符串age 26 print(年龄是 str(age))更推荐用 f-string直观且不易出错print(f年龄是{age})2.2 类型转换里隐藏的陷阱Python 的类型转换函数看着很直白int()、float()、str()、bool()、list()这些但细节坑不少。比如int(3.5)会直接报ValueError因为int()不能直接把带小数点的字符串转成整数正确做法是先float(3.5)再int()。再比如bool(False)返回的是True因为非空字符串都是真值空字符串才是False。这个细节在写条件判断时影响非常大后面讲流程控制会专门说到。列表转字符串和字符串转列表也常用。list(abc)会得到[a, b, c]但如果你想按逗号分隔应该用a,b,c.split(,)。反过来把列表[a, b, c]拼成一个字符串用,.join(...)。类型转换的原则是显式优先依赖隐式是要吃亏的。尤其是布尔转换很多人以为bool(value)就是把值变真假其实它背后走的是真值判断规则这个规则非常反直觉。2.3 序列与切片列表、元组、字符串的通用玩法序列是 Python 里非常核心的一类数据结构包括列表、元组、字符串、range 对象等。它们有一个共同能力索引和切片。切片的基本格式是[start:end:step]效果是取从start开始到end之前注意end不包含的元素每step个取一个。这个左闭右开规则和range(0, 5)生成 0、1、2、3、4 是一致的记住它就不会在使用切片时差一个数。numbers [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(numbers[2:5]) # 输出 [2, 3, 4] print(numbers[:3]) # 输出 [0, 1, 2] print(numbers[::2]) # 输出 [0, 2, 4, 6, 8] print(numbers[::-1]) # 输出 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]常见反转技巧负索引是另一个常用技巧numbers[-1]取最后一个元素numbers[-3:]取最后三个元素。这个在处理结构化数据、Excel 表格、日志文件时非常顺手。比如读入一个 CSV 文件的每一行需要去掉每行末尾的换行符再取前几列切片就是最高效的方式。字符串、元组都是不可变的切片操作不会修改原数据而是生成新数据。列表切片生成的是新列表修改切片后的新列表不会影响原列表这个特性在需要复制数据时很有用。但要注意列表切片不等于深拷贝如果列表里的元素本身是可变对象比如里面还有子列表切片后修改子列表内容仍然会影响原列表这个细节先记住以后处理嵌套数据时迟早会遇到。3. 流程控制让代码学会选择和重复环境有了基础语法铺垫完了现在进入正题。流程控制是 Python 代码能够处理复杂逻辑的起点包括条件分支、循环、以及循环中配套的break、continue、else等工具。说白了流程控制就是让程序不再是从上到下一路执行到底而是能根据条件做出不同反应能反复执行同一段逻辑。3.1 条件分支if/elif/else 的核心逻辑与缩进问题Python 的if语句语法非常干净score 85 if score 90: grade 优秀 elif score 75: grade 良好 elif score 60: grade 及格 else: grade 不及格 print(grade)这段代码一看就懂。但要注意几个关键点。第一Python 里缩进就是语法本身不像 C 系语言用大括号。同一个代码块里的语句必须保持相同缩进缩进用空格还是 Tab 不能混用我见过太多因为混用 Tab 和空格报IndentationError的新手。建议在 VSCode 里开启设置项editor.renderWhitespace显示空白字符这样一混用立刻能看出来。第二if与elif的组合顺序有讲究。程序会从第一个条件开始逐个判断一旦某个条件成立后面所有elif都会跳过。比如上面这段代码如果score是 92score 90成立就会直接输出优秀不会再去判断score 75了。所以写条件时要把范围更小的、更具体的条件放在前面否则逻辑会被吞掉。一个经典示例score 85 if score 60: print(及格) elif score 85: print(优秀)这样写85分永远输出及格因为score 60先成立elif根本不会执行。你被奇怪的结果困扰时先检查是不是条件顺序写反了。第三条件表达式可以用布尔逻辑组合。比如范围判断60 score 90在 Python 中是合法的不用写score 60 and score 90。这段代码非常适合读书期间判断成绩区间的场景。另外判断列表是否为空时直接if my_list:就够了因为空列表是真值规则中的假。3.2 for 循环与可迭代对象遍历的多种姿势for循环是 Python 里使用频率最高的控制结构。它遍历的对象可以是列表、元组、字典、字符串、文件对象、range对象等任何可迭代对象。基础写法fruits [苹果, 香蕉, 橙子] for fruit in fruits: print(f今天吃{fruit})如果要同时拿到索引和元素新手最容易写错的方式是用range(len(...))然后按下标取。更地道的写法是用enumeratefor index, fruit in enumerate(fruits, start1): print(f第{index}个水果是{fruit})遍历字典时直接遍历拿到的是键scores {张三: 88, 李四: 72, 王五: 95} for name in scores: print(f{name}的分数是{scores[name]})如果你既想要键又想要值用.items()配合序列解包for name, score in scores.items(): print(f{name}得了{score}分)这个写法在处理结构化数据时太常用了比如从 Excel、JSON 里读出来的键值对数据基本都是这么遍历的。range是配合数字循环的常用工具。range(5)生成 0 到 4range(2, 10, 2)生成 2、4、6、8。需要注意range是惰性对象它本身不是一个列表想转成列表可以list(range(5))。在 PyTorch、数据处理这类场景里range对象直接配合循环使用非常常见。3.3 while 循环与 break、continue、else 的组合while循环适合不知道要循环多少次取决于条件什么时候结束的场景。比如不断读取用户输入直到用户输入 quitwhile True: text input(请输入内容输入 quit 退出) if text quit: break print(f你输入的是{text})这里用到了break跳出循环。对应的还有continue它的作用是跳过本次循环的剩余代码直接进入下一次循环。比如只处理偶数for i in range(10): if i % 2 ! 0: continue print(i)还有一个很多人不知道的冷知识while和for后面都可以跟else。这个else分支在循环正常结束时执行如果循环因为break中断则不会执行。比如在循环里查找一个元素numbers [3, 8, 12, 7] for n in numbers: if n 12: print(找到了) break else: print(没找到)这个写法的价值在于不用额外定义一个标志位来记录有没有找到循环正常跑完就说明确实没找到。while同理。刚开始用可能会觉得别扭但习惯后你会爱死它代码简洁了不止一个档次。while循环最怕的是陷入死循环条件永远为真、循环体里又没有break或改变条件的语句。如果你的程序卡住不动了先按CtrlC强制停止再检查循环条件是不是忘了更新这是每个 Python 新手都必须经历的血泪教训。3.4 推导式用一行代码解决循环筛选问题流程控制里最让我觉得Pythonic的体现就是推导式。一句话总结推导式是把创建列表/字典 条件筛选 循环合并成一行表达式的语法糖。写出来的代码简洁、可读性强运行效率通常也更高。列表推导式的基本格式是[表达式 for 元素 in 可迭代对象 if 条件]# 生成 0~9 的平方数列表 squares [x * x for x in range(10)] # 筛选出大于 60 的成绩 scores [72, 58, 91, 63, 47, 88] passed [s for s in scores if s 60] # 处理字符串列表去掉空白并转大写 names [ alice , bob, carol ] clean_names [name.strip().upper() for name in names]是不是非常直观一行代码顶整个 for 循环加 append。字典推导式也同样好用scores {张三: 88, 李四: 72, 王五: 95} passed {name: score for name, score in scores.items() if score 80}推导式并不限定嵌套一层。两层循环的写法比如pairs [(x, y) for x in range(3) for y in range(3)]会生成所有坐标对。但我要提醒一句推导式嵌套太多层会严重降低可读性超过两层的场景建议还是正常写循环。推导式的核心价值是筛选 变换而不是替代所有循环。4. 函数编程把逻辑封装成可复用零件当你学会了流程控制能写出一段完整的逻辑接下来马上会遇到的新问题就是代码重复。同一个判断、同一个处理逻辑在脚本里复制粘贴了好几遍改一个地方就要到处找、到处改这种痛苦我太熟悉了。解决办法就是函数。函数不是 Python 特有概念Python 对其支持非常友好学起来也对新手很友好。4.1 函数的基本结构定义、调用、参数、返回值定义一个函数的语法def calculate_bmi(height, weight): bmi weight / (height ** 2) return bmidef是关键字calculate_bmi是函数名括号里是参数return返回结果。调用方式result calculate_bmi(1.75, 70) print(result)写函数最核心的思路转变不是把代码直接写在脚本里而是思考这段逻辑将来会不会被复用、能不能独立描述。比如计算 BMI、判断成绩等级、清洗一段文本数据都适合单独封装成函数。函数不需要参数也可以不需要返回值也可以。如果不写return函数默认返回None。判断一个函数是否设计合理一个简单标准是它能不能被清晰地说清楚输入什么、输出什么。如果说不清楚说明职责还不够单一拆开会更好。参数传递有一个原理需要理解Python 中变量名是对象的引用。如果你把可变对象比如列表、字典传入函数函数内部修改它外部也会受影响。比如def add_element(items, element): items.append(element) lst [1, 2] add_element(lst, 3) print(lst) # 输出 [1, 2, 3]这既是方便也是风险。如果你想保证传入的列表不被修改就在函数内部先复制一份再操作。4.2 参数进阶默认参数、关键字参数、*args 和 **kwargs参数类型是函数编程里信息量最大的一块。默认参数很实用def greet(name, greeting你好): print(f{greeting}{name}) greet(张三) # 输出 你好张三 greet(李四, 早上好) # 输出 早上好李四但默认参数有一个极经典的坑默认值不要用可变对象。比如def add_task(task, tasks[]): # 这是错的 tasks.append(task) return tasks第一次调用add_task(a)返回[a]第二次调用add_task(b)返回[a, b]因为默认列表在函数定义时就被创建了所有调用共享它。正确写法是默认值设None在函数内部创建def add_task(task, tasksNone): if tasks is None: tasks [] tasks.append(task) return tasks关键字参数调用时要记住函数定义的参数名greet(name王五, greeting嗨)当参数很多而大部分都有默认值时这种写法可读性最好。*args和**kwargs分别处理不确定多少个位置参数和不确定多少个关键字参数的场景。比如写一个求和函数def add_all(*args): return sum(args) print(add_all(1, 2, 3)) # 输出 6 print(add_all(4, 5, 6, 7, 8)) # 输出 30**kwargs适合把配置项收进字典def show_config(**kwargs): for key, value in kwargs.items(): print(f{key} {value}) show_config(hostlocalhost, port3306, userroot)这两个语法本身不难难的是理解函数参数传递的拆包与装包动作。*args把多个位置参数装成元组**kwargs把多个关键字参数装成字典反过来调用时也能用*列表和**字典把参数展开传进去。这个知识点在很多框架源码里经常出现先打好底子。4.3 变量作用域局部变量、全局变量和 UnboundLocalError函数内部定义的变量是局部变量外部不能直接访问def my_func(): x 10 print(x) # NameError反过来函数内部可以读取全局变量但直接给同名变量赋值却会导致一个著名的报错count 0 def add_count(): count count 1 # 报错 UnboundLocalError add_count()原因在于只要函数内部有一个赋值语句Python 在编译时就会把该变量当作局部变量处理。想修改外部全局变量必须显式声明count 0 def add_count(): global count count count 1但这里我更想给你一个经验建议能用函数参数和返回值解决的问题就别用global。global到后面代码变得难以追踪一个变量到底被谁改成什么值了排查起来很痛苦。更好的做法是count 0 count add_count(count)所谓作用域规则Python 遵循 LEGB 顺序局部变量 L、闭包变量 E、全局变量 G、内建变量 B。理解这层顺序之后很多为什么这里能用、那里不能用的疑问会自动解开。4.4 函数式编程思想lambda、map、filter 与函数的一等公民地位Python 里函数本身也是对象可以赋值给变量、可以当作参数传递、也可以作为返回值。这就是函数是一等公民的含义。你不需要对函数式编程有太深的理论储备只需要掌握几个实用工具即可。lambda用于定义简单的匿名函数适合只在某处用一次的场景add lambda x, y: x y print(add(3, 5)) # 输出 8但我觉得lambda更大的价值是和排序、筛选、变换工具搭配使用。比如按字典里某个字段排序students [ {name: 张三, score: 88}, {name: 李四, score: 72}, {name: 王五, score: 95}, ] students.sort(keylambda s: s[score], reverseTrue) print(students)sorted是 Python 里极其常用的函数key参数决定排序的依据配合lambda可以按任意规则排。数据处理时按日期、按数值、按照销售额排序都属于这个套路。map和filter也是很经典的两个函数式工具。map对每个元素应用函数filter根据条件筛选元素scores [72, 58, 91, 63] new_scores list(map(lambda s: s 5, scores)) # 每人加5分 passed list(filter(lambda s: s 60, new_scores)) # 筛选及格的人 print(passed)不过说实话在现代 Python 里推导式通常比map/filter更容易读很多官方文档也默认推荐推导式。我的态度是lambda加sorted的key参数你必须熟练map/filter你至少能读懂别人的代码写不写看个人习惯推导式强烈建议多用因为它的可读性真的更好。真正体现函数式编程价值的是高阶函数、嵌套函数和闭包比如装饰器的基础就是函数接收函数、返回新函数。但这些属于进阶内容先把前面前置知识弄扎实等你写过几个项目再回头研究装饰器会自然水到渠成。5. 常见问题与排查技巧实录最后这部分我把写 Python 过程中高频遇到、又没有一个教程系统讲过的实战问题集合整理出来。这些全是我带着新手走了一遍又一遍总结出来的能帮你少走很多弯路。5.1 环境与安装问题速查问题现象常见原因解决办法命令行输入python提示不是内部或外部命令Python 未加入 PATH重新安装并勾选 Add Python to PATH或手动添加环境变量VSCode 中import numpy报错但终端里 pip 显示已安装VSCode 选了解释器不是安装库的环境手动在 VSCode 选择正确的 Python 解释器pip install下载很慢或超时默认源在国外配置国内镜像源pip install提示 externally-managed-environment系统 Python 不允许直接装包用虚拟环境或者添加--user参数修改环境变量后仍然无效PATH 修改需要重启终端/编辑器关闭当前终端重新打开有个屡试不爽的排查顺序先python --version看解释器在不在再pip install 包名看安装是否成功最后在脚本里print(sys.executable)确认当前解释器是谁。这三个检查做完了90% 的环境问题都能定位。5.2 代码运行中的常见报错缩进错误是最常见的。表现形式有两种IndentationError和TabError。解决办法就是统一用空格VSCode 默认会把 Tab 转成空格。如果代码是从别处复制粘贴来的在 VSCode 里可以用CtrlA全选后直接ShiftTab批量调整缩进或者用ShiftAltF让格式化工具自动整理。TypeError: str object cannot be interpreted as an integer这类报错通常是函数参数传错类型。比如range(5)就会报这个错因为range需要整数参数。应对方法是在报错信息中找到具体是哪一行往前看一下变量的类型用print(type(...))或print(repr(...))辅助判断。UnboundLocalError我前面已经说过核心原因是在函数内部给未赋值的同名变量赋值。排查方法看一下这个变量是不是同时出现在函数内部和外部如果它只是恰好重名干脆给函数内的变量改个名字一劳永逸。IndexError: list index out of range是对列表取下标时下标超了范围。原因通常是列表比预期短比如csv读入的一行比理论上少了几个字段。排查方法在出错前打印len(变量)和实际内容。5.3 调试技巧别死盯代码学会拆解新手容易犯一个习惯性错误看到一个报错整个人脑子空白从头到尾重读代码好几遍也看不出问题。其实排查效率高的人从来不是靠死盯而是靠拆解。第一把脚本分成小块。可以在报错那一行之前加print输出中间变量。比如处理列表时不确定内容直接print(df.head())或print(list(my_list)[:10])看一眼真实数据比什么都管用。第二利用 Python 交互式环境REPL。不确定某个函数的行为时不要在脚本里试错在终端里打开python随手输入几行快速验证。第三尽早在代码里利用assert或简单的if检查条件。写函数时在最前面检查参数类型合法比函数运行到一半再崩溃要省心得多。还有一个很重要的经验报错信息要看最后一行。Python 的报错栈很长新手往往从第一行开始看看到一大堆内部调用立刻头晕。其实你要找的是最下面那几行它会明确告诉你File 你的脚本.py, line 某某行和具体的错误类型。从那里反推而不是从堆栈顶部开始漫无目的地翻。我把话再收一收。很多新手学 Python 学到流程控制和函数这里就会产生迷之自信或者迷之受挫的极端情绪要么觉得都会了要么觉得怎么这么绕。我的个人体会是这个阶段唯一的正确姿态就是多写、多想、再回头看。我见过不少同学学语法时天天刷视频真正自己动手少得可怜结果一到写项目就手忙脚乱。反而是那些老老实实把循环、条件、函数反复拆装的人后面学 numpy、pandas、爬虫、自动化办公非常顺。给你一个具体的小练习建议找一批经典编程题比如输出水仙花数、判断回文数、模拟摇骰子统计频率、用函数封装一个简易计算器。这些练习的价值不在于题目本身多复杂而在于强迫你把流程控制和函数编程组合起来写。每道题都尽量拆成 3 个函数一个负责输入处理、一个负责核心逻辑、一个负责输出展示。练过十道八道之后你会明显感觉到写代码的自然度完全不一样。到那时候再回来看这篇文章提到的大部分细节都会变成你自然而然的理解。
阅读完成 · 觉得有帮助?
咨询建站