作者
天元浪子
头图
CSDN下载自东方IC
出品
CSDN博客
国庆长假期间,Python3.9正式推出,各大IT平台和众多自媒体纷纷火力全开,热推Python3.9的新增特性。然而,除了媒体的自娱自乐,几乎所有的程序员都对此表示无感。我甚至觉得,每一次的版本升级都是在抬升Python的学习门槛,令初学者望而生畏。
简单和优雅,是Python创始人吉多·范罗苏姆(龟叔)开立山门之时为Python确立的哲学理念。现在,Pyton的发展显然已经背离了这一原则:不管有用无用,但凡别家有的,一概收入;不管是否适合,只要能充门面,悉数拿来。此情势正如当年Pandas之父韦斯·麦金尼面对Pandas的快速扩张时所表达出的无奈:“Pandas正在背离我最初所期望的简洁和易用,变得越来越臃肿和不可控制。”
曾经,我非常地喜欢Python。今天,这份爱依然在,但多了一些冷静和理性。十几年的陪伴,从默默无闻到炙手可热,Python终于在软件排行榜上占据了显耀的位置。在席卷软件行业的扩张风暴中,在Python连续不断地版本升级中,我却分明看到了一种危险的转变:Python正在从简明转向臃肿,从实用转向媚俗。
忍了很久,今日得闲,吐槽一下Python的新增语言特性。以下总结了导致Python危险转向的十大槽点,排名不分先后。
媚俗的静态类型检查
大约从Py3.5开始,直至最新的Py3.9,感觉Python语言项目团队就在做一件事儿:静态类型检查。为了实现类型检查,他们推出了typing模块,定义了一大堆的应用规则。相应的,有一批静态类型检查工具应运而生,比如Mypy、Pylint或者Pyflakes,PyCharm也可以很好的集成这些工具。对此,我只想说一句:Python是动态语言吧?既然是动态语言,那你检查个毛线?即便检查通过,就能像编译语言那样运行了?一切不过是虚幻的假象而已,请别用其他语言的理念戕害质朴的Python。Python追求的是用最简捷的方式解决问题,而不是制造麻烦,然后再解决麻烦。Python强推静态类型检查,不过是迎合那些集成开发工具(IDE),同时满足不明就里的程序员的成就感和虚荣心罢了。
画蛇添足的变量类型声明
当一个拥有5年工作经验的Python程序员读到下面的代码时,会有什么样的感受呢?
name:strage:int=18gilrfriends:list=[奥黛丽·赫本,卡米拉·贝勒,安吉丽娜·朱莉]
相信他一定会说,天哪,这是什么?是Python吗?没错,这的确是Python。看起来像是指定了变量的类型,但即使像下面这样用字符串给被指定为列表类型的变量赋值,运行时也不会发出任何的提示或警告。
gilrfriends:list=奥黛丽·赫本,卡米拉·贝勒,安吉丽娜·朱莉#打着右转灯左转gilrfriends奥黛丽·赫本,卡米拉·贝勒,安吉丽娜·朱莉
你看,打着右转灯左转,照样通行无误。这样画蛇添足的操作有什么用呢?原来仅仅是为了让IED或者类型检查工具知道变量的类型。工具原本是为程序员服务的,现在好了,你得先为工具服务。差评!
鸡肋般的函数及参数的类型注解
我一直在寻找一种可以限定函数参数类型的方法,以避免程序运行时出现意外的情况。受限于Python的机制,大多数情况下我只能使用断言(assert)在函数内部对参数类型作出限制,同时尽可能在__doc__中对参数类型及含义作详尽描述,就像下面的代码一样。
defsphere(center,radius,color,slices=90):绘制球体center-球心坐标,长度为3的元组或列表radius-半径,浮点型color-顶点颜色,字符串slices-球面分片数(数值越大越精细),整型assertisinstance(center,(tuple,list))andlen(center)==3,期望参数center是长度为3的元组或列表print(Hello)returnTrue
现在,如果按照Python指导委员会所倡导的方式,上面的代码应该写成如下的样式。
fromtypingimportUniondefsphere(center:Union[tuple,list],radius:float,color:str,slices:int=90)-bool:绘制球体center-球心坐标,长度为3的元组或列表radius-半径,浮点型color-顶点颜色,字符串slices-球面分片数(数值越大越精细),整型print(Hello)returnTrue
看上去一切都是完美的,但结果令人遗憾。这个函数及参数的类型注解只是一个注解而已,中看不中用:不管你输入了什么类型的参数,只要数量够3个或者4个,就可以被执行。唯一的作用就是降低了代码的可读性,原本四个参数一眼可见,现在却要花费20秒钟来辨认。不会有类型验证(除非使用类型检查工具),更不会有长度检查。如果想要这些功能,一切还得靠自己。
不加限制的扩展运算符
任何一门编程语言都是在不断地更新和扩展中发展起来的,Python也不例外。说实话,Python的一些语法扩展,还是非常精妙和必要的,比如Py3.8引入的海象运算符(:=),就是一个典型的例子。引入海象运算符之前,若要将一个不足16位长的字符串s用#补足16位(若大于或等于16位则原样输出),一般写成下面这样。
s=HelloWolds+#*(16-len(s))iflen(s)16elsesHelloWold######
这个代码中两次计算字符串s的长度,显然,这不是一个高效的代码。但是如果使用一个临时变量保存字符串s的长度,又不够优雅。海象运算符正是为了解决这一类问题而诞生的。
s=HelloWolds+#*(16-c)if(c:=len(s))16elsesHelloWold######
可惜,不是所有的扩展都像海象运算符这样美妙,甚至其中的很大一部分扩展并未展现出足够的必要性和不可替代性,只是给程序员带来更多使用上的困惑。比如,Py3.9新增的字典合并(
)和更新(
=)运算符,当属此列。
a={x:1,y:2}b={y:3,z:4}a
b#返回一个新的字典{x:1,y:3,z:4}a
=b#将b合并到a中a{x:1,y:3,z:4}
严重怀疑Python团队的人忘记了字典还有个update()方法可以实现这两个新的运算符的功能。
a={x:1,y:2}b={y:3,z:4}a.update(b)a{x:1,y:3,z:4}
也许有人会说,就算字典更新运算符(
=)和update()功能完全重叠,可字典合并运算符(
)返回的是一个新字典,而update()改变了原先的字典。对于持有这种想法的人,我只能悄悄提醒一下,Python对此早有解决方案。
{**a,**b}{x:1,y:3,z:4}
越俎代庖的字符串方法
大量的内置函数或方法,固然可以为程序员带来更多的便利,但也会使系统臃肿,同时增加了入门难度,使学习曲线变得陡峭。如何平衡这个尺度,是一个见仁见智的问题。在我看来,不断增加函数和方法,不但违背了Python的初衷,破坏了API的稳定性,也让程序员失去了选择和乐趣。比如,Py3.9为str对象新增了removeprefix()和removesuffix()两个方法,分别用于删除字符串前缀和后缀。
s=[主播]上港获得前场任意球(1:1)s.removeprefix([主播])上港获得前场任意球(1:1)s.removesuffix((1:1))[主播]上港获得前场任意球
类似的应用需求有很多,如果都要加入到str对象的方法库中,str对象将会变得无比庞大。此类函数的编写,分明应该交由程序员去做,Python语言项目组只需要