简介:本文从标准输入输出出发,系统讲解Python中print与input的底层机制、文件对象的角色,以及如何用open/write/with实现可靠的文件读写。读者将掌握标准流重定向、文件模式选择、上下文管理器与异常安全等关键实践,写出更健壮的I/O代码。
在任何一门编程语言中,输入与输出(I/O)都是程序与外界交互的桥梁。Python 把这件事做得相当简洁:输入靠 input(),输出靠 print(),而文件读写则交给 open() 返回的文件对象。本文将从命令行交互出发,逐层剖析 Python 的 I/O 机制,并给出可落地的工程实践建议。
初学者接触 Python 时,最常见的场景是在交互式解释器(REPL)中逐行输入代码并立即看到结果:
>>> name = input("请输入你的名字:")请输入你的名字:Alice>>> print("你好," + name)你好,Alice
这种方式反馈即时,适合验证语法和小片段逻辑。但当代码量增长后,就需要把代码写入 .py 模块文件,再通过系统命令行执行:
python demo.py
此时程序的输出会打印到终端,输入则来自键盘。理解这一过程背后发生了什么,是掌握 Python I/O 的关键。
很多人把 print() 仅仅当作“打印函数”,实际上它的完整签名中有一个常被忽略的参数:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
其中 file 的默认值是 sys.stdout,即标准输出(Standard Output),通常对应系统终端。也就是说,print() 做的事情本质上是:把对象转成字符串,然后写入某个“类文件对象”。
既然 file 可以指定,我们就能把输出重定向到文件:
f = open('1.txt', 'w')print('12345', file=f)f.close()
执行后终端不会显示任何内容,而当前工作目录下会多出一个 1.txt,内容为 12345。这里 f 就是一个文件输出对象,它替代了默认的 sys.stdout,成为新的输出目标。
文件写到了哪里?很多人会困惑。可以通过标准库查看:
>>> import os>>> os.getcwd()'/path/to/your/project'
os.getcwd() 返回当前工作目录,相对路径 1.txt 就是相对于它解析的。若不确定文件位置,养成使用绝对路径或先确认工作目录的习惯,能避免大量“文件找不到”的排查时间。
用 print(file=...) 写文件虽然可行,但语义上不够专业,还需要手动处理换行和关闭。更规范的做法是使用文件对象自带的 write() 方法:
with open('1.txt', 'w') as f:f.write('12345\n')
这里有几个值得强调的点:
write() 不会自动添加换行符,需要显式写入 \n;而 print() 默认会在末尾加换行。write() 的返回值是写入的字符数,可用于校验是否写全。with 语句是上下文管理器,无论代码块正常结束还是抛出异常,都会自动调用 close(),避免资源泄漏。| 模式 | 含义 | 特点 |
|---|---|---|
'r' |
只读 | 默认模式,文件不存在会报错 |
'w' |
只写 | 会清空原内容,文件不存在则创建 |
'a' |
追加 | 在末尾追加,不覆盖原内容 |
'x' |
独占创建 | 文件已存在则报错,适合防止误覆盖 |
'b' |
二进制 | 与上述组合,如 'rb'、'wb' |
'+' |
读写 | 如 'r+'、'w+' |
选择正确的模式非常重要。例如日志追加场景应使用 'a',避免每次运行都清空历史记录。
在跨平台场景中,文本文件的默认编码可能不同。写中文时若编码不一致,容易出现乱码或 UnicodeEncodeError。显式指定编码是更稳妥的做法:
with open('1.txt', 'w', encoding='utf-8') as f:f.write('你好,世界\n')
input() 从标准输入读取一行,返回字符串(不含末尾换行),需要数字时得手动转换:
age = int(input("请输入年龄:"))
文件读取则常用三种方式:
# 一次性读取全部内容with open('1.txt', 'r', encoding='utf-8') as f:content = f.read()# 按行读取为列表with open('1.txt', 'r', encoding='utf-8') as f:lines = f.readlines()# 逐行迭代,内存友好,适合大文件with open('1.txt', 'r', encoding='utf-8') as f:for line in f:print(line.rstrip())
处理大文件时,逐行迭代是首选,它不会把整个文件一次性载入内存。
除了手动打开文件,还可以在运行时替换 sys.stdout,让所有 print 自动写入文件:
import syswith open('output.log', 'w', encoding='utf-8') as f:original = sys.stdoutsys.stdout = ftry:print('这条信息会写入日志文件')finally:sys.stdout = original
在日志采集、批处理脚本中,这种技巧很常见。不过更推荐使用标准库的日志模块,它内置了级别、格式化和多目标输出能力。
几点工程建议:
with,让资源管理自动化。read()。try/except 捕获 FileNotFoundError、PermissionError 等,给出可读的提示。Python 的 I/O 设计遵循“显式优于隐式”的哲学:print 默认写标准输出,但允许你替换目标;open 返回文件对象,通过模式、编码、上下文管理器让你精确控制行为。理解标准输出流、文件对象与资源管理这三件事,就能从容应对从命令行小工具到批处理脚本的各类场景。掌握这些基础后,再去看更高级的序列化、缓冲与异步 I/O,会发现它们不过是同一套抽象的自然延伸。