Python 中文教程

输入输出

f-string 负责格式化,with open 负责读写文件,json 模块负责结构化数据,掌握这三样就够用了。

  • 第 9 章 · 对象、异常与文件
  • 11 分钟
  • 4 组对比

字符串格式化

f-string 是首选的格式化方式。花括号里可以写任意表达式,冒号后面是格式说明。

f-string

Python
name, pi = "Pi", 3.14159
print(f"{name} ≈ {pi:.2f}")    # => Pi ≈ 3.14
print(f"{1234567:,}")          # => 1,234,567
print(f"[{'左':<4}|{42:>4}]")  # => [左   |  42]
print(f"{pi=}")                # => pi=3.14159
var name = "Pi";
var pi = 3.14159;
System.out.println(String.format(
    "%s ≈ %.2f", name, pi));    // => Pi ≈ 3.14
System.out.println(String.format(
    "%,d", 1234567));           // => 1,234,567
System.out.println(String.format(
    "[%-4s|%4d]", "左", 42));   // => [左   |  42]
对比项PythonJava
插值f"{x}"没有内置语法
数字格式{pi:.2f},写在变量旁边%.2f,写在占位符里
调试输出f"{pi=}"没有
格式符含义相同.2f 表示两位小数

{pi=} 同时输出表达式和值,调试时很好用。

格式说明符
PythonJava说明
f"{x:.2f}""%.2f"保留两位小数
f"{x:>8}""%8s"右对齐
f"{x:<8}""%-8s"左对齐
f"{x:08.3f}""%08.3f"用 0 补齐
f"{x:,}""%,d"千分位
f"{x:.1%}"无百分比,0.25 显示为 25.0%
f"{x:x}""%x"十六进制
f"{x!r}"无用 repr() 而不是 str()

str() 生成给人看的文本,repr() 生成给开发者看的文本,通常带引号或类型信息。print 用前者,交互模式显示后者。

老代码里的格式化写法选读

你在老项目里还会看到两种写法。"{} 和 {}".format(a, b) 是 f-string 出现之前的主流方式。"%s 和 %d" % (a, b) 是更早的 C 风格写法,今天主要用在 logging 里。字符串的 rjust()、ljust()、zfill() 方法也能做简单对齐。新代码统一用 f-string。

读写文件

open() 返回文件对象,配合 with 自动关闭。文本文件要明确写 encoding="utf-8",否则默认编码取决于操作系统。

读写文本文件

Python
with open("a.txt", "w", encoding="utf-8") as f:
    f.write("第一行\n第二行\n")

with open("a.txt", encoding="utf-8") as f:
    for line in f:
        print(line.rstrip())

with open("a.txt", encoding="utf-8") as f:
    print(len(f.read()))   # => 8
var path = Path.of("a.txt");
Files.writeString(path, "第一行\n第二行\n");

for (var line : Files.readAllLines(path)) {
    System.out.println(line);
}

var text = Files.readString(path);
System.out.println(text.length());  // => 8
对比项PythonJava
写入f.write(text)Files.writeString
逐行读取for line in fFiles.readAllLines,大文件用 Files.lines
读取全部f.read()Files.readString
默认编码取决于操作系统UTF-8
行尾换行符保留,用 rstrip() 去掉自动去掉

直接遍历文件对象就是逐行读取,不会把整个文件读进内存。

文件操作
PythonJava说明
open(p)Files.newBufferedReader(p)默认只读文本模式
open(p, "w")Files.newBufferedWriter(p)覆盖写入
open(p, "a")Files.writeString(p, s, APPEND)追加写入
open(p, "x")Files.writeString(p, s, CREATE_NEW)文件已存在时报错
open(p, "rb")Files.newInputStream(p)二进制模式
f.read()Files.readString(p)读取全部
f.readlines()Files.readAllLines(p)读成行列表
Path(p).read_text()Files.readString(p)一行读完,不用 with
文件对象的其他方法选读

f.readline() 读一行,读到末尾时返回空字符串。f.write() 返回写入的字符数。f.tell() 返回当前位置,f.seek(0) 跳回开头。模式 "r+" 同时支持读写。文本模式会把换行符统一转成 \n,处理图片这类数据时一定要用二进制模式。

JSON

json 模块在标准库里。JSON 对象直接映射成 dict,数组映射成 list,不需要先定义类。

JSON 序列化

Python
import json

data = {"name": "Ann", "tags": ["a", "b"]}

text = json.dumps(data, ensure_ascii=False)
print(text)  # => {"name": "Ann", "tags": ["a", "b"]}

back = json.loads(text)
print(back["tags"][0])  # => a

with open("d.json", "w") as f:
    json.dump(data, f)
// 使用第三方库 Jackson
var mapper = new ObjectMapper();

var data = Map.of("name", "Ann");
var text = mapper.writeValueAsString(data);

var back = mapper.readValue(text, Map.class);
对比项PythonJava
支持方式标准库 json第三方库 Jackson、Gson
解析结果dict 和 list通常绑定到类
对象转字符串json.dumpswriteValueAsString
字符串转对象json.loadsreadValue

dumps 和 loads 处理字符串,多出来的 s 代表 string,dump 和 load 处理文件。需要校验时用第三方库 pydantic。

pickle选读

pickle 能序列化几乎任何 Python 对象,作用类似 Java 的 Serializable。它只能在 Python 之间使用,而且加载不可信的数据会执行任意代码。跨语言或跨系统交换数据时用 JSON。

字节和编码

Python 严格区分文本和字节。str 是文本,bytes 是字节序列,两者不能混用。读二进制文件、收发网络数据时拿到的都是 bytes。

编码和解码

Python
text = "中文"
data = text.encode("utf-8")

print(data)  # => b'\xe4\xb8\xad\xe6\x96\x87'
print(len(text), len(data))  # => 2 6
print(data.decode("utf-8"))  # => 中文
var text = "中文";
var data = text.getBytes(
    StandardCharsets.UTF_8);

System.out.println(
    text.length() + " " + data.length);  // => 2 6
System.out.println(new String(
    data, StandardCharsets.UTF_8));      // => 中文
对比项PythonJava
字节类型bytes,不可变byte[],可变
字面量b"abc"没有
编码s.encode("utf-8")s.getBytes(UTF_8)
解码b.decode("utf-8")new String(b, UTF_8)
😀 的长度len 得到 1,按字符计length() 得到 2

str 和 bytes 相加会抛 TypeError。需要可变的字节序列时用 bytearray。

控制台输入

input("请输入:") 读取一行,总是返回字符串,要数字时写 int(input())。对应 Java 的 Scanner 和 Kotlin 的 readln()。

本章要点

  • 格式化统一用 f-string,冒号后写格式说明,如 {x:.2f}
  • 文件用 with open(...) 打开,文本文件明确写 encoding="utf-8"
  • 遍历文件对象就是逐行读取,省内存
  • json.dumps 和 json.loads 直接在 dict 和字符串之间转换
  • str 是文本,bytes 是字节,用 encode 和 decode 互转

官方原文:输入与输出