Python格式化字符串

时间:2022-06-22 18:35:22

    Python格式化字符串的方式                            

方法一(%)

  % 格式化方法从 Python 刚开始的时候就存在了,堪称「一届元老」,但是 Python 官方文档中并不推荐这种格式化方式:这里描述的格式化操作容易表现出各种问题导致许多常见错误(例如无法正确显示元组和字典)。使用较新的格式化字符串文字或str.format()可以有助于避免这些错误这些替代方案还提供了更强大,灵活和可打展的格式化文本方法。

# 格式的字符串与被格式化的字符串必须一一对应,需格式化的字符串多时,容易搞混
print('hello %s, you sex is %s.' %('tab', 'boy'))
# hello tab, you sex is boy.
print('hello %s, you sex is %s.' %('boy', 'tab'))
# hello boy, you sex is tab.
# 通过字典方式格式化,哪个字符将会格式化到哪里,清晰命了
print('hello %(name)s, you sex is %(sex)s.' %{'name': 'tab', 'sex': 'boy'})
# hello tab, you sex is boy.

args = {'name': 'tab', 'sex': 'boy'}
print('hello %(name)s, you sex is %(sex)s.' %(args))
# hello tab, you sex is boy.

方法二 (.format)

  方式一:使用位置参数

In [62]: print('My name is {} ,age{}'.format('张亚飞',23))
My name is 张亚飞 ,age23

In [63]: print('My name is {0} ,age{1}'.format('张亚飞',23))
My name is 张亚飞 ,age23

 方式二:用字典方式格式化时,指定格式化字符时的位置可以调换

print('hello {name}, you sex is {sex}.'.format(sex='boy', name='tab'))
# hello tab, you sex is boy.
# '**'起到解包的作用 
args = {'name': 'tab', 'sex': 'boy'}
print('hello {name}, you sex is {sex}.'.format(**args))

方式三:填充与格式化

[填充字符][对齐方式 <^>][宽度]

In [70]: print('{0:*<10}'.format('张亚飞'))
张亚飞*******

In [71]: print('{0:*>10}'.format('张亚飞'))
*******张亚飞

In [72]: print('{0:*^10}'.format('张亚飞'))
***张亚飞****

方式四:精度与进制

In [74]: print('{0:.2f}'.format(1232132.12321))  #精确到小数点后两位
1232132.12

In [75]: print('{0:b}'.format(10))  #二进制
1010

In [76]: print('{0:o}'.format(10))  #十进制
12

In [77]: print('{0:x}'.format(10))   #十六进制
a

In [78]: print('{0:,}'.format(123232244324))    #千分位格式化
123,232,244,324

方式五:使用索引

In [80]: l1 =  ['张亚飞',23]

In [85]: l2 = ['hobby','打篮球']

In [86]: print('{0[0]}age is {0[1]},{1[0]}is{1[1]}'.format(l1,l2))
张亚飞age is 23,hobbyis打篮球

相比%格式化的方式, 推荐使用 .format 方法进行格式化字符串,一来清晰明了,二来效率更高(format 是字符串
str 内置的方法)。更多关于 .format 的用法文档,用户可在交互模式下(终端输入 python
# or ipython or bpython ) 输入 help(str.format) 查看

确实,str.format() 比 %格式化高级了一些,但是它还是有自己的缺陷。

在处理多个参数和更长的字符串时仍然可能非常冗长。

方法三 f-Strings

还好,现在我们有了 f-Strings,它可以使得字符串格式化更加容易。

f-string是以f或F开头的字符串, 其中以{}包含的字符串会进行值替换

下面从多个方面看下 f-strings 的使用方法,看完后,我相信你会对「人生苦短,我用 Python」有更深地赞同~

1 f-Strings 使用方法

name = 'ZhangYafei'
age = 24
f'hi, {name}, are you {age}'
Out[219]: 'hi, ZhangYafei, are you 24'
F'hi, {name}, are you {age}'
Out[220]: 'hi, ZhangYafei, are you 24'

因为 f-strings 是在运行时计算的,那么这就意味着你可以在其中放置任意合法的 Python 表达式,比如:

  • 运算表达式
f'{2 ** 3 + 1}'
Out[222]: '9'
  • 调用函数

还可以调用函数:

def test(name):
    return name + ' really'
    
f'{test(name)} is handsome'
Out[231]: 'ZhangYafei really is handsome'

也可以直接调用函数

f'{name.lower()} is handsome'
Out[232]: 'zhangyafei is handsome'

2. 类中使用

class People(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        return f'{self.name} is {self.age}'
    def __repr__(self):
        return f'{self.name} is {self.age}. HAHA!'
    
person = People()
ZYF = People('ZhangYafei', 24)
F'{ZYF}'
Out[236]: 'ZhangYafei is 24'
F'{ZYF!r}'
Out[237]: 'ZhangYafei is 24. HAHA!'
ZYF
Out[238]: ZhangYafei is 24. HAHA!
print(ZYF)
ZhangYafei is 24

3. 多行f-string

name = 'ZhangYafei'
age = 24
status = 'Python'
message = {
f'hi {name}'
f'you are {age}'
f'you are learning {status}'
}
message
Out[245]: {'hi ZhangYafeiyou are 24you are learning Python'}

这里需要注意,每行都要加上 f 前缀,否则格式化会不起作用:  

4 速度对比

其实,f-string 里的 f 也许可以代表 fast,它比 %格式化方法和 str.format() 都要快:

from timeit import timeit


def test_baifenhao():
    name = 'ZhangYafei'
    age = 24
    return '%s is %s.'%(name, age)


def test_format():
    name = 'ZhangYafei'
    age = 24
    return '{} is {}.'.format(name, age)


def test_f_string():
    name = 'ZhangYafei'
    age = 24
    return f'{name} is {age}.'

timeit(test_baifenhao, number=1000000)
Out[265]: 0.7293048258696899
timeit(test_format, number=1000000)
Out[266]: 0.8064396247757486
timeit(test_f_string, number=1000000)
Out[267]: 0.5187802432072317

5 注意事项

5.1 引号的处理

可以在字符串中使用各种引号,只要保证和外部的引号不重复即可。

以下使用方式都是没问题的:

f"{'ZhangYafei'}"
Out[268]: 'ZhangYafei'
f'{"ZhangYafei"}'
Out[269]: 'ZhangYafei'
f"""ZhangYafei"""
Out[270]: 'ZhangYafei'
f'''ZhangYafei'''
Out[271]: 'ZhangYafei'

那如果字符串内部的引号和外部的引号相同时呢?那就需要 进行转义:

f'you are very \'handsome\''
Out[272]: "you are very 'handsome'"

5.2 括号的处理

若字符串中包含括号 {},那么你就需要用双括号包裹它:

f'{{100}}'
Out[273]: '{100}'
f'{{{100}}}'
Out[275]: '{100}'
f'{{{{100}}}}'
Out[274]: '{{100}}'
f'{{{{{100}}}}}'
Out[276]: '{{100}}'
f'{{{{{{100}}}}}}'
Out[277]: '{{{100}}}'

5.3 反斜杠

上面说了,可以用反斜杠进行转义字符,但是不能在 f-string 表达式中使用:

5.4 注释符号

不能在表达式中出现 #,否则会报出异常;

四、Python标准库模板

来看一个例子

from string import Template
t = Template('Hey, $name!')
t.substitute(name=name)
Out[280]: 'Hey, ZhangYafei!'

你可以看到我们需要先从Python的内建 string 模块中导入 Template 类。模板字符串并不是核心的语言特征,但是它们由Python标准库的string提供的。

另外一个不同的地方是这个模板字符串不支持使用格式说明符。所以想要让先前的错误提示信息能够使用,你还需要手动转换这个int 错误号码为十六进制字符串:

templ_string = 'Hey $name, there is a $error error!'
Template(templ_string).substitute(name=name, error=hex(1111))
Out[282]: 'Hey ZhangYafei, there is a 0x457 error!'

顺利运行!

但是该什么时候才在你的代码中使用模板字符串呢?在我看来,使用模板字符串的最佳的时机就是当你的程序需要处理由用户提供的输入内容时。模板字符串是最保险的选择,因为可以降低复杂性。

其他一些复杂的字符串格式化技巧的可能会给你的程序带来安全漏洞

Python字符串格式化经验法则

Python字符串格式化经验法则:如果你的格式化字符串是由用户提供的,那么就是用模板字符串(#4)避免安全问题。不然如果是Python 3.6+的话,就使用字符串插值/f-Strings,如果不是就使用“新式”字符串格式化(str.format)。

总结重点

● 也许感到惊讶,Python在处理字符串格式化时不只有一种方法。

● 每个方法都有其优缺点。你应该根据你的用例来选择合适的方法