$ python -m pyperf timeit -s \ 'k = "foo"; v = "bar"' -- '"%s = %r" % (k, v)' ..................... Mean +- std dev: 187 ns +- 8 ns但是使用 f-string 似乎要快 42%:
$ python -m pyperf timeit -s \ 'k = "foo"; v = "bar"' -- 'f"{k!s} = {v!r}"' ..................... Mean +- std dev: 131 ns +- 9 ns优化性能的手段是将简单的 C 风格的格式化方法转换为 f-string 方法。在 3.11.0 中,只转换了 %s、%r 和 %a 三种,但是目前有一个待合入的 pull request,将会支持:%d、%i、%u、%o、%x、%X、%f、 %e、%g、%F、%E、%G。
$ python -m pyperf timeit -s \ 'k = "foo"; v = "bar"' -- '"%s = %r" % (k, v)' ..................... Mean +- std dev: 100 ns +- 5 ns大约快了 87%!当然,3.11 中其它的优化对此也有影响,比如更快的解释器启动时间。
python -m pyperf timeit -s 'x=10**1000' -- 'x//10' ..................... Mean +- std dev: 1.18 us +- 0.02 us在 Python 3.11 中:
python -m pyperf timeit -s 'x=10**1000' -- 'x//10' ..................... Mean +- std dev: 995 ns +- 15 ns大约快了18%。
$ python -m pyperf timeit -s 'd = [0] * 10000' -- 'sum(d)' ..................... Mean +- std dev: 37.4 us +- 1.1 usPython 3.10:
$ python -m pyperf timeit -s 'd = [0] * 10000' -- 'sum(d)' ..................... Mean +- std dev: 52.7 us +- 1.3 usPython 3.11:
$ python -m pyperf timeit -s 'd = [0] * 10000' -- 'sum(d)' ..................... Mean +- std dev: 39.0 us +- 1.0 usPython3.10 和 3.11 之间的区别在于,通过在 sum 函数的快速加法分支中内联对单个数字 PyLongs 的解包,可以提升在单个数字 PyLongs 上调用 sum 的性能。这样做可以避免在解包时调用 PyLong_AsLongAndOverflow。
$ python -m pyperf timeit -s \ 'x = list(map(float, range(10_000)))' -- '[x.append(i) for i in range(10_000)]' ..................... Mean +- std dev: 605 us +- 20 usPython 3.11 的列表 append:
$ python -m pyperf timeit -s \ 'x = list(map(float, range(10_000)))' -- '[x.append(i) for i in range(10_000)]' ..................... Mean +- std dev: 392 us +- 14 us对于简单的列表推导式,也有一些小的改进:
$ python -m pyperf timeit -s \ '' -- '[x for x in list(map(float, range(10_000)))]' ..................... Mean +- std dev: 553 us +- 19 usPython 3.11:
$ python -m pyperf timeit -s \ '' -- '[x for x in list(map(float, range(10_000)))]' ..................... Mean +- std dev: 516 us +- 16 us译注:记得在 3.9 版本的时候,Python 优化了调用 list()、dict() 和 range() 等内置类型的速度,在不起眼处,竟还能持续优化!
>>> sys.getsizeof(dict(foo="bar", bar="foo")) 232在 Python 3.11 中:
>>> sys.getsizeof(dict(foo="bar", bar="foo")) 184(译注:插个题外话,Python 的 getsizeof 是一种“浅计算”,这篇《Python在计算内存时应该注意的问题?》区分了“深浅计算”,可以让你对 Python 计算内存有更深的理解。)
$ python -m pyperf timeit -s \ 'import math' -- 'math.comb(100, 55)' ..................... Mean +- std dev: 3.72 us +- 0.07 us # --- $ python -m pyperf timeit -s \ 'import math' -- 'math.comb(10000, 5500)' ..................... Mean +- std dev: 11.9 ms +- 0.1 msPython 3.11:
$ python -m pyperf timeit -s \ 'import math' -- 'math.comb(100, 55)' ..................... Mean +- std dev: 476 ns +- 20 ns # --- $ python -m pyperf timeit -s \ 'import math' -- 'math.comb(10000, 5500)' ..................... Mean +- std dev: 2.28 ms +- 0.10 ms8.对于 statistics 库:优化了 mean(data)、variance(data, xbar=None) 与 stdev(data, xbar=None)
Python 3.10:
# Mean $ python -m pyperf timeit -s \ 'import statistics' -- 'statistics.mean(range(1_000))' ..................... Mean +- std dev: 255 us +- 11 us # Variance $ python -m pyperf timeit -s \ 'import statistics' -- 'statistics.variance((x * 0.1 for x in range(0, 10)))' ..................... Mean +- std dev: 77.0 us +- 2.9 us # Sample standard deviation (stdev) $ python -m pyperf timeit -s \ 'import statistics' -- 'statistics.stdev((x * 0.1 for x in range(0, 10)))' ..................... Mean +- std dev: 78.0 us +- 2.2 us
# Mean $ python -m pyperf timeit -s \ 'import statistics' -- 'statistics.mean(range(1_000))' ..................... Mean +- std dev: 193 us +- 7 us # Variance $ python -m pyperf timeit -s \ 'import statistics' -- 'statistics.variance((x * 0.1 for x in range(0, 10)))' ..................... Mean +- std dev: 56.1 us +- 2.3 us # Sample standard deviation (stdev) $ python -m pyperf timeit -s \ 'import statistics' -- 'statistics.stdev((x * 0.1 for x in range(0, 10)))' ..................... Mean +- std dev: 59.4 us +- 2.6 us9.纯 ASCII 字符串的 unicodedata.normalize(),提升到常数时间
$ python -m pyperf timeit -s \ 'import unicodedata' -- 'unicodedata.normalize("NFC", "python")' ..................... Mean +- std dev: 83.3 ns +- 4.3 nsPython 3.11:
$ python -m pyperf timeit -s \ 'import unicodedata' -- 'unicodedata.normalize("NFC", "python")' ..................... Mean +- std dev: 34.2 ns +- 1.2 ns最后的话: