news 2026/10/30 3:02:25

跟老齐学Python之开始真正编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
跟老齐学Python之开始真正编程

前言


「开始真正编程」这一步,跨的不是语法,而是心态:从「照着示例敲、跑出同样结果」变成「有个需求,自己想清楚结构,把它变成能运行的代码」。很多人卡在这里——教程都看得懂,一合上就写不出来。


需要先说明一点前提:早期的《跟老齐学Python》系列是按Python 2.7写的,而Python 2.7 已于 2020 年 1 月 1 日停止维护。作者后来出了面向 Python 3 的新版(《跟老齐学Python:轻松入门》),并明确说「以前的版本是 Python 2,本书则为 Python 3」。所以本文一律按 Python 3 讲;如果你手上是旧版材料,凡是出现print "x"、raw_input()、xrange()的地方,都要按本文的写法改写。


本文要解决的是:拿到一个真实需求之后,一个 Python 程序应该长什么样——怎么拆函数、怎么组织入口、怎么处理出错、怎么自己排查。代码以 Python 3.8 及以上为基准,只用标准库。


一、先想结构,再动手


拿到需求别急着敲第一行。先回答三个问题:



  1. 输入是什么、输出是什么?(例如:输入一个目录和一个关键字,输出匹配到的文件清单)

  2. 中间有哪几步?(扫描 → 筛选 → 排序 → 输出)

  3. 每一步失败会怎样?(目录不存在?没有权限?没有匹配?)


这三个问题想清楚,代码的主干就出来了。反之,边想边写通常写出一堆嵌在for里的if。


二、把每一步写成一个函数


「一个函数只做一件事」是让代码可测、可改的最有效纪律。仍然以「在目录里按关键字找文件」为例:


# 适用于 Python 3.8+
from pathlib import Path


def iter_files(root):
"""递归产出 root 下所有普通文件的路径。"""
root = Path(root)
for path in root.rglob("*"):
if path.is_file():
yield path


def match_by_name(paths, keyword):
"""筛出文件名中包含 keyword 的路径。"""
keyword = keyword.lower()
for path in paths:
if keyword in path.name.lower():
yield path


def summarize(paths):
"""把路径按大小升序排列后返回列表。"""
return sorted(paths, key=lambda p: p.stat().st_size)

注意每个函数都只负责一步,并且用「生成器」把「产出」与「消费」解耦:iter_files和match_by_name用yield惰性产出,summarize才真正把它们收集起来。这样即使目录里有几十万文件,也不需要在内存里存两份列表。


三、组织入口


脚本的最外层只做「串联 + 处理失败」,主体逻辑都放进函数:


# 适用于 Python 3.8+
def find(root, keyword):
paths = match_by_name(iter_files(root), keyword)
return summarize(paths)


def main(argv):
if len(argv) != 3:
print("用法:python find.py 目录 关键字")
return 2
root, keyword = argv[1], argv[2]
if not Path(root).is_dir():
print(f"目录不存在:{root}")
return 1
results = find(root, keyword)
if not results:
print("没有匹配的文件")
return 0
for path in results:
print(f"{path.stat().st_size:>10} {path}")
return 0


if __name__ == "__main__":
import sys
raise SystemExit(main(sys.argv))

三个关键点:



  • main(argv)接收参数、返回退出码。这样 main 本身是可测的,不用真的启动进程。

  • if __name__ == "__main__":是入口守卫。有了它,这个文件被别的模块import时不会自动跑一遍,只有直接运行时才执行。

  • raise SystemExit(main(...))把返回码交给进程。返回0表示成功,非零表示失败,这是命令行工具的通用约定。


四、失败要说得清楚


初学者常把异常直接抛给用户,看到一大段 Traceback 完全不知道哪错了。正确做法是在边界处(最外层)把底层异常翻译成人能看懂的话:


# 适用于 Python 3.8+
def safe_find(root, keyword):
try:
return find(root, keyword)
except PermissionError as err:
print(f"没有权限访问:{err.filename}")
return []
except OSError as err:
print(f"文件系统错误:{err}")
return []

规则是:只捕获你能处理的异常,并且给出可操作的提示。不要写裸except:,那会把 Ctrl-C 触发的KeyboardInterrupt也吞掉,程序变得无法中断。


五、调试:从读懂报错开始


真实编程中大部分时间花在排查上。几个够用的手段:



  1. 读 Traceback:从最后一行往回读,最后一行是错误类型与原因,往上找File "...", line N定位到自己写的代码。

  2. print加探针:在怀疑的分支打印变量,注意用repr()看真实内容(能暴露多余空格和换行)。

  3. assert做断言:assert len(results) >= 0, "结果集异常",用于表达「这里本应成立」。

  4. 小步验证:一次只改一处,改完立刻运行,不要攒一大坨再一起调。


# 适用于 Python 3.8+
def inspect_keyword(raw):
"""排查用户输入里肉眼看不见的字符。"""
print("原始值:", repr(raw))
print("长度:", len(raw))
print("去空格后:", repr(raw.strip()))
return raw.strip()

实战:一个能直接用的文件查找工具


把上面各段拼起来,构成一个完整脚本:


# 适用于 Python 3.8+
"""按关键字查找文件:python find.py 目录 关键字"""
import sys
from pathlib import Path


def iter_files(root):
for path in Path(root).rglob("*"):
if path.is_file():
yield path


def match_by_name(paths, keyword):
keyword = keyword.lower()
for path in paths:
if keyword in path.name.lower():
yield path


def summarize(paths):
return sorted(paths, key=lambda p: p.stat().st_size)


def find(root, keyword):
return summarize(match_by_name(iter_files(root), keyword))


def main(argv):
if len(argv) != 3:
print("用法:python find.py 目录 关键字")
return 2
root, keyword = argv[1], argv[2]
if not Path(root).is_dir():
print(f"目录不存在:{root}")
return 1
try:
results = find(root, keyword)
except PermissionError as err:
print(f"没有权限访问:{err.filename}")
return 1
if not results:
print("没有匹配的文件")
return 0
for path in results:
print(f"{path.stat().st_size:>10} {path}")
return 0


if __name__ == "__main__":
raise SystemExit(main(sys.argv))

运行方式:python find.py . py(在当前目录找名字含py的文件)。它只用标准库,跨平台可用。


常见坑点



  1. 所有代码堆在文件顶层


❌ 几十行代码平铺在模块里,没有函数 ✅ 按步骤拆函数,逻辑集中,便于单独验证



  1. 入口守卫写成别的花样


❌if __name__ == "__main__"漏了冒号,或写成单下划线_name_✅ 固定写if __name__ == "__main__":;两边各两个下划线,且必须有冒号



  1. 把库函数名当变量名用


❌list = [1, 2]、sum = 5、id = "x"覆盖内置名字 ✅ 换名,如numbers = [1, 2];内置名字留作函数调用



  1. 不处理异常,脚本直接崩


❌ 目录不存在时抛FileNotFoundError一大段栈 ✅ 在边界处捕获,打印可操作的提示并返回非零退出码



  1. 用裸except:吞掉一切


❌try: ... except: pass连 Ctrl-C 都拦下 ✅ 明确捕获ValueError/OSError等具体类型



  1. print调试后忘了删


❌ 交付的脚本里到处是调试输出 ✅ 调试完清理,或改用logging模块按级别控制



  1. 照旧教程写 Python 2 语法


❌print "结果"、raw_input()、xrange(n)✅ Python 2.7 已于 2020-01-01 停止维护;用print(...)、input()、range(n)



  1. 硬编码路径与魔法数字


❌ 把/Users/xxx/data和if n > 17:直接写死 ✅ 路径用参数或pathlib拼接,常量提取成有名字的变量


总结




环节做法



需求先定输入、输出、步骤、失败情况

拆函数一个函数一件事,用生成器解耦产出与消费

入口main(argv)返回退出码,配if __name__ == "__main__":

错误只捕具体异常,在边界翻译成人话

调试读 Traceback 最后一行;repr()看真实值;assert表达不变量

版本一律 Python 3;旧教程的 2.7 写法要改写



「真正编程」的标志不是写出多复杂的代码,而是写出的代码别人(包括三个月后的自己)能改。做到这一点的路径很朴素:把逻辑拆成职责单一的函数、把失败处理放在边界、把入口收拾干净。从今天起,每写一个小工具都按这个骨架来,很快就成了习惯。




版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 3:02:25

群晖NAS通过Docker部署比特彗星BT下载全攻略

1. 项目背景与需求分析在NAS设备上运行BT下载工具是许多用户的刚需,而群晖NAS作为市场占有率最高的品牌之一,其原生Download Station虽然稳定但功能相对有限。比特彗星作为老牌国产BT客户端,完整版具备种子市场、长效种子等特色功能&#xff…

作者头像 李华
网站建设 2026/10/30 3:02:12

AI全栈技术体系:从基础设施到应用部署的完整指南

1. AI全栈技术体系概述AI全栈技术体系是一个完整的、分层的技术架构,涵盖了从底层基础设施到上层应用的各个环节。这个体系将AI开发和应用过程中的各种技术、工具和平台组织成一个有机整体,使开发者能够系统地构建和部署AI解决方案。在当前的AI浪潮中&am…

作者头像 李华
网站建设 2026/10/30 3:01:51

跟老齐学Python之大话题小函数(1)

前言 "函数"在 Python 里是个大话题,但真正好用的函数往往很小——只做一件事、 名字说得清、输入输出一看就懂。这一篇就围绕"小函数"这个思路,把函数式风格的 常用工具串一遍:函数当值用、lambda、map / filter / sort…

作者头像 李华
网站建设 2026/10/30 3:00:57

电缆温度场仿真在电力传输中的关键应用与COMSOL实践

1. 电缆温度场仿真的工业价值与核心挑战在电力传输领域,电缆温度控制从来都不是一个简单的技术参数问题。去年某沿海城市地铁供电系统的一次故障排查经历让我深刻认识到这一点——由于隧道内电缆沟散热设计缺陷,夏季高温时段多条10kV电缆长期处于临界温度…

作者头像 李华
网站建设 2026/10/30 3:00:50

JavaEE期末题库结构化:知识点树、组卷抽题与掌握度

简介:《JavaEE期末复习题库》面向准备JavaEE课程期末考核的高校学生与需要梳理MyBatis基础知识的自学者,聚焦MyBatis配置元素、SQL映射、ORM理解与工作原理等高频考点。压缩包内共1个docx文件,约41KB,按章节组织填空题、判断题、选…

作者头像 李华
网站建设 2026/10/30 3:00:06

C#两次编译机制解析:从MSIL到JIT的底层原理与避坑指南

简介:这份PPT教程面向零基础或希望系统梳理C#与.NET知识体系的初学者,围绕C#语言基础与面向对象设计展开,帮助读者理解.NET Framework的整体架构与代码编译运行机制。内容从C#语言由来与特点讲起,涵盖程序基本结构、类与命名空间、…

作者头像 李华