2.4.3. 格式化字符串字面值

3.6 新版功能.

格式化字符串字面值 或称 f-string 是带有 'f''F' 前缀的字符串字面值。这种字符串可包含替换字段,即以 {} 标示的表达式。而其他字符串字面值总是一个常量,格式化字符串字面值实际上是会在运行时被求值的表达式。

转义序列会像在普通字符串字面值中一样被解码 (除非字面值还被标示为原始字符串)。解码之后,字符串内容所用的语法如下:

  1. f_string ::= (literal_char | "{{" | "}}" | replacement_field)*
  2. replacement_field ::= "{" f_expression ["="] ["!" conversion] [":" format_spec] "}"
  3. f_expression ::= (conditional_expression | "*" or_expr)
  4. ("," conditional_expression | "," "*" or_expr)* [","]
  5. | yield_expression
  6. conversion ::= "s" | "r" | "a"
  7. format_spec ::= (literal_char | NULL | replacement_field)*
  8. literal_char ::= <any code point except "{", "}" or NULL>

字符串在花括号以外的部分按其字面值处理,除了双重花括号 '{{''}}' 会被替换为相应的单个花括号。 单个左花括号 '{' 标示一个替换字段,它以一个 Python 表达式打头。 要同时显示表达式文本及其求值后的结果值(这在调试时很有用),可以在表达式后加一个等于号 '='。 之后可能带有一个以叹号 '!' 标示的转换字段。 之后还可能带有一个以冒号 ':' 标示的格式说明符。 替换字段以一个右花括号 '}' 作为结束。

格式化字符串字面值中的表达式会被当作包含在圆括号中的普通 Python 表达式一样处理,但有少数例外。 空表达式不被允许,lambda 和赋值表达式 := 必须显式地加上圆括号。 替换表达式可以包含换行(例如在三重引号字符串中),但是不能包含注释。 每个表达式会在格式化字符串字面值所包含的位置按照从左至右的顺序被求值。

在 3.7 版更改: 在 Python 3.7 之前, await 表达式包含 async for 子句的推导式不允许在格式化字符串字面值表达式中使用,这是因为具体实现存在一个问题。

在提供了等于号 '=' 的时候,输出将包含表达式文本,'=' 以及求值结果。 左花括号 '{' 之后包含在表达式中及 '=' 后的空格将在输出时被保留。 默认情况下,'=' 会导致表达式的 repr() 被使用,除非专门指定了格式。 当指定了格式时默认会使用表达式的 str(),除非声明了转换字段 '!r'

3.8 新版功能: 等号 '='

如果指定了转换符,表达式的求值结果会先转换再格式化。转换符 '!s' 即对结果调用 str()'!r' 为调用 repr(),而 '!a' 为调用 ascii()

在此之后结果会使用 format() 协议进行格式化。格式说明符会被传入表达式或转换结果的 __format__() 方法。如果省略格式说明符则会传入一个空字符串。然后格式化结果会包含在整个字符串最终的值当中。

最高层级格式说明符可以包含有嵌套的替换字段。 这些嵌套字段也可以包含有它们自己的转换字段和 格式说明符,但不可再包含更深层嵌套的替换字段。 这里的 格式说明符微语言str.format() 方法所使用的微语言一致。

格式化字符串字面值可以拼接,但是一个替换字段不能拆分到多个字面值。

一些格式化字符串字面值的示例:

  1. >>> name = "Fred"
  2. >>> f"He said his name is {name!r}."
  3. "He said his name is 'Fred'."
  4. >>> f"He said his name is {repr(name)}." # repr() is equivalent to !r
  5. "He said his name is 'Fred'."
  6. >>> width = 10
  7. >>> precision = 4
  8. >>> value = decimal.Decimal("12.34567")
  9. >>> f"result: {value:{width}.{precision}}" # nested fields
  10. 'result: 12.35'
  11. >>> today = datetime(year=2017, month=1, day=27)
  12. >>> f"{today:%B %d, %Y}" # using date format specifier
  13. 'January 27, 2017'
  14. >>> f"{today=:%B %d, %Y}" # using date format specifier and debugging
  15. 'today=January 27, 2017'
  16. >>> number = 1024
  17. >>> f"{number:#0x}" # using integer format specifier
  18. '0x400'
  19. >>> foo = "bar"
  20. >>> f"{ foo = }" # preserves whitespace
  21. " foo = 'bar'"
  22. >>> line = "The mill's closed"
  23. >>> f"{line = }"
  24. 'line = "The mill\'s closed"'
  25. >>> f"{line = :20}"
  26. "line = The mill's closed "
  27. >>> f"{line = !r:20}"
  28. 'line = "The mill\'s closed" '

与正常字符串字面值采用相同语法导致的一个结果就是替换字段中的字符不能与外部的格式化字符串字面值所用的引号相冲突:

  1. f"abc {a["x"]} def" # error: outer string literal ended prematurely
  2. f"abc {a['x']} def" # workaround: use different quoting

格式表达式中不允许有反斜杠,这会引发错误:

  1. f"newline: {ord('\n')}" # raises SyntaxError

想包含需要用反斜杠转义的值,可以创建一个临时变量。

  1. >>> newline = ord('\n')
  2. >>> f"newline: {newline}"
  3. 'newline: 10'

格式化字符串字面值不可用作文档字符串,即便其中没有包含表达式。

  1. >>> def foo():
  2. ... f"Not a docstring"
  3. ...
  4. >>> foo.__doc__ is None
  5. True

另请参见 PEP 498 了解加入格式化字符串字面值的提议,以及使用了相关的格式字符串机制的 str.format()