第1章 1.5 输入输出与错误处理
上章回顾:上一章我们折腾了字符串,学会用引号和 heredoc/nowdoc 往变量里塞大段文字。说白了,程序就是「加工数据的工厂」,光有原材料(数据)还不够,我们得学会把东西放进去(输入)和把结果拿出来(输出),还得学会机器坏了怎么办(错误处理)。这一章,我们让这个工厂能真正跑起来。
🎯 开场 3 分钟:为什么要学这个?
你有没有遇到过这些情况?
- 写了个计算器程序,结果只能在黑窗口里显示,想把结果存到文件里慢慢看?
- 每次改程序参数都要改代码,能不能启动时让我自己输入?
- 程序跑到一半突然崩了,满屏红色报错,完全不知道哪里出了问题?
这些都是输入输出(I/O)和错误处理没整明白导致的。说白了:
输入 = 跟程序说话,输出 = 程序跟你说话,错误处理 = 程序跟你说「我搞不定,但别慌」
学完这章,你能让程序真正和你互动——问你要数据、处理完告诉你结果、万一翻车了还能体面收场。
🧱 基础 25 分钟:核心概念\n\n
\n\n
\n\n
什么是输入输出?
生活类比:想象你去早餐店点餐。
- 输入 = 你跟店员说「老板,来碗豆浆加油条」
- 输出 = 店员把做好的豆浆和油条端给你
程序也一样:
# 输入:让用户输入名字
名字 = input("你叫什么?")
# 输出:打印问候语
print("你好," + 名字 + "!欢迎光临")
运行效果:
你叫什么?张三
你好,张三!欢迎光临
input() 就是程序「问你话」,print() 就是「告诉你结果」。
print() 的各种姿势
print() 不只是打印文字,它还是个多面手:
# 1. 打印单个字符串
print("你好世界")
# 2. 打印多个内容(自动加空格)
print("我", "爱", "编程")
# 3. 指定分隔符
print("2024", "01", "15", sep="-")
# 4. 指定结束符(默认换行,改成空格)
print("第一行", end=" ")
print("第二行(不换行)")
# 5. 打印到文件
with open("结果.txt", "w", encoding="utf-8") as f:
print("写入文件的内容", file=f)
输出:
你好世界
我 爱 编程
2024-01-15
第一行 第二行(不换行)
一句话解释:前几个好理解,第 5 个是往文件里写东西,「with open...as f」的意思是「打开文件当文件夹用,用完自动关」。
input() 的细节
input() 拿到的永远是字符串!这是个新手高频踩坑点:
# 陷阱:直接做加法
年龄 = input("你几岁?")
print("明年你就", 年龄 + 1, "岁了") # ❌ 报错!字符串不能直接加数字
# 正确做法:转成数字
年龄 = input("你几岁?")
print("明年你就", int(年龄) + 1, "岁了") # ✅ 先把字符串转成整数
输入:
你几岁?25
明年你就 26 岁了
一句话解释:int() 是把字符串「翻译」成整数的函数。input() 问用户要什么,用户给的都是文字(字符串),想当数字用就得转换。
格式化输出:f-string(推荐)
拼接字符串用 + 太累了,Python 3.6+ 提供了f-string,超方便:
姓名 = "王小明"
年龄 = 18
成绩 = 95.5
# f-string 写法:前面加个 f,里面用 {} 包裹变量
print(f"学生:{姓名},年龄:{年龄}岁,成绩:{成绩}分")
# 还能做计算
print(f"明年 {姓名} 就 {年龄 + 1} 岁了")
# 保留小数位数
print(f"平均分:{成绩:.1f}") # .1f 表示保留1位小数
输出:
学生:王小明,年龄:18岁,成绩:95.5分
明年 王小明 就 19 岁了
平均分:95.5
生活类比:f-string 就像填表,直接在表格的空格里填内容,不用再剪剪贴贴。
错误处理:try...except
程序翻车是常态,关键是怎么体面地处理:
# 场景:让用户输入两个数,做除法
try:
a = input("请输入被除数:")
b = input("请输入除数:")
结果 = int(a) / int(b)
print(f"结果是:{结果}")
except ValueError:
print("⚠️ 输入的不是有效数字,请重新输入")
except ZeroDivisionError:
print("⚠️ 除数不能为0,老弟!")
except Exception as e:
print(f"⚠️ 出了点小问题:{e}")
finally:
print("——程序执行完毕——")
运行效果(除数为0时):
请输入被除数:10
请输入除数:0
⚠️ 除数不能为0,老弟!
——程序执行完毕——
一句话解释:try 里的代码「试试看」,except 捕获具体错误类型,「finally」是不管成功失败都执行的收尾代码。
读取文件:read / readline / readlines
文件是最常见的输入来源:
# 读取整个文件(适合小文件)
with open("购物清单.txt", "r", encoding="utf-8") as f:
内容 = f.read()
print(内容)
# 逐行读取(适合大文件)
with open("购物清单.txt", "r", encoding="utf-8") as f:
for 行 in f:
print(行.strip()) # .strip() 去掉每行末尾的换行符
一句话解释:open("文件名", "r", encoding="utf-8"),「r」是 reading,「encoding="utf-8"」是告诉电脑用 UTF-8 编码读中文。
🔥 实战 35 分钟:3 个递进小项目
项目 1:个人介绍问答机(5 分钟)
# 个人介绍问答机
print("=" * 20)
print("欢迎使用个人信息采集器")
print("=" * 20)
姓名 = input("1. 你叫什么?")
城市 = input("2. 你住在哪个城市?")
职业 = input("3. 你的职业是?")
爱好 = input("4. 你有什么爱好?")
print()
print("📋 以下是你的信息确认:")
print("-" * 20)
print(f"姓名:{姓名}")
print(f"城市:{城市}")
print(f"职业:{职业}")
print(f"爱好:{爱好}")
print("-" * 20)
print("信息已录入,感谢配合!")
预期输出:
====================
欢迎使用个人信息采集器
====================
1. 你叫什么?李四
2. 你住在哪个城市?北京
3. 你的职业是?程序员
4. 你有什么爱好?跑步
📋 以下是你的信息确认:
--------------------
姓名:李四
城市:北京
职业:程序员
爱好:跑步
--------------------
信息已录入,感谢配合!
一句话解释:收集4条用户输入,用 f-string 拼成完整信息展示出来。核心就是 input() + print() 的配合。
项目 2:通讯录管理器(15 分钟)
从文件读取联系人,做增删改查:
import json
import os
通讯录文件 = "通讯录.json"
# 初始化:如果文件不存在,创建一个空通讯录
if not os.path.exists(通讯录文件):
with open(通讯录文件, "w", encoding="utf-8") as f:
json.dump({}, f, ensure_ascii=False)
def 加载通讯录():
with open(通讯录文件, "r", encoding="utf-8") as f:
return json.load(f)
def 保存通讯录(通讯录):
with open(通讯录文件, "w", encoding="utf-8") as f:
json.dump(通讯录, f, ensure_ascii=False, indent=2)
def 显示菜单():
print("\n📒 通讯录管理")
print("1. 查看所有联系人")
print("2. 添加联系人")
print("3. 删除联系人")
print("4. 退出")
def 查看联系人(通讯录):
if not 通讯录:
print("通讯录是空的,快添加一个吧!")
return
for 姓名, 电话 in 通讯录.items():
print(f" {姓名}:{电话}")
def 添加联系人(通讯录):
姓名 = input("请输入姓名:")
电话 = input("请输入电话:")
通讯录[姓名] = 电话
保存通讯录(通讯录)
print(f"✅ 已添加 {姓名},电话:{电话}")
def 删除联系人(通讯录):
姓名 = input("请输入要删除的姓名:")
if 姓名 in 通讯录:
del 通讯录[姓名]
保存通讯录(通讯录)
print(f"✅ 已删除 {姓名}")
else:
print(f"⚠️ 没找到 {姓名} 这个联系人")
# 主循环
while True:
显示菜单()
选择 = input("请选择功能(1-4):")
通讯录 = 加载通讯录()
if 选择 == "1":
查看联系人(通讯录)
elif 选择 == "2":
添加联系人(通讯录)
elif 选择 == "3":
删除联系人(通讯录)
elif 选择 == "4":
print("再见!👋")
break
else:
print("⚠️ 无效选择,请输入 1-4 之间的数字")
预期输出(添加两个联系人后查看):
📒 通讯录管理
1. 查看所有联系人
2. 添加联系人
3. 删除联系人
4. 退出
请选择功能(1-4):2
请输入姓名:张三
请输入电话:13800138000
✅ 已添加 张三,电话:13800138000
请选择功能(1-4):1
📒 通讯录管理
1. 查看所有联系人
2. 添加联系人
3. 删除联系人
4. 退出
张三:13800138000
一句话解释:用 JSON 文件存数据,json.dump() 写入,json.load() 读取。程序运行时会保存到硬盘,关闭后再打开数据还在。
项目 3:数据清洗脚本(15 分钟)
读取 CSV 文件,筛选并统计:
import csv
# 模拟一份成绩单 CSV(实际使用时从文件读取)
成绩数据 = """姓名,语文,数学,英语
王小明,85,92,88
李四,78,85,92
张小红,95,88,91
陈大明,62,75,68
刘小丽,88,95,87
"""
# 写入临时文件模拟
with open("成绩单.csv", "w", encoding="utf-8", newline="") as f:
f.write(成绩数据)
# 读取并清洗数据
平均分列表 = []
优秀生 = []
不及格 = []
try:
with open("成绩单.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for 行 in reader:
try:
姓名 = 行["姓名"]
语文 = int(行["语文"])
数学 = int(行["数学"])
英语 = int(行["英语"])
平均分 = (语文 + 数学 + 英语) / 3
平均分列表.append(平均分)
if 平均分 >= 90:
优秀生.append(f"{姓名}({平均分:.1f})")
if 语文 < 60 or 数学 < 60 or 英语 < 60:
不及格.append(姓名)
print(f"{姓名}:语文{语文},数学{数学},英语{英语},平均{平均分:.1f}")
except ValueError as e:
print(f"⚠️ 数据格式错误:{行},原因:{e}")
except FileNotFoundError:
print("⚠️ 文件不存在!")
except Exception as e:
print(f"⚠️ 发生错误:{e}")
# 统计结果
print("\n" + "=" * 30)
print("📊 统计结果")
print("=" * 30)
if 平均分列表:
print(f"全班平均分:{sum(平均分列表)/len(平均分列表):.1f}")
print(f"最高分:{max(平均分列表):.1f}")
print(f"最低分:{min(平均分列表):.1f}")
if 优秀生:
print(f"🌟 优秀生(≥90分):{', '.join(优秀生)}")
else:
print("🌟 优秀生(≥90分):暂无")
if 不及格:
print(f"⚠️ 有不及格科目:{', '.join(不及格)}")
else:
print("⚠️ 有不及格科目:暂无")
预期输出:
王小明:语文85,数学92,英语88,平均88.3
李四:语文78,数学85,英语92,平均85.0
张小红:语文95,数学88,英语91,平均91.3
陈大明:语文62,数学75,英语68,平均68.3
刘小丽:语文88,数学95,英语87,平均90.0
==============================
📊 统计结果
==============================
全班平均分:84.6
最高分:91.3
最低分:68.3
🌟 优秀生(≥90分):张小红(91.3), 刘小丽(90.0)
⚠️ 有不及格科目:陈大明
一句话解释:用 csv.DictReader 逐行读文件,每个学生的三科成绩转成整数后计算平均分,遇到无效数据用 try...except 捕获,不影响后续处理。
💪 进阶 20 分钟:常见坑 + 性能小贴士
❌ 坑 1:input() 拿到的永远是字符串
# ❌ 错误
价格 = input("商品价格:")
折后价 = 价格 * 0.8 # 字符串不能直接乘!
# ✅ 正确
价格 = float(input("商品价格:")) # 转成小数
折后价 = 价格 * 0.8
❌ 坑 2:文件路径里的反斜杠
# ❌ 错误(Windows 路径)
with open("C:\Users\张三\文档\成绩单.txt", "r") as f: # \U \T 等会被当成转义符
# ✅ 正确(两种方式)
# 方式1:raw string
with open(r"C:\Users\张三\文档\成绩单.txt", "r") as f:
# 方式2:正斜杠(Python 跨平台兼容)
with open("C:/Users/张三/文档/成绩单.txt", "r") as f:
❌ 坑 3:打开文件忘了关
# ❌ 错误(文件没关,可能丢数据)
f = open("test.txt", "w")
f.write("你好")
# 如果这中间程序崩了,文件可能没写入
# ✅ 正确(with 自动关)
with open("test.txt", "w") as f:
f.write("你好")
# with 块结束自动关闭,出错也关
❌ 坑 4:捕获了异常却啥也不干
# ❌ 错误(静默吞掉错误,debug 地狱)
try:
结果 = int(用户输入)
except:
pass
# ✅ 正确(至少打印出来)
try:
结果 = int(用户输入)
except ValueError as e:
print(f"⚠️ 无效输入:{e}")
❌ 坑 5:循环中修改正在遍历的列表
# ❌ 错误
列表 = [1, 2, 3, 4, 5]
for 数 in 列表:
if 数 % 2 == 0:
列表.remove(数) # 边遍历边删,可能漏元素
# ✅ 正确(遍历副本)
列表 = [1, 2, 3, 4, 5]
for 数 in 列表[:]: # 切片 [:] 创建副本
if 数 % 2 == 0:
列表.remove(数)
性能小贴士:大量输出用 sys.stdout
import sys
# 如果输出很多行,用 write 比 print 稍快
输出列表 = [f"第{i}行" for i in range(1000)]
# 普通方式(每行都调用 print)
for 内容 in 输出列表:
print(内容)
# 优化方式(最后一起输出)
sys.stdout.write("\n".join(输出列表))
调试技巧:三剑客
# 1. print 大法(最简单)
print(f"调试:变量a = {a}, 变量b = {b}")
# 2. assert 大法(断言,条件不对就报错)
assert a > 0, f"a 必须是正数,当前值是 {a}"
# 3. logging 大法(生产环境推荐)
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.debug(f"变量a = {a}")
logger.info("程序运行正常")
logger.warning("警告:接近上限")
logger.error("出错了!")
✏️ 练习题 + 作业题
练习题(5 道,10 分钟)
练习 1(2 分钟):个人信息输出
- 输入:运行程序,输入姓名「张三」,年龄「28」
- 预期输出:张三,你好!你今年 28 岁了
- 提示:注意 input 拿到的是字符串,int() 转年龄后才能 +1
练习 2(2 分钟):加个判断
- 输入:在练习 1 基础上,增加判断,如果年龄 ≥ 18,额外输出「你是成年人」
- 预期输出:张三,你好!你今年 28 岁了\n你是成年人
- 提示:input 获取年龄后,用 if 判断即可
练习 3(2 分钟):处理新数据
- 输入:有一份 JSON 文件 {"苹果": 5, "香蕉": 3, "橙子": 8},统计水果总数
- 预期输出:水果总数:16
- 提示:参考项目 2 的 JSON 读写,用 sum(values) 求和
练习 4(2 分钟):串联两个项目
- 输入:在项目 2 通讯录基础上,增加「搜索」功能
- 预期输出:输入姓名能查到对应电话,查不到提示「未找到」
- 提示:在主循环里加一个 "5. 搜索" 选项
练习 5(2 分钟):错误处理
- 输入:程序要求输入数字,用户输入「abc」
- 预期输出:⚠️ 输入的不是有效数字
- 提示:用 try...except ValueError 捕获错误
作业题(30 分钟 - 2 小时)
作业:做一个「个人财务小管家」
需求描述:
帮小明管理零花钱,支持记录收入/支出、查看余额、导出月报。
功能点:
1. 记账:输入「收入/支出 + 金额 + 备注」,保存到 JSON 文件
2. 查账:查看所有记录,支持按类型筛选(只看支出或只看收入)
3. 余额:显示当前余额(收入总和 - 支出总和)
4. 月报:生成月份统计(本月收入多少、支出多少、结余多少)
加分项:
1. 支持按月份筛选(如只看 2024-01 的记录)
2. 添加「预算」功能,设定每月预算,超支时警告
验收标准:
- 能成功运行,不报错
- 数据保存到 JSON 文件后,关闭程序再打开,数据还在
- 余额计算正确
提交方式:评论区贴代码或 GitHub 链接
📚 总结 + 资源
本章 3 个核心点
- 输入靠
input(),输出靠print(),但 input 拿到的永远是字符串,要转换再用 - 错误处理用
try...except,让程序翻车时也能体面收场,而不是满屏红色报错 - 文件 I/O 用
with open...as,省去手动关闭文件的麻烦,数据能持久保存
延伸学习资源
- Python 官方文档:输入输出 —— 最权威的参考手册
- Python 官方文档:错误和异常 —— 错误处理的详细说明
- 书籍《Python编程:从入门到实践》—— 第 10 章文件和数据,第 14 章测试代码
互动钩子:
💬 你在写程序时踩过哪些输入输出或错误处理的坑?评论区聊聊,老粉优先回复!
下章预告:
现在你学会了「让程序和你说话」,但如果需要根据不同情况做不同处理呢?比如「成绩及格 print 鼓励,挂科 print 安慰」—— 下一章我们来解决这个问题。

评论(0)