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版本...别太在意那些细枝末节,需要的时候再去抠...
下面是一些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
可以和r
组合,大小写都OK,但是不能与b
或u
组合。{}
内是一个表达式(什么是expression?),但不能出现注释>>> 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%'
:
后面是格式spec,f
和%
是格式符号+
显示正负号-
只有负数显示符号,正数不显示符号,这是默认设置>>> 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'
_
,,
,e
,E
都是格式符号如下:
>>> 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'"
>>> 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'
>>> 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
>>> 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,不仅是因为其灵活方便,更因为其速度,它是最快的!下面是一个简单的测试:
$ 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 --