暗无天日

=============>DarkSun的个人博客

Python格式化字符串的几种方法

%操作符(已经落伍了)

最原始的方式应该就是用 % 操作符了.

% 操作符可以按位置替换格式化符的值:

name = "earth"
return "hello %s" % name
hello earth

若有超过一个的值要格式化则需要把这些值组成一个元组:

name = "earth"
age = 4600000000
return "%s is %d old" % (name,age)
earth is 4600000000 old

不过 % 也可以按名字进行替换,这个时候 % 后面应该接一个dict:

info = {"name": "earth", "age": 4600000000, "alias": "Gaia"}
return "%(name)s is %(age) old" % info
earth is  42213467000ld

注意到,使用字典格式化时并不要求字典里的元素个数与格式化符的个数一致.

Python支持的格式化符可以在这里看到https://docs.python.org/3/library/stdtypes.html#old-string-formatting

使用字符串的format方法

字符串的format方法也支持按位置和按名字两种方式进行格式化:

按位置进行格式化:

name = "earth"
age = 4600000000
return "{} is {:f} old".format(name,age)
earth is 4600000000.000000 old

其中 {} 表示变量替换的位置.

按名字进行格式化:

name = "earth"
age = 4600000000

return "{name} is {age:f} old".format(age=age,name=name)
earth is 4600000000.000000 old

注意,它的格式化符是在 {} 中加上 :x 的后缀. 关于format方法的格式化符可以参见https://docs.python.org/3/library/string.html#string-formatting

不仅如此,format的 {} 内还能有更复杂的东西:

return "{info[0]} is {info[1]} old".format(info=("earth",4600000000))
earth is 4600000000 old

然而,这可能带来安全方面的隐患:

SECRET = 'this-is-a-secret'
class Error:
    def __init__(self):
        pass
err = Error()
user_input = '{error.__init__.__globals__[SECRET]}'
print(user_input.format(error=err))
this-is-a-secret

模板字符串

Python的标准库中提供了一个 Template 类,可以进行简单的内容替换.

from string import Template
name = "earth"
age = 4600000000
templ = Template("$name is $age old")
return templ.substitute(name=name,age=float(age))
earth is 4600000000.0 old

注意,模板字符串并别有格式化符这种东西,因此要让age以浮点型形式显示需要用float函数先转成浮点型.

使用模板字符串的优点在于比较安全, 比如上面那个format方法的隐患, 改成用模板字符,则会报错

from string import Template
SECRET = 'this-is-a-secret'
class Error:
    def __init__(self):
        pass
err = Error()
user_input = '${error.__init__.__globals__[SECRET]}'
try:
    Template(user_input).substitute(error=err)
except ValueError as e:
    print(e)
Invalid placeholder in string: line 1, col 1

Template的这个特性特别适用于格式化字符串是由外人提供的情况时使用.

Formatted String Literals(Python3.6)

这种格式化字符串的方法是由Python3.6新加入的. 它允许你在字符串内内嵌Python运算式:

a = 11
b = 2
return f'{a} + {b} = {a + b};{a} - {b} = {a - b}'
11 + 2 = 13;11 - 2 = 9

它也同时支持str.format()方法中的那些格式化符,且使用方法也一样:

num = 222
return f'{num} 的16进制表示是 {num:#x}'
222 的16进制表示是 0xde

如何抉择?

有这么多种方法格式化字符串,该如何抉择呢?

Python-String-Formatting 中有一个很好的建议:

python-string-formatting-flowchart.png