Python最基本的输入输出详解 前言输入输出是程序与外界沟通的唯一通道也是新手最容易在不经意间写错的地方。最常见的三个坑是以为input()会返回数字它永远返回字符串open()不写encoding在 Windows 上读中文文件直接乱码以及用 Python 2 的print语句在 Python 3 里根本跑不起来。还有一个必须点明的事实Python 3 的input()等价于 Python 2 的raw_input()。在 Python 2 里input()会对用户输入做eval()官方文档明确写着input()等价于eval(raw_input(prompt))也就是会执行用户输入的内容极其危险。Python 3 把这个危险的input()删掉了只保留返回字符串的安全版本——所以现代代码里绝不该再出现eval(input())这种用法。本文讲清四件事print()的参数与行为、input()的返回类型、三种字符串格式化方式、以及带encoding的文件读写。以 Python 3.8 及以上为基准。一、print()不只是打印print()的真实签名是print(*objects, sep , end\n, fileNone, flushFalse)要点*objects表示可以传任意多个位置参数会被逐个转成字符串。sep、end、file、flush只能按关键字传。sep默认是单个空格end默认是换行。不传任何对象时print()只输出一个end即一个空行。file默认是sys.stdoutfile必须是带write(string)方法的对象不能是二进制文件。# 适用于 Python 3 全版本print(a, b, c) # a b cprint(a, b, sep-) # a-bprint(不加换行, end)print(接在后面) # 不加换行接在后面print() # 输出一个空行重定向到文件、控制台刷新# 适用于 Python 3 全版本flush 参数自 3.3 起提供import sysprint(进度 1/3, end\r, filesys.stdout, flushTrue)print(进度 2/3, end\r, flushTrue)print(完成 )二、input()读进来的永远是字符串官方文档的定义若有prompt参数只能按位置传先把它写到标准输出不带换行然后从输入读一行转成字符串剥掉行尾换行符并返回。读到文件结束EOF时抛EOFError。# 适用于 Python 3 全版本name input(请输入姓名) # 返回值类型是 strprint(type(name).__name__) # strage_str input(请输入年龄)age int(age_str) # 必须显式转换否则后面没法做算术print(f明年你 {age 1} 岁)如果用户直接 Ctrl-DWindows 上 Ctrl-Z 回车结束输入input()会抛EOFError健壮的脚本应当捕获它# 适用于 Python 3 全版本try:line input(请输入)except EOFError:line print(收到, repr(line))三、格式化输出三种方式3.1 f-string推荐f-string 是带f前缀的字符串字面量花括号里可以放表达式# 适用于 Python 3.6name, ratio Ada, 0.876print(f{name} 的通过率是 {ratio:.1%}) # Ada 的通过率是 87.6%print(f{3.14159:8.2f}) # 3.14宽度 8保留 2 位小数print(f{255:#x}) # 0xff格式说明符的通用形式是[[填充]对齐][宽度][,][.精度][类型]常用的类型有d整数、f定点小数、e科学计数、%百分数、x/o十六/八进制。f-string 里如果内层表达式用了和外层相同的引号要Python 3.12 及以上PEP 701才合法3.12 之前只能让内外引号不同或改用.format()# 内外引号不同所有 Python 3.6 都合法print(f{a b}) # ab# 内外引号相同需要 Python 3.12print(f{x * 2}) # xx如果上面的第二个print在 3.12 之前的版本里运行会报SyntaxError。旧版本的等价写法是print(x * 2)或先算出变量再放进 f-string。3.2 str.format()# 适用于 Python 3 全版本print({} 和 {}.format(左, 右))print({name} 得了 {score}.format(nameBob, score88))3.3 % 格式化旧式仍可用# 适用于 Python 3 全版本print(%s 得了 %d 分 % (Bob, 88))print(%.2f % 3.14159) # 3.14三种方式都能用日常优先 f-string需要把格式模板和值分开存放时用.format()。方式最低版本优点注意f-string3.6简洁、可读3.12 前不能嵌套同类引号str.format3.0模板可复用写法略长%格式化一直有熟悉 C 的人上手快参数是元组易错四、文件读写一定要写 encodingopen()的完整签名是open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, openerNone)mode常用值mode含义r只读文本默认w只写会截断已有内容a追加x独占创建文件已存在则报错b二进制模式可与其他字母组合如rb读写如r标准做法是用with语句保证离开块时自动关闭文件# 适用于 Python 3 全版本# 写文件with open(notes.txt, w, encodingutf-8) as f:f.write(第一行\n)f.write(第二行\n)# 读文件with open(notes.txt, encodingutf-8) as f:content f.read()print(content)# 逐行读推荐处理大文件不一次性载入内存with open(notes.txt, encodingutf-8) as f:for line in f:print(line.rstrip(\n))始终显式写encodingutf-8。省略时用的是系统默认编码Linux/macOS 通常是 UTF-8而 Windows 上是 ANSI 代码页简体中文环境为 GBK同一份代码换个平台就乱码。实战一个迷你通讯录# 适用于 Python 3.8import jsonfrom pathlib import PathDATA Path(contacts.json)def load_contacts():if not DATA.exists():return {}# 显式指定编码跨平台一致text DATA.read_text(encodingutf-8)if not text.strip():return {}return json.loads(text)def save_contacts(contacts):DATA.write_text(json.dumps(contacts, ensure_asciiFalse, indent2),encodingutf-8,)def main():contacts load_contacts()while True:raw input(姓名直接回车结束).strip()if not raw:breakphone input(f{raw} 的电话).strip()contacts[raw] phonesave_contacts(contacts)print(f已保存 {len(contacts)} 条记录到 {DATA})if __name__ __main__:main()Path.read_text()/write_text()是pathlib提供的便捷读写方法Python 3.5 起有read_textwrite_text同样自 3.5 起encoding参数一直可用。常见坑点用 Python 2 的 print 语句❌print hello—— Python 3 里是语法错误 ✅print(hello)Python 2.7 已于 2020-01-01 停止维护忘了input()返回字符串❌n input(数量); total n * 2—— 得到的是字符串重复 ✅ 先转换n int(input(数量))用eval(input())处理用户输入❌value eval(input(输入))—— 会执行任意输入内容 ✅ 用int()/float()/json.loads()按需安全转换open()不写 encoding❌open(a.txt)在 Windows 上读 UTF-8 中文文件乱码 ✅open(a.txt, encodingutf-8)忘记关闭文件❌f open(a.txt); data f.read()之后没有f.close()✅ 用with open(...) as f:退出块时自动关闭w模式把原文件清空❌ 想接着写却用了open(path, w)✅ 追加用open(path, a, encodingutf-8)%格式化把元组当成多个参数❌值%s % (a, b)会报「参数过多」 ✅ 一个参数就传值本身值%s % a多参数才用元组print的重定向撞上二进制文件❌print(x, fileopen(a.bin, wb))—— 类型不匹配 ✅ 二进制文件用f.write(bx)不要用print总结主题关键结论print()sep/end/file/flush只能关键字传input()返回str剥掉行尾换行EOF 抛EOFErroreval(input())危险会执行输入不应使用f-string3.63.12 前不能嵌套同类引号str.format/%可替代 f-string注意参数是元组open()显式写encodingutf-8with自动关闭文件读写都用它wvsaw截断a追加输入输出的正确姿势其实只有几条input()回来的一律当字符串处理并显式转换格式化优先用 f-string文件操作一律with加encodingutf-8。把这三点变成肌肉记忆剩下的报错会少很多。