# Python字符串格式化

## 定义

**字符串格式化**把变量的值按指定样式嵌入字符串。Python常用的写法有两种。

f-string在字符串引号前加`f`，在花括号里写表达式，冒号后接格式说明符：

```python
f"{value:format_spec}"
```

`%` 占位符在模板里写 `%s`、`%d`等标记，再用 `%` 运算符把右边的值代入：

```python
"%d" % 42
```

格式说明符决定这个值占多宽、怎么对齐、保留几位小数、以什么进制显示。两种写法共用同一套宽度、精度和对齐概念，只是标记不同。

## 格式说明符

格式说明符的各部分按固定顺序书写，除类型外大多可以省略；只写 `:.2f`时，其余部分取默认值。

| 部分    | 作用                                         | 示例                          |
| :---- | :----------------------------------------- | :-------------------------- |
| 填充与对齐 | `<` 左对齐、`>` 右对齐、`^` 居中；对齐符前的字符用作填充         | `f"{7:*^5}"` → `**7**`      |
| 符号    | `+` 正数也显示正号，`-` 只显示负号（默认）                  | `f"{3.14:+.2f}"` → `+3.14`  |
| `#`   | 加进制前缀                                      | `f"{42:#x}"` → `0x2a`       |
| 补零    | 宽度前写`0`，在左侧补`0`                            | `f"{42:05d}"` → `00042`     |
| 宽度    | 最小总宽度                                      | `f"{42:<5d}"` → `'42   '`   |
| 精度    | `.n`保留`n`位小数                               | `f"{3.14159:.2f}"` → `3.14` |
| 类型    | `d`整数、`f`浮点、`e`科学计数、`b`二进制、`x`十六进制、`%` 百分比 | `f"{0.25:.1%}"` → `25.0%`   |

### 对齐与填充

对齐符单独写时只决定方向，例如 `:<5d`；在对齐符前再加一个字符，就用它填充空位，例如 `:*^10`表示用 `*` 填充、居中对齐、总宽10。填充字符只有一个，并且必须紧挨着对齐符。

### 符号与补零

正数默认不显示正号，写 `+` 后会强制显示；`0`必须写在宽度之前，表示用零填充而不是用空格填充。`f"{7:05d}"` 得到`00007`，`f"{7:<05d}"` 的`0`会被当成填充字符，含义与补零不同。

### 精度与类型

精度对浮点数表示小数点后的位数，`.2f`表示保留2位小数；类型字母决定如何解释这个值，`d`只接受整数，`f`按浮点显示，`%` 会先乘以100再加百分号。类型与值的种类不匹配时会抛异常。

### 百分号占位符

`%` 占位符沿用C的printf风格，模板中的每个占位符依次消耗右边的一个值：

| 占位符       | 描述            | 示例                           |
| :-------- | :------------ | :--------------------------- |
| `%s`      | 字符串，调用`str()` | `"%s" % [1, 2]` → `'[1, 2]'` |
| `%d`      | 有符号十进制整数      | `"%d" % 3.9` → `'3'`，截断小数部分  |
| `%f`      | 浮点数，默认6位小数    | `"%.2f" % 3.1415` → `'3.14'` |
| `%x`、`%X` | 十六进制整数        | `"%x" % 15` → `'f'`          |
| `%e`、`%E` | 科学计数法         |                              |
| `%%`      | 输出字面量 `%`     | `"%d%%" % 50` → `'50%'`      |

宽度和精度写在 `%` 与类型字母之间，例如 `%5.2f`表示总宽5、保留2位小数。多个值时右边要用元组，占位符数量必须与值的数量一致。

### 两种写法的取舍

f-string可以直接在模板里写表达式，参数和位置一一对应，可读性最好，Python 3.6起可用，新代码通常选它。`%` 占位符是较早的写法，参数按顺序代入，占位符与值的数量和类型必须匹配；阅读老代码时需要能认出这种模板。

两者在宽度、对齐和精度上的表达能力相近，区别主要在可读性和参数对应方式。同一段代码里混用两种风格会让参数对应关系更难检查。

## 例子

**f-string的常见格式**

```python title="format_fstring.py"
pi = 3.1415926
val = 42

f"{pi:.2f}"      # '3.14'
f"{pi:+.2f}"     # '+3.14'，显示正号
f"{val:05d}"     # '00042'，补零到5位
f"{val:<5d}"     # '42   '，左对齐
f"{val:#x}"      # '0x2a'，带十六进制前缀
f"{0.25:.1%}"    # '25.0%'，按百分比显示
```

**用 `%` 占位符代入多个值**

```python title="format_percent.py"
"%s有 %d个元素" % ("列表", 3)   # '列表有3个元素'
"%d%%" % 50                      # '50%'
"%.2f" % 3.1415                  # '3.14'
```

第一个占位符是字符串，第二个是整数，右边的元组按顺序与它们对应。

## 探索

交互演示：宽度和精度怎样影响浮点输出？。调整字段宽度与小数精度，查看右对齐后的格式。 请在站点操作演示。

## 练习

1. `f"{3.14159:.2f}"` 的结果是：

   * A.  `'3.14'`
   * B.  `'3.142'`
   * C.  `'3.14159'`
   * D.  `'3'`

   答案：A

   `.2f`表示按浮点数保留2位小数，得到`3.14`。

2. `f"{7:03d}"` 的结果是：

   * A.  `'007'`
   * B.  `'7'`
   * C.  `'0007'`
   * D.  `'70'`

   答案：A

   `0`表示补零，`3`是总宽度，`d`表示整数，所以补到3位得到`007`。

3. `"%d" % 3.9`的结果是：

   * A.  `'3'`
   * B.  `'4'`
   * C.  `'3.9'`
   * D.  抛出异常

   答案：A

   `%d`按整数输出，3.9的小数部分被截断，得到 `'3'`。

4. 关于字符串格式化，下列说法正确的是：

   * A.  f-string需要Python 3.6及以上版本
   * B.  `%d`会把3.9四舍五入为4
   * C.  `%%` 用来一次输出两个百分号
   * D.  `.2f`表示保留2位有效数字

   答案：A

   `%d`截断小数部分得到3；`%%` 只输出一个 `%`；`.2f`是保留2位小数而不是2位有效数字。

5. 关于格式说明符，下列说法正确的是：

   * A.  `^` 表示居中对齐
   * B.  `<` 表示左对齐
   * C.  `f"{42:05d}"` 会把42补零到5位
   * D.  `#x`会去掉十六进制前缀

   答案：A、B、C

   `#` 的作用是加上进制前缀，`f"{42:#x}"` 得到`0x2a`，D说反了。
