来源:Python作业辅导员

2020年10月,Python3.9正式推出,各大IT平台和众多自媒体纷纷火力全开,热推Python3.9的新增特性。然而,除了媒体的自娱自乐,几乎所有的程序员都对此表示无感。我甚至觉得 ,每一次的版本升级都是在抬升Python的学习门槛,令初学者望而生畏。

简单和优雅,是Python创始人吉多 · 范罗苏姆(龟叔)开立山门之时为Python确立的哲学理念。现在,Pyton的发展显然已经背离了这一原则:不管有用无用,但凡别家有的,一概收入;不管是否适合,只要能充门面,悉数拿来。此情势正如当年Pandas之父韦斯·麦金尼面对Pandas的快速扩张时所表达出的无奈:“Pandas正在背离我最初所期望的简洁和易用,变得越来越臃肿和不可控制。”

曾经,我非常地喜欢Python。今天,这份爱依然在,但多了一些冷静和理性。十几年的陪伴,从默默无闻到炙手可热,Python终于在软件排行榜上占据了显耀的位置。在席卷软件行业的扩张风暴中,在Python连续不断地版本升级中,我却分明看到了一种危险的转变:Python正在从简明转向臃肿,从实用转向媚俗。

忍了很久,今日得闲,吐槽一下Python的新增语言特性。以下总结了导致Python危险转向的十大槽点,排名不分先后。

1. 媚俗的静态类型检查

大约从Py3.5开始,直至最新的Py3.9,感觉Python语言项目团队就在做一件事儿:静态类型检查。

为了实现类型检查,他们推出了typing模块,定义了一大堆的应用规则。相应的,有一批静态类型检查工具应运而生,比如Mypy、Pylint或者Pyflakes,PyCharm也可以很好地集成这些工具。

对此,我只想说一句:Python是动态语言吧?既然是动态语言,那你检查个毛线?即便检查通过,就能像编译语言那样运行了?一切不过是虚幻的假象而已,请别用其他语言的理念戕害质朴的Python。

Python追求的是用最简捷的方式解决问题,而不是制造麻烦,然后再解决麻烦。Python强推静态类型检查,不过是迎合那些集成开发环境(IDE),同时满足不明就里的程序员的成就感和虚荣心罢了。

2.  画蛇添足的变量类型声明

当一个拥有5年工作经验的Python程序员读到下面的代码时,会有什么样的感受呢?

>>> name: str
>>> age: int = 18
>>> gilrfriends: list = ['奥黛丽·赫本', '卡米拉·贝勒', '安吉丽娜·朱莉']

相信他一定会说,天哪,这是什么?是Python吗?没错,这的确是Python。看起来像是指定了变量的类型,但即使像下面这样用字符串给被指定为列表类型的变量赋值,运行时也不会发出任何的提示或警告。

>>> gilrfriends: list = '奥黛丽·赫本, 卡米拉·贝勒, 安吉丽娜·朱莉' # 打着右转灯左转
>>> gilrfriends
'奥黛丽·赫本, 卡米拉·贝勒, 安吉丽娜·朱莉'

你看,打着右转灯左转,照样通行无误。这样画蛇添足的操作有什么用呢?原来仅仅是为了让IED或者类型检查工具知道变量的类型。工具原本是为程序员服务的,现在好了,你得先为工具服务。差评!

3. 鸡肋般的函数及参数的类型注解

我一直在寻找一种可以限定函数参数类型的方法,以避免程序运行时出现意外的情况。受限于Python的机制,大多数情况下我只能使用断言(assert)在函数内部对参数类型作出限制,同时尽可能在doc中对参数类型及含义作详尽描述,就像下面的代码一样。

def sphere(center, radius, color, slices=90):"""绘制球体center      - 球心坐标,长度为3的元组或列表radius      - 半径,浮点型color       - 顶点颜色,字符串slices      - 球面分片数(数值越大越精细),整型"""assert isinstance(center, (tuple, list)) and len(center)==3, '期望参数center是长度为3的元组或列表'print('Hello')return True

现在,如果按照Python指导委员会所倡导的方式,上面的代码应该写成如下的样式。

from typing import Union
def sphere(center:Union[tuple,list], radius:float, color:str, slices:int=90) -> bool:"""绘制球体center      - 球心坐标,长度为3的元组或列表radius      - 半径,浮点型color       - 顶点颜色,字符串slices      - 球面分片数(数值越大越精细),整型"""print('Hello')return True

看上去一切都是完美的,但结果令人遗憾。

这个函数及参数的类型注解只是一个注解而已,中看不中用:不管你输入了什么类型的参数,只要数量够3个或者4个,就可以被执行。唯一的作用就是降低了代码的可读性,原本四个参数一眼可见,现在却要花费20秒钟来辨认。不会有类型验证(除非使用类型检查工具),更不会有长度检查。

如果想要这些功能,一切还得靠自己。

4. 不加限制的扩展运算符

任何一门编程语言都是在不断地更新和扩展中发展起来的,Python也不例外。

说实话,Python的一些语法扩展,还是非常精妙和必要的,比如Py3.8引入的海象运算符(:=),就是一个典型的例子。引入海象运算符之前,若要将一个不足16位长的字符串s用#补足16位(若大于或等于16位则原样输出),一般写成下面这样。

>>> s = 'Hello Wold'
>>> s + '#'*(16-len(s)) if len(s) < 16 else s
'Hello Wold######'

这个代码中两次计算字符串s的长度,显然,这不是一个高效的代码。但是如果使用一个临时变量保存字符串s的长度,又不够优雅。海象运算符正是为了解决这一类问题而诞生的。

>>> s = 'Hello Wold'
>>> s + '#'*(16-c) if (c:=len(s)) < 16 else s
'Hello Wold######'

可惜,不是所有的扩展都像海象运算符这样美妙,甚至其中的很大一部分扩展并未展现出足够的必要性和不可替代性,只是给程序员带来更多使用上的困惑。比如,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}

5. 越俎代庖的字符串方法

大量的内置函数或方法,固然可以为程序员带来更多的便利,但也会使系统臃肿,同时增加了入门难度,使学习曲线变得陡峭。

如何平衡这个尺度,是一个见仁见智的问题。在我看来,不断增加函数和方法,不但违背了Python的初衷,破坏了API的稳定性,也让程序员失去了选择和乐趣。比如,Py3.9为str对象新增了removeprefix()和removesuffix()两个方法,分别用于删除字符串前缀和后缀。

>>> s = '[主播]上港获得前场任意球(1:1)'
>>> s.removeprefix('[主播]')
'上港获得前场任意球(1:1)'
>>> s.removesuffix('(1:1)')
'[主播]上港获得前场任意球'

类似的应用需求有很多,如果都要加入到str对象的方法库中,str对象将会变得无比庞大。此类函数的编写,分明应该交由程序员去做,Python语言项目组只需要关注基础的和核心的方法即可。实际上,这两个方法实现起来,也不过是一行代码而已。

>>> s = '[主播]上港获得前场任意球(1:1)'
>>> s if s.find('[主播]') < 0 else s[len('[主播]'):]
'上港获得前场任意球(1:1)'
>>> s if (n:=s.rfind('(1:1)')) < 0 else s[:n]
'[主播]上港获得前场任意球'

6. 啼笑皆非的字符串前缀

Py2时代,u是最常见的字符串前缀,Py3时代,u前缀销声匿迹,b成为了最常见的字符串前缀。无论是Py2还是Py3,原生字符串前缀r都是Python程序员眼中的熟客。从Py3.6开始,突然又冒出来一个新的字符串前缀。

>>> score = '1:1'
>>> f'当前比分{score}'
'当前比分1:1'

以前的前缀,仅仅是一个标识,现在的f前缀则变成了一种运算符,感觉美妙的理性世界瞬间崩塌了!然而,这只是一个开始,更糟糕的事情发生在Py3.8版本上,他们居然又为这个f前缀增加了等号(=)的支持。

>>> 语文=95
>>> 数学=100
>>> f'{语文=},{数学=}'
'语文=95,数学=100'

MyGod,这哪儿是代码,简直是神符!说实话,格式化字符串时,除了C语言风格的%外,我连format()函数都没用过,现在却有可能要面对同事写出来的包含加强版f前缀的代码。伤心的我,只能一笑了之。

7. 不讲逻辑的字典顺序

Py3.6发布的时候,就有人到处宣传说,字典有序了。起初我以为那不过自媒体出于猎奇的目的,随便说说,吸引眼球的。在逻辑上,字典是数据的无序集合,仅依赖于键检索,如果字典有序,那就不是字典了。

没想到,Py3.7居然真的将“字典保持插入顺序”作为新增特性正式对外公布了。幸好,官方说的是“字典保持插入顺序”,而不是“字典有序”,总算为逻辑保留了最后的底裤。

我说字典无序,不是指字典在物理实体上实现的时候真的无序,而是指它的顺序对用户而言没有明确的界定,不能作为数据的特性使用。也许Py3.7使用了新的机制可以更高效地存储和检索字典数据,但这并不是程序员所关注的。新的机制带来的字典顺序稳定,并不能成为我们可以信赖和使用的字典属性。

8. 惟恐天下不乱的函数参数限定符

说到函数的定义和传参,恐怕没有比Python更灵活的语言了。方便的同时,位置参数、默认参数、可变参数、关键字参数等几种参数类型和使用顺序,也给程序员带来了很多使用上的困惑。然而,Py3.8坚定地认为,函数参数的使用还不够混乱,还需要再刺激一下,以期达到从大乱到大治的目的。

于是,函数参数限定符登场了——为了增强效果,Python官方选择斜杠(/)作为这个限定符的表现形式。

让我们一起来尝试着读一读下面这段代码。

>>> def func(a, b, /, c, d, *, e, f):print('OK')>>> func(1,2,3,4,e=5,f=6)
OK
>>> func(1,2,3,d=4,e=5,f=6)
OK

这里,a, b是位置参数,e, f是关键字参数,c, d既可以是位置参数,也可以是关键字参数。好了,关于函数参数限定符就说这么多吧,反正也用不着——除非你是在用Python函数完全模拟C代码编写的函数。

9. 毫无优雅感的泛型函数

说到泛型,Python程序员通常会有两种表情:一种是惊讶:“Python有泛型吗?”;另一种是哂笑:“Python有型吗?”且不讨论Python是否“有型”,作为动态语言,泛型难道不是与生俱来的吗?也许Python团队不这么认为,或者他们认为Python程序员不这么认为。

为了配得上编程语言排行榜上大佬的位次,从Py3.4开始,Python团队就为Python定制了一个泛型函数装饰器。无奈这个机制实在太过牵强,用它写出来得代码丑得一批,估计没几个人会用它。

>>> from functools import singledispatch
>>> @singledispatch
def say_hello(x):print('抱歉,我不认识你')>>> @say_hello.register(int)
def _(x):print('你好,整数')>>> @say_hello.register(str)
def _(x):print('你好,字符串')>>> say_hello(5)
你好,整数
>>> say_hello('abc')
你好,字符串
>>> say_hello([1,2,3])
抱歉,我不认识你

上面这一大堆的代码,只是定义了一个函数say_hello(),可以根据传入参数的类型不同而做出不同反应。如果不使用泛型装饰器,实现起来更加简单且易读。

>>> def say_hello(x):if isinstance(x, int):print('你好,整数')elif isinstance(x, str):print('你好,字符串')else:print('抱歉,我不认识你')>>> say_hello(5)
你好,整数
>>> say_hello('abc')
你好,字符串
>>> say_hello([1,2,3])
抱歉,我不认识你

10. 前后打脸的亡羊补牢

当我第一次读到typing.List和typing.Dict的时候,有那么一小会儿,感觉像是在读java或者是C++的代码。为什么不是熟悉的list和dict呢?仅仅是为了类型提示(type hints) ,为了让集成开发工具读懂代码,生生搞出了比list和dict还复杂的概念。最终的结果是,IDE读懂了代码,程序员却看不明白了。

好在Py3.9对类型提示做了改进,为内置的以及标准库中的集合类型提供了用于类型提示中的泛型的支持,解决了一直以来Python代码中会出现两种list(list 和 typing.List)类型的尴尬情况,也算是亡羊补牢吧。


罗里吧嗦写了这么多,希望不会让Python程序员心生沮丧。事实上,不管我或者我们如何吐槽,Python依然是一门伟大的编程语言。本文的观点,仅是我作为一个原教旨主义者的个人观点,稍微掺杂了一点调侃。

欢迎各位发表高见,不要顾及我的颜面。我会装作看不见,不解释不辩论。杠爷请绕行。

---------End---------

后台回复「微信群」,将邀请加入读者交流群。

  • 《Python知识手册》

  • 《Python可视化指南》

  • 《Plotly可视化指南》

  • 《Pandas使用指南》

  • 《机器学习精选》

????分享、点赞、在看,给个三连击呗!???? 

吐槽:Python正在从简明转向臃肿,从实用转向媚俗相关推荐

  1. Python 正在从简明转向臃肿,从实用转向媚俗

    国庆长假期间,Python3.9正式推出,各大IT平台和众多自媒体纷纷火力全开,热推Python3.9的新增特性.然而,除了媒体的自娱自乐,几乎所有的程序员都对此表示无感.我甚至觉得 ,每一次的版本升 ...

  2. 危险的转变:Python正在从简明转向臃肿,从实用转向媚俗

    作者 | 天元浪子 头图 | CSDN 下载自东方 IC 出品 | CSDN 博客 国庆长假期间,Python3.9正式推出,各大IT平台和众多自媒体纷纷火力全开,热推Python3.9的新增特性.然 ...

  3. 简明python教程在线-简明python教程

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. usrbinpython#hello_world.pyprinthell ...

  4. Python基础(简明Python教程)

    Python基础(简明Python教程) 参考简明Python教程 基本概念 注释符 # 基本数据类型 整数.长整数.浮点数(52.3E-4).复数(-5+4j) 字符串 对象 运算符 与Java基本 ...

  5. python需要花钱下载吗_用Python下载知乎视频,非常实用

    原标题:用Python下载知乎视频,非常实用 Python下载知乎视频. # -*- coding: utf-8 -*- """ 下载知乎视频: 依赖: pip inst ...

  6. 简明python教程pdf-python简明教程中文pdf

    python简明教程中文pdf电子书是作者通过自己对计算机语言多年来的研究和学习得出的学习经验,对于python新手来说非常有用,值得大家下载学习. python简明教程中文pdf文章目录 1.介绍 ...

  7. 简明python教程购买-简明python教程哪版(python看什么书)

    简明 python 教程 这书 有实体书吗 有 学习Python 用哪本书好 对于零基础入门的人来说,对于Python习还是有点懵懂的,如果有一些书籍看来引导,学起来难度也会减低很多!所以向大家推荐这 ...

  8. python多态_Python 简明教程 21,Python 继承与多态

    程序不是年轻的专利,但是,它属于年轻. 目录 目录 我们已经知道封装,继承和多态 是面向对象的三大特征,面向对象语言都会提供这些机制. 1,封装 在这一节介绍类的私有属性和方法的时候,我们已经讲到过封 ...

  9. python subprocess.Popen简明总结

    2019独角兽企业重金招聘Python工程师标准>>> ###subprocess.Popen### 首先先看Popen类: class subprocess.Popen( args ...

最新文章

  1. R语言使用fs包的dir_delete函数删除指定的文件目录(remove the directory)、举一反三、file_delete函数、link_delete函数可以用来删除文件和文件夹
  2. 访谈实录:网管员如何踏上高薪之路(1)
  3. 做项目的一点收获之二
  4. MySQL慢查询处理之mysqldumpslow和mysqlsla
  5. 怎么break java8 stream的foreach
  6. 安卓下载保存到本地(一)
  7. 【小白的刷题之路】字符统计
  8. 直击WinRoute
  9. 为什么VS提示SurfFeatureDetector不是cv的成员函数
  10. androidx86 9.0下载_Surface pro 安装 android x86/chrome OS
  11. 一起谈.NET技术,浅析五大ASP.NET数据控件
  12. java舆情分析_基于Java实现网络舆情分析系统的研究与实现
  13. 354. 俄罗斯套娃信封问题--(每日一难phase2--day9)
  14. 学习方法分享:为何一年半就能拿到大厂 offer
  15. Java高铁的速度是火车的两倍_超级高铁最高速度是飞机速度的近两倍,如果研发成功,对中国房价涨跌和中国高铁的比较优势会有什么影响?...
  16. 多智能体强化学习与博弈论-博弈论基础3
  17. Autovue 21.0.2.3 新功能介绍
  18. 史上最全的 SQL 注入资料,收藏不谢
  19. 人形机器人视觉处理——走迷宫
  20. 互联网基础结构发展的三个阶段

热门文章

  1. Spring 的事务管理
  2. 【华为OD机试】We are a team【2023 B卷|200分】
  3. Bootstrap(前端开发框架一)
  4. 小小程序员买个手环都要搞事???
  5. 浏览器隐私如何进行防范?
  6. Jquery 获取元素节点
  7. 微商快手怎么去引流?如何获取到我们的粉丝?
  8. 如何查看计算机储存系统,Win7怎么看电脑内存?Win7系统查看电脑内存的三种方法...
  9. 百度在线语音识别接入经验
  10. 超级筹码(牛市真空加速定律)