Python是一种活生生的语言-正在不断发展,以跟上时代的步伐。Python软件基金会不仅增加了标准库和参考实现CPython,还为语言本身引入了新的功能和改进。
例如,Python3.8引入了一种新的内联赋值语法(“walrus操作符”),使某些操作更加简洁。另一个新批准的语法改进是模式匹配,它将使编写针对许多可能情况之一求值的代码变得更容易。这两个功能的灵感都来自于它们在其他语言中的存在和实用。
它们只是众多有用特性中的两个,这些特性可以添加到Python中,以使该语言更具表现力、更强大、更适合现代编程世界。我们还能许什么愿呢?下面是另外四个语言特性,它们可以为Python添加一些真正有价值的东西--两个我们可能真的会得到,另外两个可能不会。
Python实际上没有常量值的概念。今天,Python中的常量在很大程度上是惯例问题。使用全大写和蛇形大小写的名称(例如,DO_NOT_RESTART)暗示变量是常量。类似地,intying.Final类型注释向链接器提供不应修改对象的提示,但它不会在运行时强制这样做。
为什么?因为可变性在Python的行为中根深蒂固。当您为变量赋值时(例如,*x=3),您将在本地命名空间*x中创建一个名称,并将其指向系统中整数值为3的对象。Python始终假设名称是可变的-任何名称都可以指向任何对象。这意味着每次使用名称时,Python都会不厌其烦地查找它所指向的对象。这种动态性是Python运行速度比其他一些语言慢的主要原因之一。Python的动态性提供了极大的灵活性和便利性,但它是以运行时性能为代价的。
在Python中使用真正的常量声明的一个好处是在运行时减少了对象查找的频率,从而提高了性能。如果运行时提前知道给定值永远不会更改,则不必查找其绑定。这也可能为进一步的第三方优化提供一条途径,比如从Python应用程序(Cython,Nuitka)生成机器本地代码的系统。
但是,真正的常量将是一个重大更改,并且很可能是向后不兼容的更改。常量是以新语法的方式出现-例如,尚未使用的$符号-还是作为Python现有声明名称方式的扩展,这也将是一个值得商榷的问题。最后,还有一个更大的哲学问题,即在一种活力一直是吸引力很大的语言中,真正的常量是否有意义。
简而言之,我们可能会在Python中看到真正的常量,但这将是一个重大的突破性变化。
在许多语言中,可以编写同一函数的多个版本来处理不同类型的输入。例如,对于从整数、浮点数或其他对象进行转换,to_string()函数可以有不同的实现-但为了方便起见,它们将共享相同的名称。“重载”或“泛型”使编写健壮的软件变得更容易,因为您可以为通用过程编写泛型方法,而不是使用特定于给定类型的方法。
Python确实允许您使用一个函数名来完成多个函数的工作,但不是通过定义一个函数的多个实例。您只能在给定的作用域中定义名称一次,并且一次只能将其绑定到单个对象,因此不能在同一名称下拥有单个函数的多个版本。
Python开发人员通常要做的解决方法是使用诸如jisinstance()或type()之类的内置功能来确定提交给函数的变量类型,然后根据类型采取操作。有时,这涉及到在幕后调度特定类型的函数版本。但是,这种方法使得其他开发人员很难扩展您的函数,除非您不遗余力地使其可扩展-例如,通过分派到类中的方法(可以子类化)。
PEP3124在2007年4月提出了一种修饰函数的机制,以指示它们可能会超载。这项提议被推迟了,而不是被直接拒绝-这意味着这个想法从根本上是正确的,但实施的时机并不合适。可能加快在Python中采用重载的一个因素-或者导致这个想法完全被抛弃-是新提出的模式匹配系统的实现。
理论上,可以在幕后使用模式匹配来处理重载分派。但是,模式匹配也可以作为不使用Python实现泛型的理由,因为它已经提供了一种基于类型签名来分派操作的优雅方法。
因此,有一天我们可能会在Python中实现真正的重载,或者它的优点可能会被其他机制取代。
许多语言编译器采用尾递归优化,在这种情况下,调用自身的函数不会在应用程序中创建新的堆栈框架,因此,如果它们运行太长时间,可能会炸毁堆栈。Python不能做到这一点,事实上,它的创建者一直站出来反对这样做。
一个原因是,Python的大部分从内到外使用迭代,而不是递归函数-生成器、协程等等。在这种情况下,它意味着使用具有循环和堆栈结构的函数,而不是递归机制。循环的每次调用都可以保存到堆栈中以创建新的递归,并在递归完成时从堆栈中弹出。
Python开发人员被鼓励使用这些模式代替递归,因此递归优化的希望似乎很渺茫。这里的可能性很小,因为Python的习惯用法支持其他解决方案。
在语言创建者Guido van Rossum进行了一些抵抗之后,lambdas或匿名函数才进入Python。由于Python lambdas现在已经存在,所以它们是高度受限的:它们只允许您使用单个表达式(本质上是赋值操作中等号右侧的任何表达式)作为函数体。如果您想要完整的语句块,只需将它们拆分并根据它们生成一个实际的函数即可。
原因可以归结为van Rossum所认为的语言设计。正如van Rossum在2006年所写的那样,“我发现任何在表达式中间嵌入基于缩进的块的解决方案都是不可接受的。由于我发现语句分组的替代语法(例如大括号或开始/结束关键字)同样不可接受,这几乎使多行lambda成为一个无法解决的难题。
换句话说,问题不是技术上的,而是缺少多行lambdas的语法来补充现有Python语法的美感。如果不创建特殊情况,可能就没有办法做到这一点,而且出现特殊情况的语言往往会变得令人不快。在出现这样的独角兽之前,我们只能凑合使用单独定义的函数。