目录

一、绪论

二、% 

2.1 示例

2.2 速查表

三、format 

3.1 示例

3.2 速查表 (数字格式化)

四、f-string

4.1 说明

4.2 示例


一、绪论

随着 Python 的更新,其 字符串格式化 功能也在不断地优化。在 Python 2.6 以前,% 操作符一枝独秀;在 Python 2.6 之后,迎来后起之秀format 操作符;在 Python 3.6 之际,更有 f-string 操作符异军突起。字符串格式化的逐步优化,不但简化了操作,而且提升了效率,如下执行时间对比柱状图所示:

用python实现stft python stratify_python

可见,“远古时期” 的模板字符串 str.Template 过于低效,str.format 和 % 操作符在简便和效率之间有所权衡,而 f-string则具有 最佳性能。以下将逐一回顾:


二、% 

2.1 示例

作为最古老格式化字符串方式,% 操作符与 C 中 sprintf 函数的语法基本相同,因而具有浓浓的 C 风味,使得最终的表达式可能较为复杂和冗长。关于 % 操作符的用法一言以蔽之 —— 在目标字符串中指定位置插入待填充内容的类型符号。例如:

>>> "%s is %d years old." % ('Zhang San', 18)  # 直接使用
'Zhang San is 18 years old.'
# -------------------------------------------------------------------------
>>> name = 'Zhang San'
>>> age = 18
>>> "%s is %d years old." % (name, age)  # 间接使用
'Zhang San is 18 years old.'

2.2 速查表

常用类型符号及其说明

符号

说明

%s

格式化字符串

%c

格式化字符及其 ASCII 码

%d

格式化整数

%u

格式化无符号整型

%o

格式化无符号八进制数

%x

格式化无符号十六进制数

%X

格式化无符号十六进制数 (大写)

%f

格式化浮点数,可指定小数点后的精度

%e

格式化浮点数 (科学计数法)

%E

同 %e

%g

%f 和 %e 的简写

%G

%F 和 %E 的简写

%p

用十六进制数格式化变量的地址

辅助指令

符号

说明

*

定义宽度或小数点精度

-

用于左对齐

+

正数前显示加号 '+'

<sp>

正数前显示空格

#

八进制数前显示零 '0'、十六进制数前显示 '0x' 或 '0X'

0

显示的数字前面填充'0'而不是默认的空格

%

'%%' 输出一个 '%' (百分号转义)

(var)

映射变量 (字典参数)

m.n.

m 是显示的最小总宽度,n 是小数点后的保留位数

常用转义字符

用python实现stft python stratify_Python_02


三、format 

3.1 示例

相比于 % 操作符,str.format()

>>> "{} is {} years old.".format('Li Hua', 3)  # 不指定位置索引, 默认排列
'Li Hua is 3 years old.'
# -------------------------------------------------------------------------
>>> "{0} is {1} years old.".format('Li Hua', 3)  # 指定位置索引
'Li Hua is 3 years old.'
# -------------------------------------------------------------------------
>>> "{0} is {1}{1} years old.".format('Li Hua', 3)  # 指定位置索引, 多次使用
'Li Hua is 33 years old.'

还可以对 str.format() 设定参数:(其中使用 * ** 解包的原理详见文章 单/双星号操作符)

>>> "宿舍楼:{building}, 门牌号:{number}".format(building="鹏翔2斋", number=1234)
'宿舍楼:鹏翔2斋, 门牌号:1234'
# -------------------------------------------------------------------------
>>> info = {"building":"鹏翔2斋", "number":1234}
>>> "宿舍楼:{building}, 门牌号:{number}".format(**info)  # 使用 ** 对 dict 解包
'宿舍楼:鹏翔2斋, 门牌号:1234'
# -------------------------------------------------------------------------
>>> info2 = ("鹏翔2斋", 1234)
>>> "宿舍楼:{}, 门牌号:{}".format(*info)  # 使用 * 对 tuple 解包
'宿舍楼:鹏翔2斋, 门牌号:1234'
# -------------------------------------------------------------------------
>>> info3 = ["鹏翔2斋", 1234]
>>> "宿舍楼:{0[0]}, 门牌号:{0[1]}".format(info3)  # 使用 index 指定 list 元素
'宿舍楼:鹏翔2斋, 门牌号:1234'

甚至可以向 str.format() 传入对象:

>>> class Num:
	def __init__(self, num):
		self.num = num

>>> six = Num(6)
>>> "my number is {0.num}".format(six)  # 调用成员属性作为参数
'my number is 6'

以上实例足以说明 str.format() 的灵活与强大!

3.2 速查表 (数字格式化)

常见用法示例及其说明

示例

格式

结果

说明

3.1415

{:.2f}

3.14

保留小数点后2位

2.7182

{:+.2f}

+2.71

带符号保留小数点后2位

-1

{:+.2f}

-1.00

带符号保留小数点后2位

1.2345

{:.0f}

1

删去小数部分

8

{:x>2d}

08

整数补x (填充左边, 宽度为2)

16

{:y<4d}

16xx

整数补y (填充右边, 宽度为4)

1000000

{:,}

1,000,000

, 作千分位分隔符

1000000

{:_}

1_000_000

_ 作千分位分隔符

0.48

{:.4%}

48.0000%

小数转百分比

100000000

{:.2e}

1.00e+08

指数记法

16

{:>8d}

      16

向右对齐 (宽度为8)

16

{:<8d}

16      

向左对齐 (宽度为8)

16

{:^8d}

   16    

居中对齐 (宽度为8)

进制转换:(# 符号用于切换数字显示,可获取各进制的带前缀大、小写表示)

示例

格式

结果

说明

12

{:#b}

0b1100

带前缀 二进制小写表示

12

{:b}

1100

二进制表示

12

{:o}

14

八进制表示

12

{:d}

12

十进制表示

12

{:x}

c

十六进制表示

12

{:#X}

0XC

带前缀 十六进制大写表示

事实上,str.format() 的用法远比上述示例复杂多样,详见官方文档:格式字符串语法


四、f-string

4.1 说明

相较于前两种方法,Python 3.6 中的 f-string (格式化字符串常量 formatted string literals),应为最佳形式 —— 简洁易读,不仅有助于简化十分繁琐的写法,而且具有 最佳效率,非常建议使用。与具有恒定值的其它字符串常量不同,格式化字符串实际上是运行时运算求值的表达式。

f-string 的语法结构为:

f ' <text> { <expression> <optional !s, !r, or !a> <optional : format specifier> } <text> ... '

其中,f (或 F) 为目标字符串前缀;<text> 表示占位符的上下文;类似于 str.format,目标字符串中的占位符 (一种运行时计算的表达式) 也使用了花括号 { },在其中必须加入表达式 <expression>,可选参数标志 !s 表示调用表达式上 str() (默认)、!r 表示调用表达式的 repr()、!a 表示调用表达式的 ascii()。最后,使用 format 协议格式化目标字符串。

4.2 示例

其常用方法是在目标字符串前加上字母 f 或 F,然后在目标字符串中插入占位符(直接在 { } 中加入变量)。例如:

>>> name = 'Bob'
>>> age = 24
>>> f"{name} is {age} years old."  # 格式字符串前缀 f 或 F, 中间插入占位符 {variable}
'Bob is 24 years old.'

其实,花括号 { } 中可以灵活地填入 各种表达式,甚至可以 调用函数与类成员 等,而不仅仅局限于变量,例如:

>>> f"The result of the function is {2 * 3 + 4}"  # 算术表达式 内联运算
'The result of the function is 9.43656365691809'
# ----------------------------------------------------------------------------
>>> f'My weapen is {weapen.upper()}'  # 函数/方法调用
'My weapen is AK47'
# ----------------------------------------------------------------------------
>>> import math
>>> f"The result of the function is {2 * math.e + 4}"  # 类成员(属性/方法)调用
'The result of the function is 9.43656365691809'

当然,除了内置函数和自定义普通函数,lambda 表达式 (匿名函数) 也可以填入 { },但为避免 lambda 表达式的分号 : 带来的歧义,应将 lambda 表达式置于圆括号 ( ) 中,例如:

>>> f'The test result is {lambda x: x + 1 (99)}'  # 无法解析 End-of-File
SyntaxError: unexpected EOF while parsing
# ----------------------------------------------------------------------------
>>> f'The test result is {(lambda x: x + 1)(99)}'  # 格式:{(lambda表达式)(lambda表达式参数)}
'The test result is 100'

为避免引号冲突,可以灵活使用 单引号 ' 、双引号 '' 、单引号文本字符串 ' ' '、双引号文本字符串 '' '' '' 来解决,只需 保证 目标字符串外定界符的引号 与 目标字符串中 占位符内的引号 不同。例如:

>>> f"We are {"CT"}"  # 内外均使用了双引号 ""
SyntaxError: invalid syntax  
# ----------------------------------------------------------------------------
>>> f"We are {'CT'}"  # 内用单引号 '' 外用双引号 ""
'We are CT'
# ----------------------------------------------------------------------------
>>> f'''We are {'CT'} and you are {"T"} '''  # 内用单双 外用三
'We are CT and you are T '

# 不论怎么搭配, 只要内外不冲突即可

但注意,占位符 { } 内不能使用转义符号 \ 对引号转义 (因为不允许出现 \,除非用变量间接传递),而上下文可以:

>>> f'I think {you\'re powerful}'  # {} 内不可使用转义符号 \
SyntaxError: f-string expression part cannot include a backslash
# ----------------------------------------------------------------------------
>>> f'You\'re powerful'  # {} 外则可同正常字符串一样使用转义符号 \
"You're powerful"
# ----------------------------------------------------------------------------
>>> words = "you\'re powerful"  # 除非用变量传递
>>> f'I think {words}'
"I think you're powerful"

此外,更多技术细节详见 官方文档。由于 f-string 是基于 str.format 发展而来的, str.format 所用符号同样适用于 f-string (所以可以使用 3.2 节的速查表)。


参考文献

6.1. string — 常见的字符串操作 — Python 3.6.15 文档

Python format 格式化函数 | 菜鸟教程

Python 字符串 | 菜鸟教程

f-string - 简书

Python学习干货—f-string 更酷的格式化字符串 - 知乎

2. Lexical analysis — Python 3.10.4 documentation