Python 的 f-string 可以连接字符串与数字的原因解析
作者:豌豆花下猫 发布时间:2023-08-21 15:34:41
本文出自“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 文档,在里面查阅看是否有关于实现原理的线索。
文档地址: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
来源:https://www.cnblogs.com/pythonista/archive/2021/02/19/14418486.html
猜你喜欢
- 代码如下:<% str = request("str") reg 
- 本文实例讲述了Python实现可获取网易页面所有文本信息的网易网络爬虫功能。分享给大家供大家参考,具体如下:#coding=utf-8#--
- 什么是1433端口 1433端口,是SQL Server默认的端口,SQL Server服务使用两个端口:TCP-1433、UDP-1434
- 1、引言在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtra
- 设计模式:迭代迭代是一种设计模式,解决有序便利序列的问题。通用的可迭代对象需要支持done和next方法。伪代码如下:while not i
- 本文介绍了SpringBoot 中使用JSP的方法示例,分享给大家,具体如下:依赖: <parent>
- 翻译整理:Young.J;官方网站:http://jquery.comjQuery是一款同prototype一样优秀js开发库类,特别是对c
- HTTPX是Python3的功能齐全的HTTP客户端,它提供同步和异步API,并支持HTTP/1.1和HTTP/2安装pip install
- 查询效率分析:子查询为确保消除重复值,必须为外部查询的每个结果都处理嵌套查询。在这种情况下可以考虑用联接查询来取代。如果要用子查询,那就用E
- 本文实例讲述了Python有序字典简单实现方法。分享给大家供大家参考,具体如下:代码:# -*- coding: UTF-8 -*-impo
- 这里是一个基于GMap2和XML的小例子,数据存在XML文件中 ,这是最简单的模式,却相当地有用。实例的网址是: http://sunjia
- 前言哈希 又称作 “散列”,它接收任何一组任意长度的输入信息,通过 哈希 算法变换成固定长度的数据指
- 内码问题.用这段代码的吧,我已经改得很精简了.使用XMLHTTP抓取地址并进次内容处理Function GetBody(Url) Dim o
- 前言一些公司内部的CMS系统存在某些内容让指定的用户有权限访问,这时候可以用django自带的权限管理进行限制,比较方便。缺点:django
- 保护你的ASP页面的两种办法 有时候你只想让人们从你的站点来访问你的某些页面, 而不允许他们从其它站点的非法链接中到达这些页面。在你想保护的
- python将字典内容写入json文件的方法:我们可以先使用json.dumps()函数将字典转换为字符串;然后再将内容写入json即可。j
- 一、心知天气API密钥获取首先,访问https://www.seniverse.com,进行登录或者注册操作,然后在控制台上创建一个免费版的
- 阅读上一篇:微软建议的ASP性能优化28条守则(2) 技巧 5:不要将数据库连接缓存在 Application 或 Session 对象中
- 我们这里试输出一段字符:<%response.write Server.UrlEncode("织梦幻影")%>
- 又有人说设session.timeout=99999。这种同样不行,session有最大时间限制。我经过测试发现最大值为24小时,也就是说你