# 方式一、%符号
%号格式化字符串的方式从Python诞生之初就已经存在,时至今日,python官方也并未弃用%号。
```python
# 格式的字符串(即%s)与被格式化的字符串(即传入的值)必须按照位置一一对应
print('%s asked %s to do something' % ('egon', 'lili')) # egon asked lili to do something
print('%s asked %s to do something' % ('lili', 'egon')) # lili asked egon to do something
# 可以通过字典方式格式化,打破了位置带来的限制与困扰
print('我的名字是 %(name)s, 我的年龄是 %(age)s.' % {'name': 'egon', 'age': 18})
kwargs={'name': 'egon', 'age': 18}
print('我的名字是 %(name)s, 我的年龄是 %(age)s.' % kwargs)
```
| 转换符 | 说明 |
| ------ | --------------------------------------------- |
| %d, %i | 转换为带符号的十进制整数 |
| %o | 转换为带符号的八进制整数 |
| %x, %X | 转换为带符号的十六进制整数 |
| %e, %E | 转化为科学计数法表示的浮点数(e 小写或E大写) |
| %f, %F | 转化为十进制浮点数 |
| %g, %G | 智能选择使用 %f 或 %e 格式(%F 或 %E 格式) |
| %c | 格式化字符及其 ASCII 码 |
| %r | 使用 repr() 函数将表达式转换为字符串 |
| %s | 使用 str() 函数将表达式转换为字符串 |
## 指定最小输出宽度
```python
n = 1234567
print("n(10):%10d." % n)
print("n(5):%5d." % n)
url = "http://c.biancheng.net/python/"
print("url(35):%35s." % url)
print("url(20):%20s." % url)
```
## 指定对齐方式
默认情况下,print() 输出的数据总是右对齐的。也就是说,当数据不够宽时,数据总是靠右边输出,而在左边补充空格以达到指定的宽度。Python 允许在最小宽度之前增加一个标志来改变对齐方式,`-` 指定左对齐;`+` 指定右对齐; `0` 表示宽度不足时补零。对于整数,指定左对齐时,在右边补 0 是没有效果的,因为这样会改变整数的值。对于小数,以上三个标志可以同时存在。对于字符串,只能使用`-`标志,因为符号对于字符串没有意义,而补 0 会改变字符串的值。
```python
n = 123456
# %09d 表示最小宽度为9,左边补0
print("n(09):%09d" % n)
# %+9d 表示最小宽度为9,带上符号
print("n(+9):%+9d" % n)
f = 140.5
# %-+010f 表示最小宽度为10,左对齐,带上符号
print("f(-+0):%-+010f" % f)
s = "Hello"
# %-10s 表示最小宽度为10,左对齐
print("s(-10):%-10s." % s)
#n(09):000123456
#n(+9): +123456
#f(-+0):+140.500000
#s(-10):Hello
```
## 指定精度
```python
#使用方法
%m.nf
%.nf
f = 3.141592653
# 最小宽度为8,小数点后保留3位
print("%8.3f" % f)
# 最小宽度为8,小数点后保留3位,左边补0
print("%08.3f" % f)
# 最小宽度为8,小数点后保留3位,左边补0,带符号
print("%+08.3f" % f)
```
# 方式二、str.format
## 内置格式码
```python
整数: 'bcdoxXn'
浮点数: 'eEfFgGn%'
字符串: 's'
```
## 使用位置参数
```python
# 按照位置一一对应
print('{} asked {} to do something'.format('egon', 'lili')) # egon asked lili to do something
print('{} asked {} to do something'.format('lili', 'egon')) # lili asked egon to do something
```
## 使用索引
```python
# 使用索引取对应位置的值
print('{0}{0}{1}{0}'.format('x','y')) # xxyx
```
## 使用关键字参数或字典
```python
# 可以通过关键字or字典方式的方式格式化,打破了位置带来的限制与困扰
print('我的名字是 {name}, 我的年龄是 {age}.'.format(age=18, name='egon'))
kwargs = {'name': 'egon', 'age': 18}
print('我的名字是 {name}, 我的年龄是 {age}.'.format(**kwargs)) # 使用**进行解包操作
```
## 填充格式化
```python
# 先取到值,然后在冒号后设定填充格式:[填充字符][对齐方式][宽度]
# *<10:左对齐,总共10个字符,不够的用*号填充
print('{0:*<10}'.format('开始执行')) # 开始执行******
# *>10:右对齐,总共10个字符,不够的用*号填充
print('{0:*>10}'.format('开始执行')) # ******开始执行
# *^10:居中显示,总共10个字符,不够的用*号填充
print('{0:*^10}'.format('开始执行')) # ***开始执行***
```
## 精度与进制格式化
```python
print('{salary:.3f}'.format(salary=1232132.12351)) #精确到小数点后3位,四舍五入,结果为:1232132.124
print('{0:b}'.format(123)) # 转成二进制,结果为:1111011
print('{0:o}'.format(9)) # 转成八进制,结果为:11
print('{0:x}'.format(15)) # 转成十六进制,结果为:f
print('{0:,}'.format(99812939393931)) # 千分位格式化,结果为:99,812,939,393,931
```
## {!r}和{!s}
```python
"value = {0!r}".format(a)
# 等同于
"value = {0}".format(repr(a))
"name: {name!s}".format(name)
# 等同于
"name: {name}".format(str(name))
```
# 方式三、f-Strings
str.format() 比 %格式化高级了一些,但是它还是有自己的缺陷。当需要传入的字符串过多时,仍然会显得非常冗长。自从python3.6版本依赖引入了f-Strings方法。
## 变量填充
```python
name = 'egon'
age = 18
print(f'{name} {age}') # egon 18
print(F'{age} {name}') # 18 egon
```
## 表达式填充
```python
# 可以在{}中放置任意合法的Python表达式,会在运行时计算
# 比如:数学表达式
print(f'{3*3/2}') # 4.5
# 比如:函数的调用
def foo(n):
print('foo say hello')
return n
print(f'{foo(10)}') # 会调用foo(10),然后打印其返回值
# 比如:调用对象的方法
name='EGON'
print(f'{name.lower()}') # egon
```
## 类中使用
```python
>>> class Person(object):
... def __init__(self, name, age):
... self.name = name
... self.age = age
... def __str__(self):
... return f'{self.name}:{self.age}'
... def __repr__(self):
... return f'===>{self.name}:{self.age}<==='
...
>>>
>>> obj=Person('egon',18)
>>> print(obj) # 触发__str__
egon:18
>>> obj # 触发__repr__
===>egon:18<===
```
## 多行填充
```python
# 当格式化字符串过长时,如下列表info
name = 'Egon'
age = 18
gender = 'male'
hobbie1='play'
hobbie2='music'
hobbie3='read'
info = [f'名字:{name}年龄:{age}性别:{gender}',f'第一个爱好:{hobbie1}第二个爱好:{hobbie2}第三个爱好:{hobbie3}']
# 我们可以回车分隔到多行,注意每行前都有一个f
info = [
# 第一个元素
f'名字:{name}'
f'年龄:{age}'
f'性别:{gender}',
# 第二个元素
f'第一个爱好:{hobbie1}'
f'第二个爱好:{hobbie2}'
f'第三个爱好:{hobbie3}'
]
print(info)
# ['名字:Egon年龄:18性别:male', '第一个爱好:play第二个爱好:music第三个爱好:read']
```
# 方式四、标准库模板
从Python 2.4起,Python标准库string引入了Template也可以用来格式化字符串,所以说,与前三种方式的一个显著区别就是:Template并属于python语言的核心语法特征。
```python
from string import Template
name='EGON'
t = Template('Hello $name!')
res=t.substitute(name=name)
print(res) # Hello EGON!
#这个模板字符串不支持类似str.format那样的进制转换,需要我们自己处理
templ_string = 'Hello $name, there is a $error error!!!'
res=Template(templ_string).substitute(name=name, error=hex(12345))
print(res) # Hello EGON, there is a 0x3039 error!!!
```
# 对比总结
1、如果格式化的字符串是由用户输入的,那么基于安全性考虑,推荐使用Template。
2、如果使用的python3.6+版本的解释器,推荐使用f-Stings。
3、如果要兼容python2.x版本的python解释器,推荐使用str.format。
4、如果不是测试的代码,不推荐使用%。