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使用matplotlib绘图时图例显示问题的解决
Apr 27 Python
Python数据操作方法封装类实例
Jun 23 Python
使用Python写一个贪吃蛇游戏实例代码
Aug 21 Python
python修改list中所有元素类型的三种方法
Apr 09 Python
Python如何发布程序的详细教程
Oct 09 Python
pip安装py_zipkin时提示的SSL问题对应
Dec 29 Python
Python遍历文件夹 处理json文件的方法
Jan 22 Python
详解Python装饰器
Mar 25 Python
python基于socket进行端口转发实现后门隐藏的示例
Jul 25 Python
基于python调用psutil模块过程解析
Dec 20 Python
pandas数据选取:df[] df.loc[] df.iloc[] df.ix[] df.at[] df.iat[]
Apr 24 Python
Python如何实现机器人聊天
Sep 10 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中sql注入漏洞示例 sql注入漏洞修复
2014/01/24 PHP
PHP连接和操作MySQL数据库基础教程
2014/09/29 PHP
javascript 多浏览器 事件大全
2010/03/23 Javascript
jquery中ajax学习笔记一
2011/10/16 Javascript
jQuery $.data()方法使用注意细节
2012/12/31 Javascript
jquery中$.post()方法的简单实例
2014/02/04 Javascript
node.js中的buffer.fill方法使用说明
2014/12/14 Javascript
Angular中的Promise对象($q介绍)
2015/03/03 Javascript
JavaScript三元运算符的多种使用技巧
2015/04/16 Javascript
JS排序方法(sort,bubble,select,insert)代码汇总
2016/01/30 Javascript
Atitit.js的键盘按键事件捆绑and事件调度
2016/04/01 Javascript
原生js的ajax和解决跨域的jsonp(实例讲解)
2017/10/16 Javascript
微信小程序wx:for和wx:for-item的用法详解
2018/04/01 Javascript
jQuery事件模型默认行为执行顺序及trigger()与 triggerHandler()比较实例分析
2020/04/30 jQuery
VUE项目实现主题切换的多种方法
2020/11/26 Vue.js
[00:09]DOTA2全国高校联赛 精彩活动引爆全场
2018/05/30 DOTA
[36:33]完美世界DOTA2联赛循环赛 Matador vs Forest 第一场 11.06
2020/11/06 DOTA
[59:00]DOTA2-DPC中国联赛 正赛 Ehome vs PSG.LGD BO3 第一场 3月7日
2021/03/11 DOTA
python 正则表达式 概述及常用字符
2009/05/04 Python
在python里协程使用同步锁Lock的实例
2019/02/19 Python
pandas修改DataFrame列名的实现方法
2019/02/22 Python
Python numpy数组转置与轴变换
2019/11/15 Python
使用Django清空数据库并重新生成
2020/04/03 Python
python TCP包注入方式
2020/05/05 Python
Django 如何使用日期时间选择器规范用户的时间输入示例代码详解
2020/05/22 Python
Steve Madden官网:美国鞋类品牌
2017/01/29 全球购物
个人职业生涯规划书1500字
2013/12/31 职场文书
小学学雷锋活动总结
2014/04/25 职场文书
教师业务培训方案
2014/05/01 职场文书
房屋过户委托书范本
2014/10/07 职场文书
2014年煤矿工人工作总结
2014/12/08 职场文书
2015年圣诞节活动总结
2015/03/24 职场文书
2015员工年度考核评语
2015/03/25 职场文书
社区党务工作总结2015
2015/05/19 职场文书
python 下划线的多种应用场景总结
2021/05/12 Python
MYSQL 无法识别中文的永久解决方法
2021/06/03 MySQL