f-string格式化字符串

自Python 3.6开始加入标准库。您可以在PEP 498中阅读所有内容。f-string,一种改进Python格式字符串的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快!

f-string在形式上是以 f 或 F 修饰符引领的字符串(f’xxx’ 或 F’xxx’),以大括号 {} 标明被替换的字段;f-string在本质上并不是字符串常量,而是一个在运行时运算求值的表达式。

f-string在功能方面不逊于传统的%-formatting语句和str.format()函数,同时性能又优于二者,且使用起来也更加简洁明了,因此对于Python3.6及以后的版本,推荐使用f-string进行字符串格式化。

例如:

1
2
3
4
name = "Tom"
age = 44
s = f"Hello, {name}. You are {age}."
print(s) # 输出Hello, Tom. You are 44.

使用大写字母F也是有效的:

1
2
3
4
name = "Eric"
age = 74
s = F"Hello, {name}. You are {age}."
print(s) # 输出Hello, Eric. You are 74.

由于f-string是在运行时进行渲染的,因此可以将任何有效的Python表达式放入其中。这可以让你做一些漂亮的事情。 你可以做一些非常简单的事情,就像这样: f”{2 * 37}” #输出 74

你可以调用函数

1
2
3
name = "Eric"
s = f"{name.lower()} is funny."
print(s)  # 输出eric is funny.

f-string语法

1
2
3
("{{" | "}}" | "{" f_expression ["!" conversion] [":" format_spec] "}")*  
conversion        ::=  "s" | "r" | "a"  
format_spec       ::=  (literal_char | NULL | replacement_field)*  

花括号外部的字符串部分按字面处理,除了任何两个的花括号’{{‘或’}}‘替换为相应的单个花括号。单个开口花括号’{‘标记替换字段,以Python表达式开头。在表达式之后,可能存在由感叹号’!‘引入的转换字段。还可以附加格式说明符,由冒号’:’引入。替换字段以右侧括号’}‘结尾。

格式化字符串文字中的表达式被视为由括号括起来的常规Python表达式,但有一些例外。不允许使用空表达式,并且lambda表达式必须由显式括号括起来。表达式可以包含换行符(例如,在三引号字符串中),但它们不能包含注释。

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

format_spec语法(同str.format()方法一样)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{[[fill]align][sign][#][0][width][,][.precision][type]}

fill  可选,可以是任何字符
align 可选,是对齐方式,可供选择的值有:
     '<' 左对齐
     '>' 右对齐
     '=' 只对数字类型有效
     '^'居中对齐
sign  可选,是对齐方式,可供选择的值有:
     '+' 表示正负数字都应使用符号。正数前加正号,负数前加负号;
     '-' 表示符号只能用于负数(这是默认行为)。正数前无符号,负数前加负号;
     ' ' 正数前加空格,负数前加负号;
#    可选,用于转换。 对于不同类型,替代形式的定义不同。 此选项仅对integer,float,complex和Decimal类型有效。 对于整数,当使用二进制,八进制或十六进制输出时,此选项将前缀“0b”,“0o”或“0x”添加到输出值。 对于浮点数,复数和十进制,备用形式会导致转换结果始终包含小数点字符,即使后面没有数字也是如此。 通常,只有在跟随数字的情况下,这些转换的结果中才会出现小数点字符。 此外,对于“g”和“G”转换,不会从结果中删除尾随零。
width    可选,数字宽度,表示总共输出多少位数字
.precision    可选,小数点后保留的位数,进行四舍五入计算。
typecode     可选
  s : 获取传入对象的__str__方法的返回值,并将其格式化到指定位置
  r : 获取传入对象的__repr__方法的返回值,并将其格式化到指定位置
  c : 如果是整数的话,将数字转换成其unicode对应的值10进制范围为0 <= i <= 1114111(py27则只支持0-255);如果是字符的话,将字符添加到指定位置
  o : 将整数转换成八进制表示,并将其格式化到指定位置
  x : 将整数转换成十六进制表示,并将其格式化到指定位置
  d : 将整数、浮点数转换成十进制表示,并将其格式化到指定位置
  e : 将整数、浮点数转换成科学计数法,并将其格式化到指定位置(小写e
  E : 将整数、浮点数转换成科学计数法,并将其格式化到指定位置(大写E
  f :  将整数、浮点数转换成浮点数表示,并将其格式化到指定位置(默认保留小数点后6位)
  F : 同上
  g : 自动调整将整数、浮点数转换成浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是e;)
  G : 自动调整将整数、浮点数转换成浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是E;)
  % : 百分比。将数字乘以100,并以固定格式(“f”)显示,后跟百分号。

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
>>> 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()等同于!r
"He said his name is 'Fred'."
>>> 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}"  # 利用date的format specifier
'January 27, 2017'
>>> number = 1024
>>> f"{number:#0x}"  # 利用整数的format specifier
'0x400'

你甚至可以使用带有f-string的类创建对象。想象一下你有以下类:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Comedian:
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
    def __str__(self):
        return f"{self.first_name} {self.last_name} is {self.age}."
    def __repr__(self):
        return f"{self.first_name} {self.last_name} is {self.age}. Surprise!"

new_comedian = Comedian("Eric", "Idle", "74")
s = f"{new_comedian}"
print(s)  #输出Eric Idle is 74.

__str ()和repr ()方法处理对象如何呈现为字符串,因此您需要确保在类定义中包含至少一个这些方法。如果必须选择一个,请使用repr (),因为它可以代替str __()。 __str ()返回的字符串是对象的非正式字符串表示,应该可读。repr ()返回的字符串是官方表示,应该是明确的。调用str()和repr()比直接使用str ()和repr __()更好。

默认情况下,f字符串将使用__str (),但如果包含转换标志!r,则可以确保它们使用repr __():

例如:

1
2
3
4
f"{new_comedian}"
#输出 Eric Idle is 74.
f"{new_comedian!r}"
#输出 Eric Idle is 74. Surprise!

多行f-string

例如:

1
2
3
4
message = (f"Hi {name}. "
        f"You are a {profession}. "
        f"You were in {affiliation}.")
print(message)  #输出Hi Eric. You are a comedian. You were in Monty Python.

但请记住,您没必要将f放在多行字符串的每一行的前面。以下代码也能work:

1
2
3
4
message = (f"Hi {name}. "
        "You are a {profession}. "
        "You were in {affiliation}.")
print(message)  #输出Hi Eric. You are a {profession}. You were in {affiliation}.

注意事项

引号

您可以在表达式中使用各种类型的引号。只要确保在表达式中使用的f-string外部没有使用相同类型的引号即可。 以下写法都是正确的:

1
2
3
4
5
6
f"{'Eric Idle'}"  #输出Eric Idle
f"'Eric Idle'"    #输出'Eric Idle'
f'{"Eric Idle"}'  #输出Eric Idle
f'"Eric Idle"'    #输出"Eric Idle"
f"""Eric Idle"""  #输出Eric Idle
f'''Eric Idle'''  #输出Eric Idle

字典

说到引号,注意你在使用字典的时候。如果要为字典的键使用单引号,请记住确保对包含键的f-string使用双引号。 以下代码是有效的:

1
2
comedian = {'name': 'Eric Idle', 'age': 74}
f"The comedian is {comedian['name']}, aged {comedian['age']}."  #输出The comedian is Eric Idle, aged 74.

但是,以下代码就是一个语法错误:

1
2
3
4
f'The comedian is {comedian['name']}, aged {comedian['age']}.'
  File "<ipython-input-40-cd7d8a3db23b>", line 1
    f'The comedian is {comedian['name']}, aged {comedian['age']}.'
SyntaxError: invalid syntax

如果您在字典键周围使用与在f-string外部使用相同类型的引号,则第一个字典键开头的引号将被解释为字符串的结尾。

大括号

为了使字符串出现大括号,您必须使用双大括号:

例如:

1
2
3
4
5
6
7
name = "Tom"
s1 = F"Hello, {name}. "
s2 = F"Hello, {{name}}. "
s3 = F"Hello, {{{name}}}. "
print(s1) #输出Hello, Tom.        #替换变量name的值
print(s2) #输出Hello, {name}.     #两个{{替换为{,{失去应有的替换作用,name作为字符串打印出来。
print(s3) #输出Hello, {Tom}.      #前两个{{替换为{,第三个{将变量name替换为Tom,所以结果是{Tom}。

反斜杠

正如您之前所看到的,您可以在f-string的字符串部分使用反斜杠转义符。但是,您不能使用反斜杠在f-string的表达式部分中进行转义:

例如:

1
2
3
4
5
6
print(f"\"I am {'Eric Idle'}\"")    #输出"I am Eric Idle"
print(f"\"I am {\'Eric Idle\'}\"")  #报错
  File "main.py", line 1
    print(f"\"I am {\'Eric Idle\'}\"")
         ^
SyntaxError: f-string expression part cannot include a backslash

lambda表达式

如果您需要使用lambda表达式,请记住,lambda表达式必须由显式括号括起来。

例如:

1
2
3
4
f"{lambda x: x * 37(2)}"
  File "<fstring>", line 1
    (lambda x)
SyntaxError: unexpected EOF while parsing

您可以通过将您的lambda嵌套在圆括号中来解决此问题:

1
2
f"{(lambda x: x * 37)(2)}"
74

转载请注明本网址。