本文出自“Python 为什么”系列,请查看全副文章
在 Python 猫
的上一篇文章中,咱们比照了两种创立列表的办法,即字面量用法 [] 与内置类型用法 list(),进而剖析出它们在运行速度上的差别。
在剖析为什么 list() 会更慢的时候,文中说到它须要通过名称查找与函数调用两个步骤,那么,这就引出了一个新的问题:list() 不是内置类型么,为什么它不能间接就调用创立列表的逻辑呢?也就是说,为什么解释器必须通过名称查找,能力“意识”到该做什么呢?
其实起因很简略:内置函数 / 内置类型的名称并不是关键字,它们只是解释器内置的一种便捷性能,不便开发者开箱即用而已。
PS:内置函数 built-in function 和内置类型 built-in type 很类似,但 list() 理论是一种内置类型而不是内置函数。我曾对这两种易混同的概念做过辨析,请查看这篇文章。为了不便了解与表述,以下统称为内置函数。
1、内置函数的查找优先级最低
内置函数的名称并不属于关键字,它们是能够被从新赋值的。
比方上面这个例子:
# 失常调用内置函数
list(range(3)) # 后果:[0, 1, 2]
# 定义任意函数,而后赋值给 list
def test(n):
print("Hello World!")
list = test
list(range(3)) # 后果:Hello World!
在这个例子中,咱们将自定义的 test 赋值给了 list,程序并没有报错。这个例子甚至还能够改成间接定义新的同名函数,即 ”def list(): …”。
这阐明了 list 并不是 Python 限定的关键字 / 保留字。
查看官网文档,能够发现 Python 3.9 有 35 个关键字,明细如下:
如果咱们将上例的 test 赋值给任意一个关键字,例如 ”pass=test”,就会报错:SyntaxError: invalid syntax。
由此,咱们能够从这个角度看出内置函数并不是万能的:它们的名称并不像关键字那般巩固不变,尽管它们处在零碎内置作用域里,然而却能够被用户部分作用域的对象所轻松拦挡掉!
因为解释器查找名称的程序是“部分作用域 -> 全局作用域 -> 内置作用域”,因而内置函数其实是处在最低优先级。
对于老手来说,这有肯定的可能会产生意想不到的状况(内置函数有 69 个,要全记住是有难度的)。
那么,为什么 Python 不把所有内置函数的名称都设为不可复写的关键字呢?
一方面起因是它想管制关键字的数量,另一方面可能是想留给用户更多的自在。内置函数只是解释器的举荐实现而已,开发者能够依据须要,实现出与内置函数同名的函数。
不过,这样的场景极少,而且开发者个别会定义成不同名的函数,以 Python 规范库为例,ast
模块有 literal_eval() 函数(对标 eval() 内置函数)、pprint
模块有 pprint() 函数(对标 print() 内置函数)、以及 itertools
模块有 zip_longest() 函数(对标 zip() 内置函数)……
2、内置函数可能不是最快的
因为内置函数的名称并非保留的关键字,以及它处于名称查找的末位程序,所以内置函数有可能不是最快的。
上篇文章展现了 [] 比 list() 快 2~3 倍的事实,其实这还能够推广到 str()、tuple()、set()、dict() 等等内置类型中,都是字面量用法稍稍快于内置类型用法。
对于这些内置类型,当咱们调用 xxx() 时,能够简略了解成正在做类的实例化。在面向对象语言中,类先实例化再应用,这是再失常不过的。
然而,这样的做法有时也显得繁琐。为了方便使用,Python 给一些罕用的内置类型提供了字面量表示法,也就是 ””、[]、()、{} 等等,示意字符串、列表、元组和字典等数据类型。
文档出处:https://docs.python.org/3/reference/lexical_analysis.html#delimiters
一般而言,所有编程语言都必须有一些字面量示意,但根本都局限在数字类型、字符串、布尔类型以及 null 之类的根底类型。
Python 中还减少了几种数据结构类型的字面量,所以是更为不便的,同时这也解释了为什么内置函数可能不是最快的。
一般而言,同样的齐备性能,内置函数总是比咱们自定义的函数要快,因为解释器能够做一些底层的优化,例如 len() 内置函数必定比用户定义的 x.len() 函数快。
有些人据此造成了“内置函数总是更快”的意识误区。
解释器内置函数绝对于用户定义函数,前者靠近于走后门;而字面量表示法绝对于内置函数,前者是在走更快的后门。
也就是说,在有字面量表示法的状况下,某些内置函数 / 内置类型并不是最快的!
小结
诚然,Python 自身并不是万能的,那它的任何语法形成局部(内置函数 / 类型),就更不是万能的了。然而,个别咱们会认为内置函数 / 类型总归是“出人头地”的,是受到诸多非凡虐待的,显得像是“万能的”。
本文从“list() 居然会败给 []”破题,从两个角度揭示了内置函数其实存在着某种有余:内置函数的名称并不是关键字,而内置作用域位于名称查找的最低优先级,因而在调用时,某些内置函数 / 类型的执行速度就显著慢于它们对应的字面量表示法。
本文对上一个“Python 为什么”话题做了延展探讨,一方面空虚了后面的内容,另一方面,也有助于大家了解 Python 的几个根底概念及其实现。
如果你喜爱本文,请点赞反对下吧!另外,我还写了 20+ 篇相似的话题,请关注 Python 猫
查看,并在 Github 上给我一颗小星星吧~~
—>>> 最初是福利时刻:
我把两年写作的 100 多篇精品文章集结成了一本 700 多页的《优雅的 Python》电子书,诚意举荐!!请在微信关注Python 猫
,回复“优雅”两字获取~~