F-strings

在python3.6.2版本中,PEP 498 提出一种新型字符串格式化机制,被称为“字符串插值”或者更常见的一种称呼是F-strings(主要因为这种字符串的第一个字母是f)

简单了解:

①、F-strings提供了一种明确且方便的方式将python表达式嵌入到字符串中来进行格式化:

import math
radius = 10
pi = math.pi
print(f'Circumference of a circle with radius {radius}:{2*pi*radius}') # Circumference of a circle with radius 10:62.83185307179586

②、同样的,在F-strings中我们也可以执行函数:

import math
radius = 10
def area_of_circle(radius):
return 2 * math.pi * radius print(f'Area of a circle with radius {radius}:{area_of_circle(radius=radius)}') # Area of a circle with radius 10:62.83185307179586

③、F-strings的运行速度很快。比%-string和str.format()这两种格式化方法都快得多——这两种是最常用的两种字符串格式化的方式。 

实测F-string大多情况下比%-string要快,但偶尔也不一定(无法解释)

 from timeit import timeit
a = 1
b = 2 print(timeit('''f"{a} + {b} = {a + b}" ''',number=100000,globals=globals()))
print(timeit('''"{} + {} = {}".format(a, b, a + b) ''',number=100000,globals=globals()))
print(timeit('''"%s + %s = %s"%(a, b, a + b) ''',number=100000,globals=globals())) # 0.03593731506849315
# 0.052114410958904116
# 0.0491952511415525

实测对比

对比剖析:

①、为什么F-strings的运行速度这么快?它们是以怎样的形式运行得呢?PEP 498给出了如下的线索:

使用最小的语法,F-strings提供了一种在字符串中嵌入表达式的方法。需要注意的是,F-strings是运行过程中形成的表达式,而不是常数值。在Python源代码中,F-strings是一个以f为前缀,其中包含了表达式的字符串。表达式的结果将显示在其所在的位置上。

重点是F-strings是运行过程中进行计算的表达式,而不是一个常数值。这意味着F-strings和其他python表达式一样都是在运行过程中计算出结果的。CPython编译器在将F-strings解析成字符串和表达式以生成合适的抽象语法树的阶段使性能得到巨大的提升:

我们使用ast模块来查看一个简单的表达式a + b在F-strings之中和之外两种情况下的抽象语法树的情况。可以看到表达式F-strings中的表达式被解析成一个普通的旧式的二进制操作,和单独的表达式 a + b解析成的结果是一样的。甚至在字节码层面我们也可以看到F-strings表达式也像普通表达式那样进行计算。

add_two函数简单的将两个本地变量a和b进行相加并返回结果值。add_two_fstring函数实现的功能类似,但相加的表达式放到f-strings内。在add_two_fstring函数反汇编出的字节码中,FORMAT_VALUE指令(这个指令出现在这里因为毕竟一个F-strings需要将其内部的表达式字符串化),和不使用F-strings的 a + b表达式的结果是一样的。

F-strings的过程主要分为两步:一是把花括号中的表达式计算出来(和普通的Python表达式一样),然后将其结果填充到花括号的位置,并将组合后的字符串作为结果返回。这些步骤不需要额外的运行过程处理。这使得F-strings运行速度更快也更有效率。

②、为何str.format()会比F-strings慢得多呢?当看过其对应的反汇编字节码之后,原因就很明显了。

反汇编得到的字节码中,第一眼就能看到两个字节码指令:LOAD_METHOD和 CALL_METHOD。当我们使用上str.format()时,首先要在全局范围内寻找format函数。这个步骤是通过LOAD_METHOD指令实现的。全局变量查找是一个开销比较大的操作,包括了一系列的步骤(如果比较感兴趣的话,可以看看我之前关于属性查找方面的博文)。一旦format函数被定位到,二进制加操作(BINARY_ADD)将会被唤醒对变量a、b进行相加。最后,通过CALL_METHOD字节码指令调用format函数,然后将格式化后的结果返回。Python中的函数调用具有相当大的开销。当使用str.format()时,消耗在LOAD_METHOD和 CALL_METHOD上额外的时间导致str.format()比F-strings慢的多。

③、那么%-strings 这种格式化方法又是什么原因呢?之前的结果可以看到,它的运行速度介于str.format()和F-strings之间。让我们再一次看一下使用%-strings 格式化方法反汇编后的字节码来寻找一些线索:

一瞬间,我们就发现字节码中并没有LOAD_METHOD和 CALL_METHOD指令——所以 %-string 这种方法避免了全局属性查找和函数调用的开销。这解释了为什么%-strings 要比str.format()快。但为什么%-strings 的运行速度仍然比f-strings要慢呢?在BINARY_MODULO字节码指令上,%-strings 可能会消耗额外的时间。通过分析BINARY_MODULO字节码我并没得出结果,但看了CPython源代码后,我们就可以了解为什么在调用BINARY_MODULO时会产生很小的额外开销。

上图的Python源代码中可以看出,BINARY_MODULO操作是过载的。每次被调用时,它总需要检查运算对象的类型来决定元算对象是否为字符串对象(代码的第7-13行)。如果它们是,然后modulo 执行字符串格式操作。如果不是,它将执行日常的模块(返回第一个参数和第二个参数的余数)。尽管很小,但这种类型检查确实产生了一些额外开销,而F-strings并不存在这些问题。

希望这篇文章能给大家一些启发,帮助大家理解为什么F-strings能从众多字符串格式化方法中脱颖而出。F-strings快速、易学、实用,能有效减少代码量,何不快快用起来!

英文原文:https://ogmcsrgk5.qnssl.com/vcdn/1/优质文章长图/a-closer-look-at-how-python-f-strings-work-f197736b3bdb.png

Python开发【笔记】:探索Python F-strings的更多相关文章

  1. python开发笔记-通过xml快捷获取数据

    今天在做下python开发笔记之如何通过xml快捷获取数据,下面以调取nltk语料库为例: import nltk nltk.download() showing info https://raw.g ...

  2. visual studio 2015 搭建python开发环境,python入门到精通[三]

    在上一篇博客Windows搭建python开发环境,python入门到精通[一]很多园友提到希望使用visual studio 2013/visual studio 2015 python做demo, ...

  3. python开发笔记-python调用webservice接口

    环境描述: 操作系统版本: root@9deba54adab7:/# uname -a Linux 9deba54adab7 --generic #-Ubuntu SMP Thu Dec :: UTC ...

  4. python开发学习-day01 (python安装与版本、字符串、字典、运算符、文件)

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  5. python 学习笔记 9 -- Python强大的自省简析

    1. 什么是自省? 自省就是自我评价.自我反省.自我批评.自我调控和自我教育,是孔子提出的一种自我道德修养的方法.他说:“见贤思齐焉,见不贤而内自省也.”(<论语·里仁>)当然,我们今天不 ...

  6. Python学习笔记之Python的enumerate函数

    Python 的 enumerate() 函数就像是一个神秘的黑箱,你无法简单地用一句话来概括这个函数的作用与用法. enumerate() 函数属于非常有用的高级用法,而对于这一点,很多初学者甚至中 ...

  7. python 学习笔记一——Python安装和IDLE使用

    好吧,一直准备学点啥,前些日子也下好了一些python电子书,但之后又没影了.年龄大了,就是不爱学习了.那就现在开始吧. 安装python 3 Mac OS X会预装python 2,Linux的大多 ...

  8. python学习笔记(一):python简介和入门

    最近重新开始学习python,之前也自学过一段时间python,对python还算有点了解,本次重新认识python,也算当写一个小小的教程.一.什么是python?python是一种面向对象.解释型 ...

  9. python学习笔记:python简介和入门

    编程语言各有千秋.C语言适合开发那些追求运行速度.充分发挥硬件性能的程序.而Python是用来编写应用程序的高级编程语言. Python就为我们提供了非常完善的基础代码库,覆盖了网络.文件.GUI.数 ...

  10. Python开发基础之Python常用的数据类型

    一.Python介绍 Python是一种动态解释型的编程语言.Python它简单易学.功能强大.支持面向对象.函数式编程,可以在Windows.Linux等多种操作系统上使用,同时Python可以在J ...

随机推荐

  1. 转载:30多条mysql数据库优化方法,千万级数据库记录查询轻松解决

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  2. KEGG orthology (KO) 数据库简介

    KEGG, 简称京都基因组百科全书,包含了许多的数据库,对于研究基因功能来说,KEGG orthology 数据库是最基本的一个数据库: KEGG Orthology 简称KO, 对于每个功能已知的基 ...

  3. html中可以自定义属性,,,妈的竟然才知道..

    html中可以自定义属性,,,妈的竟然才知道.. <input userinfo="没见过帅哥呀" />

  4. python改动文件内容,不须要read,write多个动作。

    python  要改动文件内容,经常使用 是先read.后write , 再 rename.非常不爽. 比方:须要 把       yuv_dir ="../HD/"   # &q ...

  5. 第八章 示例代码(MyBatis)

    Sample Code JPetStore 6 is a full web application built on top of MyBatis 3, Spring 3 and Stripes. I ...

  6. ASP.NET中相对路径的使用总结

    如果有一个网站上的图片的路径是这样的: http://localhost:2008/websit1/images/1.jpg websit1表示的是虚拟路径或者是站点 在asp.net中,如果我们在. ...

  7. ftp命令行工具如何 连接 非标准21端口(其他端口)的ftp服务器

    windows: step1:ftp命令进入ftp交互环境 step2:ftp>open ip空格port 然后...

  8. linux下 redis 启动

    启动文件 startredis.sh  : nohup /data/redis/bin/redis-server /data/redis/etc/redis.conf & 关闭文件 stopr ...

  9. Ext3.4--TreeGridDemo

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CategoryProper ...

  10. 用Broadcast Receiver刷新数据(二)

    采用消息发布/订阅的一个很大的优点就是代码的简洁性,并且能够有效地降低消息发布者和订阅者之间的耦合度.举个例子,比如有两个界面,ActivityA和ActivityB,从ActivityA界面跳转到A ...