总结f-string技巧

Last Updated: 2024-05-10 12:44:29 Friday

-- TOC --

Python从3.6版本开始支持f-string特性,这是一种更加灵活的拼装字符串的方法,关键是它最快!

f-string在表达式出现的上下文进行计算,可以访问所有locals和globals。而str.format的计算上下文,仅限在给str.format接口的输入。f-string在对象格式化表达上,与str.format基本上是一样的!

后续的版本,对f-string的特性还在不断增强,支持范围更广,特别是3.12版本...别太在意那些细枝末节,需要的时候再去抠...

f-string基础

下面是一些self-explaining代码:

>>> a = 'abc'
>>> f"a is \\ {a}"
'a is \\ abc'
>>> fr"a is \\ {a}"
'a is \\\\ abc'
>>> F"a is \\ {a}"
'a is \\ abc'
>>> FR"a is \\ {a}"
'a is \\\\ abc'
>>> f"a is {a*3}"
'a is abcabcabc'
>>> f"{0 if 0 else 1}"
'1'
# f"a is {a # comment}" comments is not allowed 
>>> f = 1.2345
>>> f"{f}"
'1.2345'
>>> f"{f:.2f}"
'1.23'
>>> f"{f:+.2f}"
'+1.23'
>>> f"{f:-.2f}"
'1.23'
>>> f"{f:%}"
'123.450000%'
>>> f"{f:.2%}"
'123.45%'
>>> f"{f:+.2%}"
'+123.45%'
>>> f"{f:-.2%}"
'123.45%'
>>>
>>> g = -3.2567
>>> f"{g:-}"
'-3.2567'
>>> f"{g:-%}"
'-325.670000%'
>>> f"{g:-.3%}"
'-325.670%'
>>> f"{{abc123}}"
'{abc123}'
>>> f"{{abc123"
'{abc123'
>>> f"abc123}}"
'abc123}'
>>> f"ab\"c1\"23"
'ab"c1"23'
>>> f"{{ab\"c1\"23}}"
'{ab"c1"23}'
>>> a = 123456789
>>> f"{a:_}"
'123_456_789'
>>> f"{a:,}"
'123,456,789'
>>> f"{a:e}"
'1.234568e+08'
>>> f"{a:E}"
'1.234568E+08'
>>> f"{a:.2e}"
'1.23e+08'
>>> f"{a:.2E}"
'1.23E+08'

debugging特性

如下:

>>> a = 'abc'
>>> b = 123
>>> f"{a=}"
"a='abc'"
>>> f"{b=}"
'b=123'

这个feature从3.8开始有,被称为f-string的debugging特性。注意,它是空格敏感的:

>>> f'{a =}'
"a ='abc'"
>>> f'{a = }'
"a = 'abc'"
>>> f'{a= }'
"a= 'abc'"
>>> f'{a=    }'
"a=    'abc'"

调用str或repr

>>> class xyz():
...   def __str__(self):
...     return 'str'
...   def __repr__(self):
...     return 'repr'
...
>>> x = xyz()
>>> print(f"{x!s}")  # call __str__
str
>>> print(f"{x!r}")  # call __repr__
repr

!a则是调用ascii()接口。

进制转换

>>> bases = dict(b='bin',o='oct',x='hex',X='HEX',d='decimal')
>>> bases
{'b': 'bin', 'o': 'oct', 'x': 'hex', 'X': 'HEX', 'd': 'decimal'}
>>> for i in range(16):
...   for b,_ in bases.items():
...     print(f"{i:8{b}}", end='')
...   print()
...
       0       0       0       0       0
       1       1       1       1       1
      10       2       2       2       2
      11       3       3       3       3
     100       4       4       4       4
     101       5       5       5       5
     110       6       6       6       6
     111       7       7       7       7
    1000      10       8       8       8
    1001      11       9       9       9
    1010      12       a       A      10
    1011      13       b       B      11
    1100      14       c       C      12
    1101      15       d       D      13
    1110      16       e       E      14
    1111      17       f       F      15

自定义格式

通过对象的__format__魔法接口实现。

>>> class xyz():
...   def __format__(self, spec):
...     if spec == 'v':
...       return 'v'
...     if spec == 'vv':
...       return 'vv'
...
>>> x = xyz()
>>> f"{x:v}"
'v'
>>> f"{x:vv}"
'vv'

估计datetime模块也是用这个方法实现的如下功能:

>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2023, 5, 17, 17, 38, 8, 486180)
>>> f"{now:%Y-%m-%d}"
'2023-05-17'
>>> f"{now:%Y-%m-%d %H:%M:%S}"
'2023-05-17 17:38:08'

总结Python魔法接口

填充和对齐

>>> a = 'abc'
>>> f"{a:>12}"
'         abc'
>>> f"{a:^12}"
'    abc     '
>>> f"{a:<12}"
'abc         '
>>> f"{a:12}"
'abc         '
>>> f"{a:*>12}"
'*********abc'
>>> f"{a:*^12}"
'****abc*****'
>>> f"{a:*<12}"
'abc*********'
# >>> f"{a:*12}"   # wrong spec

nested f-string

>>> num = 123.456
>>> f'{f"{num:.1f}":>10}'
'     123.5'
>>>
>>> num = 123.456789
>>> w = 16
>>> p = 4
>>> f'{f"{num}":{w}.{p}}'
'123.            '
>>> f'{f"{num}":>{w}.{p}}'
'            123.'

f-string最快

使用f-string,不仅是因为其灵活方便,更因为其速度,它是最快的!下面是一个简单的测试:

$ python -m timeit -s 'a="123";b="abc"' -p 'c=a + " " + b'
2000000 loops, best of 5: 113 nsec per loop
$ python -m timeit -s 'a="123";b="abc"' -p 'c="%s %s"%(a,b)'
1000000 loops, best of 5: 201 nsec per loop
$ python -m timeit -s 'a="123";b="abc"' -p 'c="{} {}".format(a,b)'
1000000 loops, best of 5: 273 nsec per loop
$ python -m timeit -s 'a="123";b="abc"' -p 'c="".join((a," ",b))'
2000000 loops, best of 5: 140 nsec per loop

$ python -m timeit -s 'a="123";b="abc"' -p 'c=f"{a} {b}"'
5000000 loops, best of 5: 93.7 nsec per loop

就速度而言,一些常见的字符串拼接场景,没有不使用f-string的道理...

本文链接:https://cs.pynote.net/sf/python/202305171/

-- EOF --

-- MORE --