Python 字符串格式化 f-string f“{}“ .format

Python f-string 用法

简单介绍

格式字符串字面值 或称 f-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>

起源

f-string是格式化字符串的一种很好的方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快!

  • 3.6 新版功能.

  • 在 3.7 版更改: Python 3.7 以前, 因为实现的问题,不允许在格式字符串字面值表达式中使用 await 表达式与包含 async for 子句的推导式。

  • 3.8 新版功能: 等号 '='

    '='用法通常用于调试过程输出变量名称及其存储的值.

    表达式里含等号 ‘=’ 时,输出内容包括表达式文本、‘=’ 、求值结果。输出内容可以保留表达式中左花括号 ‘{’ 后,及 ‘=’ 后的空格。没有指定格式时,‘=’ 默认调用表达式的 repr()。指定了格式时,默认调用表达式的 str(),除非声明了转换字段 ‘!r’。

基本用法

整数格式化

基本格式类型

格式描述符含义与作用适用变量类型
s普通字符串格式字符串
b二进制整数格式整数
c字符格式,按 unicode 编码将整数转换为对应字符整数
d十进制整数格式整数
o八进制整数格式整数
x十六进制整数格式(小写字母)整数
X十六进制整数格式(大写字母)整数
e科学计数格式,以 e 表示 ×10^浮点数、复数、整数(自动转换为浮点数)
E与 e 等价,但以 E 表示 ×10^浮点数、复数、整数(自动转换为浮点数)
f定点数格式,默认精度(precision)是 6浮点数、复数、整数(自动转换为浮点数)
F与 f 等价,但将 nan 和 inf 换成 NAN 和 INF浮点数、复数、整数(自动转换为浮点数)
g通用格式,小数用 f,大数用 e浮点数、复数、整数(自动转换为浮点数)
G与 G 等价,但小数用 F,大数用 E浮点数、复数、整数(自动转换为浮点数)
%百分比格式,数字自动乘上 100 后按 f 格式排版,并加 % 后缀浮点数、整数(自动转换为浮点数

数学符号相关格式描述符

格式描述符含义与作用
+负数前加负号(-),正数前加正号(+
-负数前加负号(-),正数前不加任何符号(默认)
(空格)负数前加负号(-),正数前加一个空格
#切换数字显示方式, 用于控制是否显示进制前缀, 例如二进制’0b’, 八进制的’0o’和十六进制的’0x’

注:

空格或其他符合也可作为宽度占位符(例如下文对齐和填充字符部分用法).

千分位占位符也可以使用_.

8 16 进制的占位符如果使用大写格式, 那么打印出的进制前缀也会变为相应大写格式.

from random import randint
print(f"前导0、统一宽度、千分位、八进制、十六进制、带前缀大写十六进制、二进制")

nlist = [randint(-9999, 99999) for i in range(10)]
for i, n in enumerate(nlist):
    line = f"No.{i:04d}:{n:8d}:{n:8,d}:{n:8o}:{n:8x}:{n:#8X}:{n:020b}"
    print(line)

前导0、统一宽度、千分位、八进制、十六进制、带前缀大写十六进制、二进制
No.0000:   64972:  64,972:  176714:    fdcc:  0XFDCC:00001111110111001100
No.0001:   92916:  92,916:  265364:   16af4: 0X16AF4:00010110101011110100
No.0002:   99560:  99,560:  302350:   184e8: 0X184E8:00011000010011101000
No.0003:   23767:  23,767:   56327:    5cd7:  0X5CD7:00000101110011010111
No.0004:   33628:  33,628:  101534:    835c:  0X835C:00001000001101011100
No.0005:     710:     710:    1306:     2c6:   0X2C6:00000000001011000110
No.0006:   47749:  47,749:  135205:    ba85:  0XBA85:00001011101010000101
No.0007:   56646:  56,646:  156506:    dd46:  0XDD46:00001101110101000110
No.0008:   22526:  22,526:   53776:    57fe:  0X57FE:00000101011111111110
No.0009:   34263:  34,263:  102727:    85d7:  0X85D7:00001000010111010111

浮点数格式化

from random import uniform
print("前导0、统一宽度右对齐、千分位、小数点后固定位数、百分比")

flist = [uniform(-999, 9999) for i in range(10)]
for i, f in enumerate(flist):
    line = f"{f:012.2f}:{f:12.3f}:{f:12,.2f}:{f:12.1%}"
    print(line)

前导0、统一宽度右对齐、千分位、小数点后固定位数、百分比
000004842.42:    4842.417:    4,842.42:   484241.7%
000003106.63:    3106.634:    3,106.63:   310663.4%
000009213.21:    9213.205:    9,213.21:   921320.5%
000008040.67:    8040.671:    8,040.67:   804067.1%
000006086.32:    6086.322:    6,086.32:   608632.2%
000005251.10:    5251.105:    5,251.10:   525110.5%
000008219.07:    8219.072:    8,219.07:   821907.2%
000007046.32:    7046.325:    7,046.32:   704632.5%
000000192.89:     192.888:      192.89:    19288.8%
000006164.21:    6164.208:    6,164.21:   616420.8%

时间格式化

常用的特殊格式类型:标准库 datetime 给定的用于排版时间信息的格式类型,适用于 datedatetimetime 对象

格式描述符含义显示样例
%a星期几(缩写)‘Sun’
%A星期几(全名)‘Sunday’
%w星期几(数字,0 是周日,6 是周六)‘0’
%u星期几(数字,1 是周一,7 是周日)‘7’
%d日(数字,以 0 补足两位)‘07’
%b月(缩写)‘Aug’
%B月(全名)‘August’
%m月(数字,以 0 补足两位)‘08’
%y年(后两位数字,以 0 补足两位)‘14’
%Y年(完整数字,不补零)‘2014’
%H小时(24 小时制,以 0 补足两位)‘23’
%I小时(12 小时制,以 0 补足两位)‘11’
%p上午/下午‘PM’
%M分钟(以 0 补足两位)‘23’
%S秒钟(以 0 补足两位)‘56’
%f微秒(以 0 补足六位)‘553777’
%zUTC 偏移量(格式是 ±HHMM[SS],未指定时区则返回空字符串)‘+1030’
%Z时区名(未指定时区则返回空字符串)‘EST’
%j一年中的第几天(以 0 补足三位)‘195’
%U一年中的第几周(以全年首个周日后的星期为第 0 周,以 0 补足两位)‘27’
%w一年中的第几周(以全年首个周一后的星期为第 0 周,以 0 补足两位)‘28’
%V一年中的第几周(以全年首个包含 1 月 4 日的星期为第 1 周,以 0 补足两位)‘28’
import datetime
e = datetime.datetime.today()
f'the time is {e:%Y-%m-%d (%a) %H:%M:%S}'

'the time is 2022-12-29 (Thu) 22:23:58'

格式化打印各种数据类型

from faker import Faker

f = Faker()
# 使用faker库生成所需数据
word = f.word()  # 生成一个单词
print(f"str: '{word}' in a line")
print(f"int: {f.pyint()}")
print(f"float: {f.pyfloat()}")
print(f"bool: {f.pybool()}")
print(f"list: {f.words()}")
print(f"dict: {f.pydict(3, 1, 2)}")
print(f"set: {f.pyset(3, 1, 2)}")
print(f"tuple{f.pytuple(3, 1, 2)}")

str: 'animal' in a line
int: 3387
float: -31220036492.2902
bool: False
list: ['expect', 'shake', 'there']
dict: {'yard': 7553}
set: {106}
tuple(2603, 8262, 3320)

对齐和填充字符

from faker import Faker

f = Faker()
namelist = [f.first_name() for i in range(10)]
print(f"{'-' * 10}{'左中右对齐'}{'-' * 10}")
for name in namelist:
    line = f"|{name:<16}|{name:^16}|{name:>16}|"
    print(line)

print(f"\n{'-' * 10}{'填充字符'}{'-' * 10}")
for i, name in enumerate(namelist):
    line = f"{i}{name:.>16}"
    print(line)

----------左中右对齐----------
|James           |     James      |           James|
|Luis            |      Luis      |            Luis|
|Keith           |     Keith      |           Keith|
|Kimberly        |    Kimberly    |        Kimberly|
|Lauren          |     Lauren     |          Lauren|
|Gregory         |    Gregory     |         Gregory|
|Daniel          |     Daniel     |          Daniel|
|Adam            |      Adam      |            Adam|
|Emily           |     Emily      |           Emily|
|Jessica         |    Jessica     |         Jessica|

----------填充字符----------
0...........James
1............Luis
2...........Keith
3........Kimberly
4..........Lauren
5.........Gregory
6..........Daniel
7............Adam
8...........Emily
9.........Jessica

此处f"\n{'-' * 10}{'填充字符'}{'-' * 10}"可以用f"\n{'填充字符':-^24}"替代, f-string的优雅之处在此刻尽显

print(f"\n{'填充字符并居中对齐':-^35}")
for i, name in enumerate(namelist):
    line = f"[{name:-^40}]"
    print(line)

-------------填充字符并居中对齐-------------
[-----------------James------------------]
[------------------Luis------------------]
[-----------------Keith------------------]
[----------------Kimberly----------------]
[-----------------Lauren-----------------]
[----------------Gregory-----------------]
[-----------------Daniel-----------------]
[------------------Adam------------------]
[-----------------Emily------------------]
[----------------Jessica-----------------]

调试阶段输出变量名及其内容

# 变量=值,输出
a, b = 12, 34
s = f"{a=}, {b=}, {a*a+b*b=}"
print(s)

a=12, b=34, a*a+b*b=1300

嵌套调用

# 嵌套的格式
from math import pi
for i in range(10):
    print(f"{pi:.{i}f}")  # f-string中可以使用变量进行动态格式化

3
3.1
3.14
3.142
3.1416
3.14159
3.141593
3.1415927
3.14159265
3.141592654

多行f-string

name, age, lang = 'leo', 21, 'python'
message = (
    f"Hi I'm {name}. "
    f"My age is {age}. "
    f"{lang} is the best language."
)
message

"Hi I'm leo. My age is 21. python is the best language."

任意表达式

f-string 是在运行时进行渲染的, 因此可以使用表达式, 函数…

这将使您的代码变得更加优雅

细心的您可能会发现, 上文有部分使用了此特性

name = 'Leo'
age = 21
print(
    f"My name is {name.lower()}. "
    f"Tomorrow my age will be {age + 1}"
)

My name is leo. Tomorrow my age will be 22

您甚至可以使用f-string来格式化您打印的对象

就像这样:

class Person:
    def __init__(self, name, age, type_):
        self.name = name
        self.age = age
        self.type_ = type_

    def __str__(self):
        return f"<{self.__class__.__name__}> {self.name}, {self.age}, {self.type_}"


p = Person("leo", 21, "student")
print(p)

<Person> leo, 21, student

注意

在使用 f-string 时大括号内所用的引号不能和大括号外的引号定界符冲突, 根据情况切换’和", 如果仍不满足需求可以使用’''和"“”

>>> f'I am {"Eric"}'
'I am Eric'
>>> f'I am {'Eric'}'
  File "<stdin>", line 1
    f'I am {'Eric'}'
                ^
SyntaxError: invalid syntax
>>> f"He said {"I'm Eric"}"
  File "<stdin>", line 1
    f"He said {"I'm Eric"}"
                ^
SyntaxError: invalid syntax

>>> f'He said {"I'm Eric"}'
  File "<stdin>", line 1
    f'He said {"I'm Eric"}'
                  ^
SyntaxError: invalid syntax

>>> f"""He said {"I'm Eric"}"""
"He said I'm Eric"
>>> f'''He said {"I'm Eric"}'''
"He said I'm Eric"

当您想要在f-string中打印{}时, 需要使用{{}} , 此时双括号内部的内容将不会被渲染

>>> f"{{12 + 3}}"
'{12 + 3}'

conversion 用法

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

默认情况下,f-string 将使用 str(),但如果包含转换标志,则可以确保它们使用 repr()

class People:
    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}. made by repr!"


# 调用
person01 = People("Wang", "Leo", "21")
print(f"{person01}")
print(f"{person01!r}")

Wang Leo is 21.
Wang Leo is 21. made by repr!

ascii(object)
与 repr() 类似,返回一个字符串,表示对象的可打印形式,但在 repr() 返回的字符串中,非 ASCII 字符会用 \x、\u 和 \U 进行转义。生成的字符串类似于 Python 2 中 repr() 的返回结果。

ascii(object)
与 repr() 类似,返回一个字符串,表示对象的可打印形式,但在 repr() 返回的字符串中,非 ASCII 字符会用 \x、\u 和 \U 进行转义。生成的字符串类似于 Python 2 中 repr() 的返回结果。

!a 用法

a_str = "阿多 🔥 hold the door"
b_str = "💯 ✔ 🌈"
print(f"{a_str!a}")
print(f"{b_str!a}")

'\u963f\u591a \U0001f525 hold the door'
'\U0001f4af \u2714 \U0001f308'
class People:
    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}. made by repr!"


# 调用
person01 = People("Wang", "Leo", "21")
print(f"{person01}")
print(f"{person01!r}")

Wang Leo is 21.
Wang Leo is 21. made by repr!
a_str = "阿多 🔥 hold the door"
b_str = "💯 ✔ 🌈"
print(f"{a_str!a}")
print(f"{b_str!a}")

'\u963f\u591a \U0001f525 hold the door'
'\U0001f4af \u2714 \U0001f308'

旧时代的格式化字符串

在 Python 3.6 之前,有两种将 Python 表达式嵌入到字符串文本中进行格式化的主要方法:

  • %-formatting
  • str.format()

这两种方法都具有一定的局限性

从 Python 3.6 开始,f-string 作为格式化字符串的一种很好的新方法。与其他格式化方式相比,

不仅更易读,更简洁,不易出错,而且速度更快!

%-formatting

字符串支持使用%进行格式化, 例如:

name = 'leo'
msg = "Hello, I'm %s." % name
print(msg)

Hello, I'm leo.

为什么 %-formatting 不好用

上面刚刚看到的代码示例足够易读。

但是,一旦你开始使用几个参数和更长的字符串,你的代码将很快变得不太容易阅读。

这种格式不是很好,因为它是冗长的,会导致错误,比如不能正确显示元组或字典, 不方便找出每个占位符对应的变量。

幸运的是,未来有更光明的日子 — 3.6 版本, f-string出现了。

如你所见, 使用f-string后代码变得更加直观

first_name = "Eric"
last_name = "Idle"
age = 8
profession = "comedian"
affiliation = "Monty Python"
info1 = "Hello, %s %s. You are %02d. You are a %s. You were a member of %s." % (
    first_name, last_name, age, profession, affiliation)
info2 = f"Hello, {first_name} {last_name}. You are {age:02d}. You are a {profession}. You were a member of {affiliation}."
print(info1)
print(info2)

Hello, Eric Idle. You are 08. You are a comedian. You were a member of Monty Python.
Hello, Eric Idle. You are 08. You are a comedian. You were a member of Monty Python.

str.format()

这种字符串格式化方式早在 2.6 版本就已经引入

str.format()是对%-formatting的改进。它使用正常的函数调用语法,并且可以通过对要转换为字符串的对象的**format **()方法进行扩展。

使用 str.format(),被替换字段用大括号标记:

name, age = 'leo', 8
msg = "Hello, {}. I'm {:02d}.".format(name, age)
print(msg)

Hello, leo. I'm 08.

并且您可以使用索引来决定使用变量的顺序

name, age = 'leo', 8
msg1 = "Hello, {1}. my info is: {1}-{0:02d}.".format(age, name)
print(msg1)

Hello, leo. my info is: leo-08.

%-formatting 相比, str.format() 完全可以说是一个升级版本.
但当处理多个参数和更长的字符串时, 仍存在过于冗长, 易读性差等问题

first_name = "Eric"
last_name = "Idle"
age = 74
profession = "comedian"
affiliation = "Monty Python"
print(("Hello, {first_name} {last_name}. You are {age}. " +
       "You are a {profession}. You were a member of {affiliation}.")
      .format(first_name=first_name, last_name=last_name, age=age,
              profession=profession, affiliation=affiliation))

Hello, Eric Idle. You are 74. You are a comedian. You were a member of Monty Python.

性能

f-string 中的 f 也可以代表“速度快”。

f-string 比%-formatting 和 str.format()都快。正如你已经看到的,f-string 是运行时渲染的表达式,而不是常量值。以下是文档摘录:

“F-strings provide a way to embed expressions inside string literals, using a minimal syntax. It should be noted that an f-string is really an expression evaluated at run time, not a constant value. In Python source code, an f-string is a literal string, prefixed with f, which contains expressions inside braces. The expressions are replaced with their values.” (Source)

在运行时,大括号内的表达式将在其自己的作用域中进行求值,然后将其与其余字符串组合在一起。

以下是性能测试:

% % timeit
name = "Eric"
age = 74
'%s is %s.' % (name, age)

227 ns ± 4.81 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
% % timeit
name = "Eric"
age = 74
'{} is {}.'.format(name, age)

278 ns ± 3.37 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
% % timeit
name = "Eric"
age = 74
'{name} is {age}.'

17.7 ns ± 0.0882 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)

如您所见, f-string, %-formatting 和 str.format()中 f-string 是最快的

参考链接

(排名不分先后)

官方文档 docs.python.org

Python 格式化字符串 f-string f"{}{}{}"详细介绍

python3 f-string 格式化字符串的高级用法

python 中的 fstring 的 !r,!a,!s

陈斌教授关于 f-string 的语法知识

made by leo wang

date: 2022/12/30

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值