10-python格式化字符串的四种方法(%,format,f-string,string template)

3 f-string (格式化字符串) in Python

自 Python 3.6 引入以来,f-string 提供了一种更加简洁和直观的方式来进行字符串格式化。其语法简单明了:只需在字符串前加上字母 fF,并在字符串中使用 {} 来包裹需要插入的内容。

它相比于之前的%格式化和字符串format方法写起来更简洁
f-string 也可以用大写F开头或者与 r 原始字符串结合使用。但是你不能将其与 b”” 或者 ”u” 混用。

在这里插入图片描述

使用 f-string 的样例:

msg = 'hello world'
print(f'msg: {msg}')  # 输出:msg: hello world

这就可以了!再也不需要用 string.format 或者 % 了。不过 f-string 并不能完全替代 str.format。本文也将列举出这两者并不通用的情况。

基本的字符串格式化

如上文所述,使用 f-string 格式化字符串十分简单。唯一的要求就是给它一个有效的表达式。f-string 也可以用大写 F 开头或者与 r 原始字符串结合使用。但是你不能将其与 b"" 或者 u"" 混用。

book = "The dog guide"
num_pages = 124
print(f"The book {book} has {num_pages} pages")  # 输出:The book The dog guide has 124 

f-string 的限制

虽然 f-string 十分便捷,但它并不能完全代替 str.format。f-string 在表达式出现的上下文中进行求值计算。根据 PEP 498,这意味着该表达式可以获取所有局部和全局变量。而且该表达式是在运行时计算的表达式。如果在 { <expr> } 之中使用的表达式无法被计算,就会跳出如下异常。

f"{name}"
# NameError: name 'name' is not defined

这对 str.format 来说就不是问题,你可以提前定义一个模板字符串,并在之后调用 .format 方法时再传递上下文信息。

s = "{name}"
print(s.format(name="Python"))  # 输出:Python
print(s)  # 输出:{name}

另外还有个限制是,你不能在 f-string 中使用行内注释。

f"My name is {name #name}!"
# SyntaxError: f-string expression part cannot include '#'

如何格式化一个表达式

如果不想定义变量,那你可以在大括号中使用常量。Python 会计算该表达式并显示最终计算结果。

print(f"4 * 4 is {4 * 4}")  # 输出:4 * 4 is 16

或者你可以…

n = 4
print(f"4 * 4 is {n * n}")  # 输出:4 * 4 is 16

如何使用 f-string 来调试代码

调试是 f-string 最常见的用途之一了。Python 3.8 之前,很多人会用一种非常繁杂的 hello = 42; f"hello = {hello}" 来进行调试。针对此 Python 3.8 引入了一个新功能。你可以用 f"{hello=}" 重写上面的代码,而 Python 会显示 hello=42。下面这个例子展示了在使用函数表达式时如何应用该特性,其原理与上文代码是一样的。

def magic_number():
    return 42

print(f"{magic_number() = }")  # 输出:magic_number() = 42

如何格式化数字的不同进制

f-string 还能在不同进制下显示数字。例如,你不需要通过 b 来对一个 int 进行格式转化就可以显示其二进制结果。

print(f'{7:b}')  # 输出:111

总结一下就是你可以用 f-string 来格式化:

  • int 到二进制
  • int 到十六进制
  • int 到八进制
  • int 到十六进制(所有符号大写)

下面的例子使用缩进功能和进制格式化创建了一个表,可以显示数字在不同进制下的值。

bases = {
    "b": "bin", 
    "o": "oct", 
    "x": "hex", 
    "X": "HEX", 
    "d": "decimal"
}
for n in range(1, 21):
    for base, desc in bases.items():
        print(f"{n:5{base}}", end=' ')
    print()

如何用 f-string 打印对象

你可以用 f-string 打印自定义对象。默认设置是,如果你向 f-string 表达式传递了一个对象,它将会显示该对象 __str__ 方法的返回值。不过,你也可以用显式转换操作标志来打印 __repr__ 的值。

  • !r - 使用 repr() 将值转化为文本。
  • !s - 使用 str() 将值转化为文本。
class Color:
    def __init__(self, r: float = 255, g: float = 255, b: float = 255):
        self.r = r
        self.g = g
        self.b = b

    def __str__(self) -> str:
        return "A RGB color"

    def __repr__(self) -> str:
        return f"Color(r={self.r}, g={self.g}, b={self.b})"

c = Color(r=123, g=32, b=255)

# 如不加任何操作符, 会打印 __str__ 的值
print(f"{c}")  # 输出:A RGB color

# 用 `obj!r` 的话会打印 __repr__ 的值
print(f"{c!r}")  # 输出:Color(r=123, g=32, b=255)

# 使用 `!s` 跟默认值一样
print(f"{c!s}")  # 输出:A RGB color

Python 也允许通过定义不同类型使用 __format__ 方法控制格式化结果,下面的例子会展示所有可能情况。

class Color:
    def __init__(self, r: float = 255, g: float = 255, b: float = 255):
        self.r = r
        self.g = g
        self.b = b

    def __str__(self) -> str:
        return "A RGB color"

    def __repr__(self) -> str:
        return f"Color(r={self.r}, g={self.g}, b={self.b})"

    def __format__(self, format_spec: str) -> str:
        if not format_spec or format_spec == "s":
            return str(self)

        if format_spec == "r":
            return repr(self)

        if format_spec == "v":
            return f"Color(r={self.r}, g={self.g}, b={self.b}) - A nice RGB thing."

        if format_spec == "vv":
            return (
                f"Color(r={self.r}, g={self.g}, b={self.b}) "
                f"- A more verbose nice RGB thing."
            )

        if format_spec == "vvv":
            return (
                f"Color(r={self.r}, g={self.g}, b={self.b}) "
                f"- A SUPER verbose nice RGB thing."
            )

        raise ValueError(
            f"Unknown format code '{format_spec}' " "for object of type 'Color'"
        )

c = Color(r=123, g=32, b=255)

print(f'{c:v}')  # 输出:Color(r=123, g=32, b=255) - A nice RGB thing.
print(f'{c:vv}')  # 输出:Color(r=123, g=32, b=255) - A more verbose nice RGB thing.
print(f'{c:vvv}')  # 输出:Color(r=123, g=32, b=255) - A SUPER verbose nice RGB thing.
print(f'{c}')  # 输出:A RGB color
print(f'{c:s}')  # 输出:A RGB color
print(f'{c:r}')  # 输出:Color(r=123, g=32, b=255)

最后,还有个用来转义 ASCII 字符的 a 操作符。更多信息可参考 官方文档

utf_str = "Áeiöu"
print(f"{utf_str!a}")  # 输出:'\\xc1ei\\xf6u'

如何用 f-string 设定浮点数精度

F-string 可以像 str.format 那样格式化浮点数。想要实现这一点,你需要加一个 :(冒号)再加一个 .(英文句号)然后跟着小数点位数最后以 f 结尾。

举例来说,你可以通过如下代码打印一个浮点数精确到百分位的近似值。

num = 4.123956
print(f"num rounded to 2 decimal places = {num:.2f}")  # 输出:num rounded to 2 decimal places = 4.12

不加任何选项的话,则会打印浮点数本身的精确值。

print(f'{num}')  # 输出:4.123956

如何将一个数字格式化为百分数

Python f-string 方法有个非常便捷的实现格式化百分数的操作方法。方法与浮点数格式化类似,但是要用 % 代替结尾的 f。它会将原始数值乘以 100 并显示成有百分符号的固定格式。精度一样也是可以设定的。

total = 87
true_pos = 34
perc = true_pos / total

print(f"Percentage of true positive: {perc:%}")  # 输出:Percentage of true positive: 39.080460%
print(f"Percentage of true positive: {perc:.2%}")  # 输出:Percentage of true positive: 39.08%

如何调整或者增加 f-string 的填充

你可以便捷地通过 < 或者 > 符号来调整字符串填充。

greetings = "hello"
print(f"She says {greetings:>10}")  # 输出:She says      hello

# Pad 10 char to the right
print(f"{greetings:>10}")  # 输出:     hello

print(f"{greetings:<10}")  # 输出:hello     

# You can omit the < for left padding
print(f"{greetings:10}")  # 输出:hello     
a = "1"
b = "21"
c = "321"
d = "4321"

print("\n".join((f"{a:>10}", f"{b:>10}", f"{c:>10}", f"{d:>10}")))
# 输出:
#          1
#         21
#        321
#       4321

如何转义符号

如果你想打印由大括号括起来的变量名称,而不是该变量的值,那你需要双层大括号 {{<expr>}}

hello = "world"
print(f"{{hello}} = {hello}")  # 输出:{hello} = world

而如果你想转义双引号,就需要在引号前用反斜线 \ 做标记。

print(f"{hello} = \"hello\"")  # 输出:world = "hello"

如何使字符串居中

想要实现字符串居中,可以通过 var:^N 的方式。其中 var 是你想要打印的变量,N 是字符串长度。如果 N 小于 var 的长度,会打印全部字符串。

hello = "world"
print(f"{hello:^11}")  # 输出:  world   
print(f"{hello:*^11}")  # 输出:***world***
print(f"{hello:*^10}")  # 输出:**world***
print(f"{hello:^2}")  # 输出:world

如何格式化千分位

F-string 也允许我们自定义数字显示的格式。有个非常普遍的需求就是把数字以每 3 位为一个间隔使用下划线进行分隔。

big_num = 1234567890
print(f"{big_num:_}")  # 输出:1_234_567_890

如何使用逗号千分位分隔符数字

实际上,你可以随便用任何符号做千分位分隔符。所以用逗号做分隔符也完全没问题。

big_num = 1234567890
print(f"{big_num:,}")  # 输出:1,234,567,890

甚至可以一次性同时搞定既有千分位分隔符又有精度设定的浮点数。

num = 2343552.6516251625
print(f"{num:,.3f}")  # 输出:2,343,552.652

如何用空格做千分位分隔符

用空格也可以吗?好吧,这个问题是挺棘手,不过也能实现。你可以用逗号做分隔符之后再用空格替换逗号。

big_num = 1234567890
print(f"{big_num:,}".replace(',', ' '))  # 输出:1 234 567 890

还有个方法是设定你的本地语言环境,换成一个用空格作千位分隔符的环境比如 pl_PL(波兰语环境)。更多信息可参考这个 Stack Overflow 链接

如何用科学计数法(指数计数法)显示一个数字

可以用 e 或者 E 字符来格式化。

num = 2343552.6516251625
print(f"{num:e}")  # 输出:2.343553e+06
print(f"{num:E}")  # 输出:2.343553E+06
print(f"{num:.2e}")  # 输出:2.34e+06
print(f"{num:.4E}")  # 输出:2.3436E+06

在 f-string 中使用 if-else

F-string 也能计算稍微复杂的运算式,比如 if/else。

a = "this is a"
b = "this is b"

print(f"{a if 10 > 5 else b}")  # 输出:this is a
print(f"{a if 10 < 5 else b}")  # 输出:this is b

如何在 f-string 中使用字典

你可以在 f-string 中使用字典。唯一的要求是引起整个字符串的引号要跟内部的引号不一样。

color = {"R": 123, "G": 145, "B": 255}
print(f"{color['R']}")  # 输出:123
print(f'{color["R"]}')  # 输出:123
print(f"RGB = ({color['R']},{color['G']}, {color['B']})")  # 输出:RGB = (123, 145, 255)

如何用 f-string 拼接字符串

合并 f-string 与普通字符串拼接一样,可以隐式地直接拼接,或者显式地用加号 +,或者使用 str.join 方法。

# 隐式字符串拼接
print(f"{123}" " = " f"{100}" " + " f"{20}" " + " f"{3}")  # 输出:123 = 100 + 20 + 3

# 使用加号 + 的显式字符串拼接
print(f"{12}" + " != " + f"{13}")  # 输出:12 != 13

# 使用 str.join 的字符串拼接
print("".join((f"{13}", f"{45}")))  # 输出:1345
print("#".join((f"{13}", f"{45}")))  # 输出:13#45

如何格式化 datetime 对象

F-string 也支持 datetime 对象的格式化。其过程与 str.format 格式化日期的方法很近似。请查阅官方文档中的表格获取更多所支持格式的相关信息。

import datetime
now = datetime.datetime.now()
ten_days_ago = now - datetime.timedelta(days=10)
print(f'{ten_days_ago:%Y-%m-%d %H:%M:%S}')  # 输出:2024-08-22 16:08:07
print(f'{now:%Y-%m-%d %H:%M:%S}')  # 输出:2024-09-01 16:08:07

4.字符串模板 string template

>>> from string import Template
>>> s = Template('$who likes $what')
>>> s.substitute(who='tim', what='kung pao')
'tim likes kung pao'
>>> d = dict(who='tim')
>>> Template('Give $who $100').substitute(d)
Traceback (most recent call last):
...
ValueError: Invalid placeholder in string: line 1, col 11
>>> Template('$who likes $what').substitute(d)
Traceback (most recent call last):
...
KeyError: 'what'
>>> Template('$who likes $what').safe_substitute(d)
'tim likes $what'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huanghong6956

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值