我们这一节把Python的输入输出彻底讲透,不绕弯子,直接拆开揉碎。课件编号是1-3,说明前面已经讲过环境搭建、变量和基础数据类型,如果你刚跟上,也没关系,这一节的内容完全可以从零开始理解,然后用它把前面的知识点串起来。所谓输入输出,本质上就是程序跟外部世界对话的方式,input负责听,print负责说,再加上文件读写,让数据能存下来、传出去。不管你是写爬虫、做数据分析、搞自动化办公,还是单纯学语法,输入输出都是绕不开的地基,今天这篇文章就把这块地基每一块砖都给你看清楚,顺带把我实际教学和写代码过程中踩过的坑、总结的技巧都放进去。
1. 先把输入输出看透:为什么每个初学者都要过这一关
1.1 输入输出到底解决什么问题
说句实在话,我第一次带学生入门的时候,发现很多人对print这把锤子有误解,觉得它就是个“在屏幕上显示文字”的工具。其实输入输出远不止这么简单。程序本身的逻辑计算只是内部活动,就像一个人在自己脑子里做心算,别人看不见。而输入输出,才是这个人和外部世界沟通的嘴和耳朵。没有它们,程序就算计算能力再强,也只是个闭门造车的摆设。
从学习的角度拆解,输入输出牵涉几个核心层面:一是跟用户交互,用户通过键盘输入数据,程序处理后再把结果反馈给用户;二是跟文件交互,把数据写入磁盘持久化存储,或从文件读入内存进行处理;三是跟其他程序交互,比如通过标准输入输出管道配合系统命令使用。课件第1-3篇的核心内容,就是围绕着这些交互方式中最基础、最常用的部分展开的。
1.2 这篇课件在整条学习路径上的位置
你可以把整个Python学习路径理解成盖房子。环境搭建是平整地基,变量和数据类型是准备建材,而输入输出就是安装门窗。没有门窗,房子建得再坚固,人也没法住进去。第1-3篇正是起着从“理解数据在内存中长什么样”过渡到“让数据流动起来”的关键作用。
后续你会学到流程控制(if、for、while)、函数、文件处理进阶、异常处理等等,几乎每个环节都要用到输入输出。比如后面做一个小型的学生成绩管理系统,你要用input录入学生姓名和分数,用print展示成绩单,用文件读写保存数据和读取数据。可以说,学不好输入输出,后面寸步难行;学好了,后面很多项目都是在这些基础操作上叠加逻辑而已。
2. 核心语法拆解:print和input的每一个细节
2.1 print的完整用法:不只是“打印”
很多人用print只用到最基础的功能,也就是敲一个print("hello"),然后就结束了。实际上print是一个功能相当丰富的函数,它的完整签名是:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)逐个来看。*objects表示你可以一次性传入多个对象,print会把它们依次输出。比如:
print("姓名", "张三", "年龄", 18) # 输出:姓名 张三 年龄 18第二个参数是sep,代表间隔符,默认是一个空格。如果你想用逗号、横线或者其他符号来分隔输出内容,可以直接指定:
print("2026", "02", "04", sep="-") # 输出:2026-02-04我在实际写脚本的时候,经常用sep这个参数来拼接带格式的输出文本,比如生成带分隔符的日志行。比手动拼接字符串要清爽得多。
第三个参数是end,默认是换行符,也就是说print打印完会自动换到下一行。如果你不想换行,或者想换成别的结尾字符,就设置end:
print("请稍候", end="...") print("完成") # 输出:请稍候...完成这个在写进度提示的时候特别有用,可以让多个print输出保持在同一行,动态更新提示信息。
第四个参数是file,指定输出到哪里。默认输出到控制台,也就是sys.stdout,但你可以把它指向一个文件对象,实现把内容写入文件的功能。举个最常见的例子:
with open("log.txt", "w", encoding="utf-8") as f: print("这是一条日志", file=f)这个用法在很多官方脚本里都会出现,比你手动调用f.write()要直观,尤其适合批量输出格式化文本的场景。
第五个参数是flush,决定是否立即将缓冲区的内容刷出来。默认是False,也就是说print的内容可能会先暂存在内存缓冲区里,等缓冲区满或程序正常结束时才真正输出到目标位置。如果你需要实时看到输出,尤其是在写涉及循环长时间运行的脚本时,可以设置flush=True。举个实际场景:
import time for i in range(5): print(f"进度:{i}", flush=True) time.sleep(1)不设置flush的话,在某些环境下这些输出可能会攒在一起一次性显示,看起来像是程序卡住了。设置了flush=True就能保证每条输出立即显示。
2.2 input的正确姿势:拿到的永远是字符串
input函数的作用是从标准输入读取一行文本。它有一个可选参数prompt,用于在等待输入前输出一行提示文字:
name = input("请输入你的名字:") print("你好,", name)这个函数最简单,也最容易踩坑。最大的坑就是它的返回值永远是字符串,不管你输入的是数字、小数还是别的什么。看下面这个例子:
age = input("请输入你的年龄:") print(age + 1)运行这段代码会直接报错,因为age是字符串类型,字符串不能和整数直接相加。正确做法是进行类型转换:
age = int(input("请输入你的年龄:")) print(age + 1)这是初学者最容易犯的错误,也是每位老师都要反复强调的重点。input拿到的数据要不要转换、转换成什么类型,取决于你后续要对这个数据做什么操作。做算术运算就转成int或float,做拼接就直接用字符串。
另一个值得注意的细节是input在读取的时候会去掉末尾的换行符,但是不会去掉你输入内容前后的空格。如果你不小心多敲了空格,拿到的字符串就可能带着多余的空格。比如用户输入了“ 张三 ”,那么name的值就是“ 张三 ”,打印出来倒还好,如果拿来做匹配判断就会出问题。稳妥的做法是加上strip()方法:
name = input("请输入你的名字:").strip()2.3 格式化输出的三把武器
格式化输出也是输入输出这一课的重头戏。Python里主要有三种方式,老牌的%格式化、比较古老的format()方法、以及现在最推荐的f-string。
%格式化是Python早期风格。比如:
name = "李四" score = 92.5 print("%s的分数是%.2f" % (name, score))这里%s表示字符串占位符,%f表示浮点数占位符,%.2f表示保留两位小数。这种风格在老代码里很常见,但写起来比较繁琐,容易占位符和参数对应错,我已经很少在新代码里用了。
format()方法比%要灵活一些,支持按位置、按名称等方式传参:
print("{}的分数是{:.2f}".format(name, score))这种方式可读性不错,但是写起来依然有点绕,尤其是当参数多、格式复杂时,大括号里的格式控制符很容易写错。
f-string是Python 3.6引入的特性,也是我现在最推荐的方式。它直接在字符串前面加一个f,然后把变量名或表达式写进大括号里:
print(f"{name}的分数是{score:.2f}")f-string的好处有三个:一是不需要额外传参,直接把变量名写进去就行,代码看着特别清爽;二是大括号里可以直接写表达式,比如f"{a + b}"、f"{name.upper()}";三是性能比前两种更好。我用f-string写了无数行代码,确实是最符合直觉的格式化方式。
3. 实操演练:跟着敲一遍就能上手
3.1 第一个实操:个人信息登记小脚本
光看语法是不够的,手要跟着动起来。我设计了一个非常简单但又包含完整输入输出链路的练习,就是写一个个人信息登记的脚本。需求如下:让用户输入姓名、年龄、城市,然后程序把这三项信息打印成一行整齐的格式化文本。代码如下:
name = input("请输入姓名:").strip() age = input("请输入年龄:").strip() city = input("请输入城市:").strip() print("=" * 40) print(f"姓名:{name}") print(f"年龄:{age}") print(f"城市:{city}") print("=" * 40)这里有几个细节你可以感受一下。第一,我给每个input都加了strip(),确保用户不小心敲出的空格不会混入数据。第二,print("=" * 40)这一行利用字符串乘法输出了一条分隔线,简单却很实用。第三,年龄我故意没有转成int,因为这里只是展示信息,不参与任何计算,保持字符串完全没问题。
3.2 第二个实操:简单计算器,体会类型转换的重要性
再来看一个稍微进阶一点的练习,写一个两数相加的计算器。这个练习的核心理念就是:input拿到的是字符串,转成数字才能做算术运算。
num1 = float(input("请输入第一个数字:")) num2 = float(input("请输入第二个数字:")) result = num1 + num2 print(f"{num1} + {num2} = {result}")这里使用float而不是int,有一个好处是它同时支持整数和小数输入。比如输入3和4.5,都能正确转换并参与运算。如果只转int,输入3.5就会报错。
这个练习看起来简单,但却是很多复杂程序的雏形。比如你后面学列表、字典、函数之后,可以把这段逻辑封装成一个函数,再做一个循环不断接收用户输入,就变成了一个可交互的迷你计算器。
3.3 第三个实操:写入文件和读取文件
控制台输入输出只是第一步,真正的数据往往需要落地保存,这就涉及文件输入输出。先看一个最基础但很完整的例子,把用户输入的三行文字保存到一个文件里,然后再读取出来显示:
lines = [] for i in range(3): line = input(f"请输入第{i+1}行内容:") lines.append(line) with open("output.txt", "w", encoding="utf-8") as f: for line in lines: f.write(line + "\n") print("文件写入完成,开始读取内容:") with open("output.txt", "r", encoding="utf-8") as f: content = f.read() print(content)这个例子涵盖了三个重要知识点。第一个是open函数的使用,第一个参数是文件路径,第二个参数是模式("w"表示写入,"r"表示读取),第三个参数encoding指定编码格式,以utf-8写入才能确保中文正常显示。第二个是with语句的用法,它能自动管理文件资源,即使处理过程中出现异常,文件也会被正确关闭,不用手动调用f.close()。第三个是文件读取的简单方式,read()一次把整个文件内容读成一个字符串。
3.4 第四步:命令行参数输入
交互式的input是面向用户的输入方式,但在自动化场景里,更多用的是命令行参数输入。比如你写了一个脚本prepare_report.py,希望运行的时候直接通过命令行传入日期和文件名参数,而不是每次手动输入。
import sys if len(sys.argv) < 3: print("用法:python prepare_report.py <日期> <输出文件名>") sys.exit(1) date = sys.argv[1] filename = sys.argv[2] print(f"正在为{date}生成报告,保存到{filename}")sys.argv是一个列表,其中第0个元素是脚本文件名本身,第一个参数开始才是你传入的自定义参数。运行方式如下:
python prepare_report.py 2026-02-04 report.txt这种输入方式在写自动化脚本、定时任务、数据分析流水线时非常常用。强烈建议初学者在掌握了input之后,尽早接触sys.argv,它能让你对“程序如何接收外部数据”有更完整的理解。
4. 新手最容易踩的坑与排查技巧
4.1 常见报错速查表
教学过程中我发现,很多初学者在输入输出上遇到的问题高度集中。我把最典型的一批整理成了下面这个表格,遇到报错直接对着查就行。
| 错误现象 | 发生原因 | 解决方法 |
|---|---|---|
| TypeError: can only concatenate str (not "int") to str | 直接用字符串+整数做拼接 | 把数字用str()转成字符串,或改用f-string |
| ValueError: invalid literal for int() | int()试图转换非数字字符串,比如"abc"或"3.5" | 确认输入内容能转为int,小数请用float() |
| FileNotFoundError | 读取不存在的文件时没有处理异常 | 检查文件路径,或先判断os.path.exists() |
| UnicodeDecodeError | 用错误编码读取文本文件 | 打开文件时指定正确的encoding参数,中文一般用utf-8 |
| SyntaxError: Missing parentheses in call to 'print' | Python 3里漏写了print的括号 | Python 3中print是一个函数,必须加括号 |
| NameError: name 'x' is not defined | 变量名拼写错误或者作用域问题 | 检查变量名是否一致,尤其注意input赋值是否有冲突 |
这张表你不需要背,只要在遇到报错时回来对照排查即可。编程的常态就是不断遇到错误、不断解决错误,这恰恰是学习最快的路径。
4.2 输入输出调试的几个实用偏方
除了看报错信息,我还有几个调试输入输出问题的小偏方,实测下来非常管用。
第一个偏方是“打印类型”。当你搞不清楚input到底返回了什么类型时,直接在代码里加一行print(type(变量名)),立即就能看出它是str、int还是其他类型。很多时候问题瞬间就清楚了。比如:
data = input("输入一个数字:") print(type(data)) # <class 'str'>第二个偏方是“单独测一行”。如果一段程序运行出错,不要慌着从头看到尾,先在出错那一行的上面加print,把涉及的关键变量值打出来。比如怀疑文件路径不对,就在open之前先print("文件路径是:", path),确认路径内容。
第三个偏方是“最小化复现”。如果程序报错并且你定位不到问题,可以新建一个空脚本,只写几行最简代码来触发同样的问题。比如单独测一下float()转换非数字字符串会报什么错。把问题范围缩到最小,解决难度就大幅下降了。
第四个偏方是“用repr看细节”。print一个字符串时,如果里面含不可见字符(比如换行、制表符、空格),你是看不出来的。改用repr()来输出,就能看到转义后的样子。举个例子:
name = input("输入名字:") print(repr(name)) # 如果你输入了 "abc " ,输出显示 'abc ' ,末尾空格一目了然这个技巧在处理用户输入、清洗数据时极其好用。
4.3 开发和调试过程中可能遇到的几个典型场景
除了直接报错,还有一些不报错但结果不对的隐蔽问题。最常见的就是input提示符过了一万行代码都看不见,尤其是当程序前面有大量print输出的时候,提示文字被推到屏幕外面,用户根本看不到程序在等输入。解决思路是在等待输入前,清屏或者把提示信息做得更醒目一些。
还有一个典型的坑是Windows系统和Linux系统在文件路径上的差异。Windows路径用反斜杠,比如"C:\Users\test\data.txt",但反斜杠在Python字符串里是转义字符,所以要么双写反斜杠写成"C:\Users\test\data.txt",要么使用原始字符串r"C:\Users\test\data.txt"。这个细节在文件输入输出时特别容易踩,一定要记住。
多个input连续出现时,如果用户在输入内容时不小心敲了回车或者多打了空格,后续的转换就容易出问题。我建议在需要连续输入多行数据的场景中,把所有输入先收进列表,后续统一进行清洗和类型转换,而不是每读一行就立刻转换。
5. 从课件到实战:输入输出还能怎么玩
5.1 用输入输出搭建一个命令行小工具
不要小看这一课的内容,输入输出一旦灵活运用,已经足够搭建出非常有用的命令行小工具。我举个例子,比如写一个代办事项管理的最小程序:
tasks = [] while True: print("\n1. 添加事项 2. 查看事项 3. 退出") choice = input("请选择操作:").strip() if choice == "1": task = input("请输入事项内容:").strip() if task: tasks.append(task) print("已添加") elif choice == "2": if tasks: for i, task in enumerate(tasks, 1): print(f"{i}. {task}") else: print("暂无待办事项") elif choice == "3": print("再见") break else: print("无效选择,请重新输入")这个程序只用到了input、print、列表、while循环、if判断,全是前面学过的最基础的东西,但组合起来就是一个有实际使用价值的小工具。很多大型软件的管理界面,本质上也是这样的循环结构。
5.2 文件输入输出在真实项目里的地位
写入文件和读取文件看起来简单,但在真实项目里地位极高。数据分析的流程一般是:从数据源读文件,处理之后写回文件;爬虫抓下来的数据写入文件保存;日志系统将运行信息写入日志文件;配置文件读取后控制程序行为。
举一个贴近生活的例子,假如你想分析自己一个月的消费记录,简单方式是把每一笔开销按“日期,类别,金额”逐行写在txt或CSV文件里,然后用Python读取这个文件做统计:
total = 0 count = 0 with open("expenses.txt", "r", encoding="utf-8") as f: for line in f: parts = line.strip().split(",") if len(parts) == 3: total += float(parts[2]) count += 1 print(f"共有{count}笔消费,总金额:{total:.2f}元")这里用到了read的逐行迭代方式,配合split方法把每行按逗号拆开。这个思路可以扩展到几乎所有结构化文本文件的处理中,比如老师留下的成绩表、收款记录、库存清单等等。
5.3 与系统交互:标准输入输出和管道
还有一种输入输出应用方式是标准输入输出配合系统管道来使用,也就是用|把一个程序的输出连接到另一个程序的输入。比如你写了一个Python脚本用于过滤日志中的错误行,就可以和其他命令行工具配合,形成一条完整的处理链。这在日常系统维护中非常实用,初学者可以先了解有这样一个扩展方向,用到时再深入学习。生活化一点的类比就像流水线:一台机器的产出,成为下一台机器的原料,输入输出就是这中间的传送带。
6. 课程练习与自我检测
6.1 三道递进练习
空谈无用,学完必须自己动手。我给初学者设计了三个难度递进的练习。第一题是仿写,第二题是改进,第三题是综合应用。做完这三题,这一章的内容就可以算真正入门了。
第一题:仿写一个简单的用户信息收集程序,要求用户输入姓名、学号、所在城市,然后用f-string把它们合并打印成一条标准格式的信息。这个练习纯粹为了练习input和print的基本用法,不涉及任何高级逻辑。
第二题:在上一个程序的基础上,增加一个功能——把收集到的信息写入文件,并且能够在下次运行程序时读取出来展示。这个练习重点考察文件读写的基本流程,尤其是with open的规范写法。
第三题:设计一个迷你抽奖程序。程序预先准备一个名单文件,每行存一个名字,运行时读取名单,随机抽取一个名字,并把中奖结果写入中奖记录文件。这个练习涉及文件读取、随机数、字符串处理和文件写入,是一个完整的小项目。
第三题参考答案(先用后看,自己动脑写一遍收获更大):
import random with open("names.txt", "r", encoding="utf-8") as f: names = [line.strip() for line in f if line.strip()] if not names: print("名单为空") else: winner = random.choice(names) print(f"恭喜 {winner} 中奖!") with open("winners.txt", "a", encoding="utf-8") as f: f.write(winner + "\n")注意这里用了"a"模式(追加模式),每次抽出的中奖者都追加到winners.txt文件末尾,不会覆盖历史记录。
6.2 检验学习效果的几个关键问题
做完了练习,可以用几个问题来检验自己是否真正理解。第一个问题:input的返回值类型是什么,为什么需要做类型转换?第二个问题:print函数的end和sep参数分别控制什么,能不能举一个具体的使用场景?第三个问题:用with语句打开文件和使用open+close有什么区别,为什么推荐用with?第四个问题:f-string相比%格式化和format()方法有什么优势,什么情况下选用哪种?如果你能不看资料就回答出来,这一课的知识点就已经掌握得比较扎实了。
7. 经验随笔:我是如何看待“输出”这个闭环的
讲完所有知识点,我再分享一点个人体会。做任何程序,本质上都在处理“输入 -> 处理 -> 输出”这条链路。能写好输入输出,并不只是学了一两个函数,而是在建立一种思考方式:数据从哪来,经过什么变换,最终到哪去。
我在实际写代码的过程中,越来越觉得朴素的基础操作反而是用得最频繁的。华丽的高级技巧可能一天用不上一次,但print、input、open、write这些基础操作,几乎每天都要面对。把简单的事情做熟练了,复杂的事情自然就能一步步拆解。这也是我为什么在课件编排里特别重视1-3这一节的原因。别看它内容看起来不多,当你真正熟练掌握了字符串的拼接与格式化、输入的类型转换、文件读写的各种模式,后续学习文件处理进阶、面向对象、数据分析,都会顺畅很多。
这节课就到这里。我建议你把文章里的每个代码都亲自敲一遍,敲完再试着改动一下参数、换一换场景,比如把个人信息改成商品信息、把计算器改成温度转换器。动手和不动手的差距,往往就在这一周的功夫里拉开了。