本文出自“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/pe…
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