Python 的 f-string 可以连接字符串与数字的原因解析


Posted in Python onFebruary 20, 2021

本文出自“Python为什么”系列,归档在 Github 上:https://github.com/chinesehuazhou/python-whydo

毫无疑问,Python 是一门强类型语言。强类型语言。强类型语言!(关于强弱类型话题,推荐阅读这篇 技术科普文)

这就意味着,不同类型的对象通常需要先做显式地类型转化, 然后才能进行某些操作。

下面以字符串和数字为例,看看强行操作会产生什么结果:

>>> "Python猫" + 666
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

它报类型错误了(TypeError),说字符串只能连接(concatenate)字符串,不能连接 int 类型。 这正是强类型语言的基本约束。

但是,如果我们先把数字“转化”成字符串类型,再执行“+”操作,就不会报错了:

>>> "Python猫" + str(666)
'Python猫666'

上面的这个例子,对读者们来说,应该并不难理解。

由此,我们要引出一个问题:如何在不作显式类型转化的情况下,进行字符串与数字类型的拼接呢?

在《详解Python拼接字符串的七种方式》这篇文章中,它梳理了七种拼接字符串的写法,我们可以逐个来试验一下。

几种字符串拼接方式:

1、格式化类:%、format()、template

2、拼接类:+、()、join()

3、插值类:f-string

为了节省篇幅,此处直接把可以顺利拼接的 4 种写法罗列如下:

>>> "%s %d" % ("Python猫", 666)
'Python猫 666'

>>> from string import Template
>>> s = Template('${s1}${s2}')
>>> s.safe_substitute(s1='Python猫',s2=666)
'Python猫666'

>>> "Python猫{}".format(666)
'Python猫666'

>>> num = 666
>>> f"Python猫{num}"
'Python猫666'

第一种写法(即 % 格式化)来自古老的 C 语言,其中的“%d”是一个占位符,表示它将要接收一个整数,并格式化成字符串。

第二和第三种写法,它们是第一种写法的升级版,不同的是,它们的占位符是通用型的,不必指定“%s”、“%d”等等明确的类型。这两种写法中,数字类型的参数被传给特定的格式化方法(即 safe_substitute 与 format),在这些方法的内部,它们会作类型转化处理。

可以说,上述三种写法都不难理解,它们的意图都有迹可循。

但是,现在再看看最后一种写法,也就是 f-string 写法,似乎就不是那么明显了。

首先,在字符串内部,它并没有像“%格式化”那样指定占位符的类型;其次,所要拼接的数字并没有作为任何函数的参数来传递。

也就是说,在明面上根本看不出任何要作类型转化的意图。但是,由于我们已知 Python 是强类型语言,已知数字类型绝对不可能直接拼接到字符串里,因此,只能说明 f-string 语法在底层作了某种类型转化的操作!

那么,我们就可以再提出一个新的问题:f-string 语法在处理字符串与数字时,是如何实现数字的类型转化的呢?

也许有的读者会猜想它是调用了内置的 str() 或 repr()(或它们对应的魔术方法__str__() 与 __repr__()),从而实现类型转化,但是,答案并没有如此简单!

f-string 语法是在 Python 3.6 版本引入的。为了省事,我们直接找到 PEP-498 文档,在里面查阅看是否有关于实现原理的线索。

Python 的 f-string 可以连接字符串与数字的原因解析

文档地址:https://www.python.org/dev/peps/pep-0498

PEP 里提到,f-string 的语法格式是这样的:

f'<text> { <expression> <optional !s, !r, or !a> <optional : format specifier> } <text> ...'

其中,花括号里的内容就是要作格式化的内容,除去可选的“optional”部分后,“expression”部分就是真正要处理的内容。对应前文的例子,数字 666 就是一个 expression。

expression 会按 __format__ 协议进行格式化,但是并不会直接调用 __format__() 这个方法。

文档上指出,实际的执行过程等效于type(value).__format__(value, format_spec) 或者 format(value, format_spec)

事实上,字符串对象的 foramt() 方法跟 Python 内置的 foramt() 函数,它们都会调用__format__() 魔术方法,所以,f-string 其实是前文中 format() 格式化写法的升级版。

在默认情况下,format_spec 是一个空字符串,而format(value, "") 的效果等同于str(value) ,因此,在不指定其它 format_spec 的情况下,可以简单地认为 f-string 就是调用了 str() 来作的类型转化……

至此,我们看到了 f-string 的实现原理,明白了它在拼接字符串与数字时,效果等效于前文的 format() 格式化方法,也等效于使用 str() 进行类型转化。

写在最后:本文属于“Python为什么”系列(Python猫出品),该系列主要关注 Python 的语法、设计和发展等话题,以一个个“为什么”式的问题为切入点,试着展现 Python 的迷人魅力。更多精彩文章,请移步 Github 查看,项目地址:https://github.com/chinesehuazhou/python-whydo

到此这篇关于Python 的 f-string 可以连接字符串与数字的原因解析的文章就介绍到这了,更多相关Python f-string 连接字符串与数字内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python实现探测socket和web服务示例
Mar 28 Python
Python的Socket编程过程中实现UDP端口复用的实例分享
Mar 19 Python
在CentOS上配置Nginx+Gunicorn+Python+Flask环境的教程
Jun 07 Python
Python数据结构与算法之常见的分配排序法示例【桶排序与基数排序】
Dec 15 Python
Django中的CBV和FBV示例介绍
Feb 25 Python
python增加矩阵维度的实例讲解
Apr 04 Python
基于python批量处理dat文件及科学计算方法详解
May 08 Python
Django实现登录随机验证码的示例代码
Jun 20 Python
Python学习笔记基本数据结构之序列类型list tuple range用法分析
Jun 08 Python
Python手绘可视化工具cutecharts使用实例
Dec 05 Python
Python双链表原理与实现方法详解
Feb 22 Python
python的链表基础知识点
Sep 13 Python
安装不同版本的tensorflow与models方法实现
Feb 20 #Python
python爬虫scrapy基本使用超详细教程
Feb 20 #Python
解决pip安装tensorflow中出现的no module named tensorflow.python 问题方法
Feb 20 #Python
conda安装tensorflow和conda常用命令小结
Feb 20 #Python
TensorFlow低版本代码自动升级为1.0版本
Feb 20 #Python
python爬虫scrapy基于CrawlSpider类的全站数据爬取示例解析
Feb 20 #Python
TensorFlow的环境配置与安装方法
Feb 20 #Python
You might like
PHP之变量、常量学习笔记
2008/03/27 PHP
yii2.0整合阿里云oss的示例代码
2017/09/19 PHP
为Yahoo! UI Extensions Grid增加内置的可编辑器
2007/03/10 Javascript
Jquery升级新版本后选择器的语法问题
2010/06/02 Javascript
js控制的遮罩层实例介绍
2013/05/29 Javascript
js 上下左右键控制焦点(示例代码)
2013/12/14 Javascript
JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)
2014/08/16 Javascript
AngularJS入门教程(一):静态模板
2014/12/06 Javascript
JavaScript必知必会(三) String .的方法来自何方
2016/06/08 Javascript
Bootstrap Metronic完全响应式管理模板之菜单栏学习笔记
2016/07/08 Javascript
jQuery+HTML5+CSS3制作支持响应式布局时间轴插件
2016/08/10 Javascript
JavaScript SHA512加密算法详细代码
2016/10/06 Javascript
JS公共小方法之判断对象是否为domElement的实例
2016/11/25 Javascript
浅谈Angular.js中使用$watch监听模型变化
2017/01/10 Javascript
Node.js使用Express创建Web项目详细教程
2017/03/31 Javascript
详解用vue.js和laravel实现微信授权登陆
2017/06/23 Javascript
关于react-router的几种配置方式详解
2017/07/24 Javascript
浅谈Vue 初始化性能优化
2017/08/31 Javascript
vuex页面刷新后数据丢失的方法
2019/01/17 Javascript
python通过邮件服务器端口发送邮件的方法
2015/04/30 Python
Python编写生成验证码的脚本的教程
2015/05/04 Python
Python 多线程抓取图片效率对比
2016/02/27 Python
在Pandas中处理NaN值的方法
2019/06/25 Python
Python如何使用bokeh包和geojson数据绘制地图
2020/03/21 Python
在pycharm创建scrapy项目的实现步骤
2020/12/01 Python
Python字节单位转换(将字节转换为K M G T)
2021/03/02 Python
使用CSS3创建动态菜单效果
2015/07/10 HTML / CSS
Html5如何唤起百度地图App的方法
2019/01/27 HTML / CSS
中国制造网:Made-in-China.com
2019/10/25 全球购物
M.M.LaFleur官网:美国职业女装品牌
2020/10/27 全球购物
在浏览器端如何得到服务器端响应的XML数据
2012/11/24 面试题
退休感言
2014/01/28 职场文书
计算机维护专业推荐信
2014/02/27 职场文书
气象学专业个人求职信
2014/03/15 职场文书
家长寄语大全
2014/04/02 职场文书
SQL Server2019安装的详细步骤实战记录(亲测可用)
2022/06/10 SQL Server