欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python输出格式化 格式化字符串语法 format f-string 格式化操作符% 数据类型转换 对齐方式 转换标志字符

程序员文章站 2022-07-15 08:10:24
...

Python输出格式化 格式化字符串语法

1.format

1.1 Format String Syntax

格式字符串语法 str.format() 方法和 Formatter 类共享相同的格式字符串语法(尽管在 Formatter 的情况下,子类可以定义自己的格式字符串语法)。 语法与格式化字符串文字的语法有关,但存在差异。

格式字符串包含用大括号 {}包围的“替换字段”。 大括号中未包含的任何内容都被视为文字文本,将原样复制到输出中。 如果需要在文字文本中包含大括号字符,可以通过加倍转义:{{}}

替换字段的语法如下:

replacement_field ::=  "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
arg_name          ::=  [identifier | digit+]
attribute_name    ::=  identifier
element_index     ::=  digit+ | index_string
index_string      ::=  <any source character except "]"> +
conversion        ::=  "r" | "s" | "a"
format_spec       ::=  <described in the next section>

用不太正式的术语来说,替换字段可以以 field_name 开头,它指定要对其值进行格式化并插入到输出中的对象,而不是替换字段。 field_name后跟可选的转换字段,前面是感叹号“!”,和 format_spec,前面是冒号“:”。 这些指定替换值的非默认格式。

field_name本身以一个 arg_name开头,它可以是数字或关键字。 如果是数字,则表示位置参数,如果是关键字,则表示命名关键字参数。 如果格式字符串中的数字 arg_names依次为 0, 1, 2, … ,它们都可以省略(不仅仅是一些),并且数字 0, 1, 2, … 将按该顺序自动插入。 由于 arg_name不是引号分隔的,因此无法在格式字符串中指定任意字典键(例如,字符串'10'':-]')。 arg_name后面可以跟任意数量的索引或属性表达式。 '.name' 形式的表达式使用 getattr()选择命名属性,而'[index]'形式的表达式使用__getitem__()进行索引查找。

  • str.format() 可以省略位置参数说明符,因此 '{}{}'.format(a, b) 等效于'{0} {1}'.format(a, b) )Formatter可以省略位置参数说明符。

一些简单的格式字符串示例:

"First, thou shalt count to {0}"  # 引用第一个位置参数
"Bring me a {}"                   # 隐式引用第一个位置参数
"From {} to {}"                   # 与“From {0} to {1}”相同
"My quest is {name}"              # 引用关键字参数 'name' 
"Weight in tons {0.weight}"       # 第一个位置参数的“weight”属性
"Units destroyed: {players[0]}"   # 关键字参数“players”的第一个元素。
>>> '{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'
>>> '{}, {}, {}'.format('a', 'b', 'c')  # 3.1+ only
'a, b, c'
>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
>>> '{2}, {1}, {0}'.format(*'abc')      # unpacking argument sequence
'c, b, a'
>>> '{0}{1}{0}'.format('abra', 'cad')   # arguments' indices can be repeated
'abracadabra'
>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'
>>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'}
>>> 'Coordinates: {latitude}, {longitude}'.format(**coord)
'Coordinates: 37.24N, -115.81W'
>>> coord = (3, 5)
>>> 'X: {0[0]};  Y: {0[1]}'.format(coord)
'X: 3;  Y: 5'
>>> c = 3-5j
>>> ('The complex number {0} is formed from the real part {0.real} and the imaginary part {0.imag}.').format(c)
'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.'

引用关键字参数'name'“From {0} to {1}”相同 隐式引用第一个位置参数 引用第一个位置参数 转换字段在格式化之前导致类型强制。 通常,格式化值的工作由值本身的 __format__()方法完成。 但是,在某些情况下,需要强制将类型格式化为字符串,覆盖其自己的格式化定义。 通过在调用__format__()之前将值转换为字符串,可以绕过正常的格式化逻辑。

当前支持三种转换标志:'!s'调用 str() 值,'!r'调用 repr()'!a'调用 ascii()

"Harold's a clever {0!s}"        # 首先对参数调用 str()
"Bring out the holy {name!r}"    # 首先对参数调用 repr()
"More {!a}"                      # 首先对参数调用 ascii()
>>> "repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2')
"repr() shows quotes: 'test1'; str() doesn't: test2"

format_spec 字段包含如何呈现值的规范,包括字段宽度、对齐方式、填充、小数精度等细节。 每个值类型都可以定义自己的“formatting mini-language”或对 format_spec 的解释。

format_spec 字段还可以在其中包含嵌套的替换字段。 这些嵌套的替换字段可能包含字段名称、转换标志和格式规范,但不允许更深的嵌套。 在解释 format_spec 字符串之前替换 format_spec中的替换字段。 这允许动态指定值的格式。

Format Specification Mini-Language

格式规范迷你语言“Format specifications”在格式字符串中包含的替换字段中使用,以定义单个值的呈现方式。 它们也可以直接传递给内置的format()函数。 每个可格式化的类型都可以定义如何解释格式规范。大多数内置类型实现以下格式规范选项,尽管某些格式选项仅受数字类型支持。 一般约定是,空格式规范产生的结果与对值调用 str() 的结果相同。 非空格式规范通常会修改结果。

标准格式说明符的一般形式是:

format_spec     ::=  [[fill]align][sign]['#'][0][width][grouping_option][.precision][type]
fill            ::=  <any character>
align           ::=  "<" | ">" | "=" | "^"
sign            ::=  "+" | "-" | " "
width           ::=  digit+
grouping_option ::=  "_" | ","
precision       ::=  digit+
type            ::=  "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"

格式对齐

如果指定了有效的对齐值,则它前面可以是一个填充字符,该字符可以是任何字符,如果省略则默认为空格。 在格式化字符串文字中或使用str.format() 方法时,不能使用文字花括号(“{”或“}”)作为填充字符。 但是,可以插入带有嵌套替换字段的花括号。 此限制不会影响 format() 函数。

各种对齐选项的含义如下:

Option Meaning
'<' 强制字段在可用空间内左对齐(这是大多数对象的默认设置)。
'>' 强制字段在可用空间内右对齐(这是大多数对象的默认设置)。
'=' 强制将填充放置在符号(如果有)之后但在数字之前。 这用于以“+000000120”形式打印字段。 此对齐选项仅对数字类型有效。 当“0”紧跟在字段宽度之前时,它成为默认值。
'^' 强制字段在可用空间内居中。
>>> '{:<30}'.format('left aligned')
'left aligned                  '
>>> '{:>30}'.format('right aligned')
'                 right aligned'
>>> '{:^30}'.format('centered')
'           centered           '
>>> '{:*^30}'.format('centered')  # use '*' as a fill char
'***********centered***********'

请注意,除非定义了最小字段宽度,否则字段宽度将始终与填充它的数据大小相同,因此在这种情况下对齐选项没有意义。

正负号

符号sign 选项仅对数字类型有效,可以是以下之一:

Option Meaning
'+' 表示正数和负数都应使用符号。
'-' 表示一个符号应该只用于负数(这是默认行为)。
space 表示应在正数上使用前导空格,在负数上使用减号。
>>> '{:+f}; {:+f}'.format(3.14, -3.14)  # show it always
'+3.140000; -3.140000'
>>> '{: f}; {: f}'.format(3.14, -3.14)  # show a space for positive numbers
' 3.140000; -3.140000'
>>> '{:-f}; {:-f}'.format(3.14, -3.14)  # show only the minus -- same as '{:f}; {:f}'
'3.140000; -3.140000'

数字进制转换

  • #’ 选项使“替代形式”用于转换。 对于不同的类型,替代形式的定义不同。 此选项仅对整数、浮点数和复杂类型有效。 对于整数,当使用二进制、八进制或十六进制输出时,此选项将相应的前缀“0b”、“0o”或“0x”添加到输出值。 对于浮点数和复数,替代形式导致转换结果始终包含小数点字符,即使后面没有数字也是如此。 通常,只有在小数点字符后面跟着数字时,小数点字符才会出现在这些转换的结果中。 此外,对于 ‘g’ 和 ‘G’ 转换,不会从结果中删除尾随零。
  • ,’ 选项表示使用逗号作为千位分隔符。 对于区域设置感知分隔符,请改用“n”整数表示类型。
  • _’ 选项表示对浮点表示类型和整数表示类型 ‘d’ 使用下划线作为千位分隔符。 对于整数表示类型“b”、“o”、“x”和“X”,将每 4 位插入下划线。 对于其他演示文稿类型,指定此选项是错误的。
  • width是定义最小总字段宽度的十进制整数,包括任何前缀、分隔符和其他格式字符。 如果未指定,则字段宽度将由内容决定。
>>> '{:,}'.format(1234567890)
'1,234,567,890'
>>> '{:_}'.format(1234567890)
'1_234_567_890'

当没有给出明确的对齐方式时,在宽度字段前面加上一个零 (’0’) 字符,为数字类型启用符号感知零填充。 这等效于对齐类型为“=”的填充字符“0”。

精度是一个十进制数,表示对于用 ‘f’ 和 ‘F’ 格式的浮点值小数点后应显示多少位,或对于用 ‘g’ 格式的浮点值小数点前后应显示多少位或 ‘G’。 对于非数字类型,该字段指示最大字段大小 - 换句话说,字段内容中将使用多少个字符。 整数值不允许使用精度。

  • 可用的字符串表示类型有:
Type Meaning
's' 字符串格式。 这是字符串的默认类型,可以省略。
None The same as 's'.
整数
  • 可用的整数表示类型有:
Type Meaning
'b' 二进制格式。 输出以 2 为底的数字。
'c' Character. 在打印之前将整数转换为相应的 unicode 字符。
'd' 十进制整数。 输出以 10 为底的数字。
'o' 八进制格式。 输出以 8 为底的数字。
'x' 十六进制整数。 输出以 10 为底的数字, 使用小写字母表示 9 以上的数字。
'X' 十六进制整数。 输出以 10 为底的数字,使用大写字母表示 9 以上的数字。
'n' 数字。 这与 'd' 相同,只是它使用当前的语言环境设置来插入适当的数字分隔符。
None The same as 'd'.
>>> # format also supports binary numbers
>>> "int: {0:d};  hex: {0:x};  oct: {0:o};  bin: {0:b}".format(42)
'int: 42;  hex: 2a;  oct: 52;  bin: 101010'
>>> # with 0x, 0o, or 0b as prefix:
>>> "int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}".format(42)
'int: 42;  hex: 0x2a;  oct: 0o52;  bin: 0b101010'
浮点数

除了上述表示类型之外,整数还可以使用下面列出的浮点表示类型(’n’ 和None除外)进行格式化。 这样做时, float() 用于在格式化之前将整数转换为浮点数。

  • 浮点数和小数值的可用表示类型有:
Type Meaning
'e' 科学计数法。 对于给定的精度“p”,用科学记数法格式化数字,用字母“e”将系数与指数分开。 系数在小数点前有一位,在小数点后有‘p’位,总共有‘p+1’位有效数字。 在没有给出精度的情况下,对“float”使用小数点后的“6”位精度,并显示“Decimal”的所有系数数字。 如果小数点后没有数字,除非使用# 选项,小数点也会被删除。
'E' 科学计数法。 与“e”相同,除了使用大写的“E”作为分隔符。
'f' 定点符号。 对于给定的精度 p,将数字格式化为十进制数,小数点后正好有 p 位。 在没有给出精度的情况下,对“float”使用小数点后的“6”位精度,并使用足够大的精度来显示“Decimal”的所有系数数字。 如果小数点后没有数字,除非使用# 选项,小数点也会被删除。
'F' 定点符号。 与 'f' 相同,但将 nan 转换为 NAN,将 inf 转换为 INF
'g' 一般格式。 对于给定的精度“p = 1”,这会将数字四舍五入为“p”有效数字,然后根据其大小将结果格式化为定点格式或科学记数法。 “0”的精度被视为等同于“1”的精度。

精确规则如下:假设使用表示类型“e”和精度“p-1”格式化的结果将具有指数``“exp” . 然后,如果m <= exp <p,其中m-4表示浮点数-6表示小数,则数字的格式为表示类型“f”和精度“p-1-exp” . 否则,数字的格式为表示类型“e”和精度“p-1”。 在这两种情况下,从有效数中删除无关紧要的尾随零,并且如果小数点后面没有剩余数字,则也将删除小数点,除非使用了“#”选项。<br /><br />如果没有给出精度,则使用精度为6 [float] 的有效数字。 对于“Decimal”,结果的系数由值的系数位数构成; 科学记数法用于绝对值小于“1e-6”的值和最低有效位的位值大于1的值,否则使用定点记数法。<br /><br />无论精度如何,正负无穷大正负零nans 分别被格式化为inf-inf0-0nan`。
'G' 一般格式。 与 'g' 相同,但如果数字太大则切换到 'E'无穷大NaN的表示也是大写的。
'n' 数字。 这与 'g' 相同,除了它使用当前的语言环境设置来插入适当的数字分隔符。
'%' 百分比。 将数字乘以 100 并以固定 ('f') 格式显示,后跟一个百分号。
None 对于“float”,这与“g”相同,除了当使用定点表示法来格式化结果时,它总是至少包含小数点后的一位。 使用的精度与忠实地表示给定值所需的一样大。
对于 Decimal,这与 'g''G' 相同,具体取决于当前 context.capitals 的值 十进制上下文。
总体效果是匹配由其他格式修饰符更改的 str() 的输出。
>>> "Scientific: {0:e};  Fixed-point: {0:f};  General format: {0:g}".format(5.2)
'Scientific: 5.200000e+00;  Fixed-point: 5.200000;  General format: 5.2'
>>> 'Correct answers: {:.2%}'.format(19/22)
'Correct answers: 86.36%'

日期类型

>>> import datetime
>>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)
>>> '{:%Y-%m-%d %H:%M:%S}'.format(d)
'2010-07-04 12:15:58'

1.2Formatted string literals(f-string)

格式化字符串文字 ,3.6 版中的新功能。

formatted string literalf-string 是以“f”或“F”为前缀的字符串字面量。 这些字符串可能包含替换字段,这些字段是由大括号{} 分隔的表达式。 虽然其他字符串文字始终具有常量值,但格式化字符串实际上是在运行时计算的表达式。

转义序列

转义序列像在普通字符串文字中一样解码(除非文字也被标记为原始字符串)。 解码后,字符串内容的语法为:

f_string          ::=  (literal_char | "{{" | "}}" | replacement_field)*
replacement_field ::=  "{" f_expression ["="] ["!" conversion] [":" format_spec] "}"
f_expression      ::=  (conditional_expression | "*" or_expr)
                         ("," conditional_expression | "," "*" or_expr)* [","]
                       | yield_expression
conversion        ::=  "s" | "r" | "a"
format_spec       ::=  (literal_char | NULL | replacement_field)*
literal_char      ::=  <any code point except "{", "}" or NULL>

大括号之外的字符串部分按字面处理,除了任何双花括号“{{”或“}}”被相应的单花括号替换。 单个左大括号 ‘{’ 标记一个替换字段,它以 Python表达式开头。 要在计算后显示表达式文本及其值(在调试中很有用),可以在表达式后添加等号“=”。 一个转换字段,由感叹号 ‘!’ 引入 可能会跟随。 也可以附加格式说明符,由冒号“:”引入。 替换字段以结束大括号“}”结尾。

格式化字符串文字中的表达式被视为用括号括起来的正则 Python 表达式,但有一些例外。 不允许使用空表达式,并且lambda赋值表达式 :=都必须用显式括号括起来。 替换表达式可以包含换行符(例如在三引号字符串中),但它们不能包含注释。 每个表达式都在格式化字符串文字出现的上下文中按从左到右的顺序进行计算。

当提供等号“=”时,输出将包含表达式文本、“=”和计算值。 左大括号 ‘{’ 之后、表达式中和 ‘=’ 之后的空格都保留在输出中。 默认情况下,除非指定了格式,否则 ‘=’ 会导致提供表达式的repr()。 当指定格式时,它默认为表达式的 str() ,除非声明了转换 ‘!r’。(3.8)

>>> foo = "bar"
>>> f"{ foo = }" # 保留空白
" foo = 'bar'"
>>> line = "The mill's closed"
>>> f"{line = }"
'line = "The mill\'s closed"'
>>> f"{line = :20}"
"line = The mill's closed   "
>>> f"{line = !r:20}"
'line = "The mill\'s closed" '

字符串格式

如果指定了转换,则在格式化之前转换表达式的计算结果。 转换’!s’ 对结果调用str(),’!r’ 调用repr(),’!a’ 调用ascii()

>>> name = "Fred"
>>> f"He said his name is {name!r}."
"He said his name is 'Fred'."
>>> f"He said his name is {repr(name)}."  # repr() is equivalent to !r
"He said his name is 'Fred'."

然后使用format()协议对结果进行格式化。 格式说明符传递给表达式或转换结果的__format__()方法。 省略格式说明符时传递空字符串。 然后将格式化的结果包含在整个字符串的最终值中。

*格式说明符可能包括嵌套的替换字段。 这些嵌套字段可能包括它们自己的转换字段和格式说明符,但可能不包括更深层嵌套的替换字段。 format specifier mini-language 与 str.format() 方法使用的格式说明符相同。

格式化字符串文字可以连接,但替换字段不能跨文字拆分。

>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"  # 嵌套字段
'result:      12.35'
>>> today = datetime(year=2017, month=1, day=27)
>>> f"{today:%B %d, %Y}"  # 使用日期格式说明符
'January 27, 2017'
>>> f"{today=:%B %d, %Y}" # 使用日期格式说明符和调试
'today=January 27, 2017'
>>> number = 1024
>>> f"{number:#0x}"  # 使用整数格式说明符
'0x400'

与常规字符串文字共享相同语法的结果是替换字段中的字符不得与外部格式化字符串文字中使用的引用冲突:

f"abc {a["x"]} def"    # 错误:外部字符串文字过早结束
f"abc {a['x']} def"    # 解决方法:使用不同的引用

格式表达式中不允许使用反斜杠,并且会引发错误:

>>> f"newline: {ord('\n')}"  # 引发语法错误
SyntaxError: f-string expression part cannot include a backslash

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

>>> newline = ord('\n')
>>> f"newline: {newline}"
'newline: 10'

2.格式化操作符 %

printf 风格的字符串格式化

注意:这里描述的格式化操作表现出各种导致许多常见错误的怪癖(例如无法正确显示元组和字典)。 使用较新的格式化字符串文字、 str.format() 接口或模板字符串可能有助于避免这些错误。 这些替代方案中的每一个都提供了自己的权衡和简单性、灵活性和/或可扩展性的好处。

  • 字符串对象有一个独特的内置操作:%操作符(取模)。 这也称为字符串格式或插值运算符。 给定格式 % 值(其中格式是字符串),格式中的% 转换规范被替换为零个或多个值元素。 效果类似于在C语言中使用sprintf()

  • 如果 format 需要单个参数,则值可能是单个非元组对象。否则,values必须是一个元组,它的项数正好是格式字符串指定的项数,或者是单个映射对象(例如,字典)。

定义格式

转换说明符包含两个或更多字符,并具有以下组件,必须按此顺序出现:

  1. ‘%’ 字符,标记说明符的开始。

  2. 映射键(可选),由带括号的字符序列组成(例如,(somename))。

  3. 转换标志(可选),影响某些转换类型的结果。

  4. 最小字段宽度(可选)。 如果指定为“*”(星号),则从值中元组的下一个元素读取实际宽度,并且要转换的对象在最小字段宽度和可选精度之后。

  5. 精密度(可选),以“.”的形式给出 (点)后跟精度。 如果指定为“*”(星号),则从值中元组的下一个元素读取实际精度,并且要转换的值在精度之后。

  6. 长度修饰符(可选)。

  7. 转换类型。

当正确的参数是字典(或其他映射类型)时,字符串中的格式必须在该字典中包含一个带括号的映射键,该键紧接在 ‘%’ 字符之后插入。 映射键从映射中选择要格式化的值。 例如:

>>> '%(language)s has %(number)03d quote types.' % {'language': "Python", "number": 2}
'Python has 002 quote types.'

在这种情况下,格式中不能出现 * 说明符(因为它们需要顺序参数列表)。

转换标志字符

Flag Meaning
'#' 值转换将使用“alternate form”(定义见下文)。
'0' 转换将为数值填充零。
'-' 转换后的值左调整(如果两者都给出,则覆盖“0”转换)。
' ' (一个空格)在有符号转换产生的正数(或空字符串)之前应该留一个空格。
'+' 符号字符('+''-')将在转换之前(覆盖“空格”标志)。
m.n m表示最小总宽度,n是小数点后的位数
>>> "%#X" % 189
'0XBD'
>>> "%010d" % 12
'0000000012'
>>> "%10d" % 12
'        12'
>>> "%-10d" % 12
'12        '
>>> "%+6.2f" % 12.2389
'+12.24'
>>> "%-6.2f" % 12.2389
'12.24 '

长度修饰符(h、l 或 L)可能存在,但被忽略,因为它对于 Python 不是必需的——例如 %ld 与 %d 相同。

转换类型

Conversion Meaning Notes
'd' 有符号整数十进制
'i' 有符号整数十进制
'o' 有符号八进制值 (1)
'u' 过时的类型 - 它与“d”相同 (6)
'x' 有符号的十六进制(小写) (2)
'X' 有符号的十六进制(大写) (2)
'e' 浮点指数格式(小写) (3)
'E' 浮点指数格式(大写) (3)
'f' 浮点十进制格式 (3)
'F' 浮点十进制格式 (3)
'g' 浮点格式。 如果指数小于 -4 或不小于精度,则使用小写指数格式,否则使用十进制格式 (4)
'G' 浮点格式。 如果指数小于 -4 或不小于精度,则使用大写指数格式,否则使用十进制格式 (4)
'c' 单字符(接受整数或单字符串)
'r' 字符串(使用 repr() 转换任何 Python 对象) (5)
's' 字符串(使用 str() 转换任何 Python 对象) (5)
'a' 字符串(使用 ascii() 转换任何 Python 对象) (5)
'%' 不转换任何参数,结果中会出现一个“%”字符

Notes: 1. 替代形式导致在第一个数字之前插入一个前导八进制说明符 (‘0o’)。

  1. 替代形式导致在第一个数字之前插入前导“0x”或“0X”(取决于使用的是“x”还是“X”格式)。

  2. 替代形式导致结果始终包含小数点,即使其后没有数字。精度决定小数点后的位数,默认为 6。

  3. 替代形式使结果始终包含小数点,并且不会像其他情况那样删除尾随零。精度决定小数点前后的有效位数,默认为 6。

  4. 如果精度为N,则输出被截断为N个字符。

  5. 见 PEP 237。

由于 Python 字符串具有明确的长度,因此 %s 转换不假定 ‘\0’ 是字符串的结尾。

>>> "int: %d;  hex: %x;  oct: %o" % (15,15,15)
'int: 15;  hex: f;  oct: 17'
>>> "Scientific: %e;  Fixed-point: %f;  General format: %g " % (12.2389,12.2389,12.2389)
'Scientific: 1.223890e+01;  Fixed-point: 12.238900;  General format: 12.2389 '
>>> "character : %c;  repr(): %r;  str(): %s;  ascii(): %a" % ("s","skp","skp","skp")
"character : s;  repr(): 'skp';  str(): skp;  ascii(): 'skp'"