檄Python文

发布时间:

最后更新:

总字数:
1.6k

这是一篇临时起意的文章,极其主观。

我不是Python专家,确切地说,连小白都算不上。此前搞比赛,搞机器人视觉,跑模型的代码全是C++写的,并不熟悉Python。我如今开始做AI的科研,不得不去学Python了,可是越学越让我难受。

难受并不是因为Python的语言特性不好,我也没什么资格去讨论那些“引入多重继承是不是一个错误”“动态类型好不好”……一类的问题。我只能从一个最俗的俗人的角度,谈一谈我对Python的不满:太丑了!

以下是非常主观偏颇的个人观点。换句话说,把这篇文章当做我的无能狂怒的气话好了。

开始之前,我认为我们有必要复习一下所谓“Python之禅”中的第一条:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.

反直觉

之前为了联系老师,花了一天时间,上线了一个个人网站,用的是现成的模板,基于React。我在没有学过React,也没有学过现代Javascript的情况下,照样看得懂代码,上手就能魔改模板。

可是来到Python这里却全不是这么一回事了,面对那些匪夷所思的符号和下划线,我一头雾水,非得查文档不可。让我大开眼界的一点是:

1
2
3
class someClass(baseClass):
def __init__(self):
pass

我的天呀,怎么会有人用括号来表示继承?一开始看到这样的写法,我脑子都烧了:这个括号莫非是什么构造方法的参数列表?那么,下面的那个__init__又是什么东西……而且,上一次看见这么多下划线,还是在一些C标准库的源码里。为什么咱们就不能好好地用几个“extends”“private”“public”之类的关键字,而是一会儿括号啦,一会儿又是冒号啦,一会儿又是下划线……不消得说了。

事实上,Python想用括号表示的东西多得很:函数调用、参数列表、类继承、元组……

然而到了元组头上,就要出事了。请问,创建只有一个元素的元组该怎么写呢?Python专家们显然考虑到了这个问题,他们给出的答案是:

1
singleton = 'hello',    # <-- note trailing comma

看到这个孤零零的逗号,我眼珠子都要抠出来了。或许这就叫做“Beautiful”吧;Python的官方文档甚至恬不知耻地辩解道:

只有一个元素的元组可以通过在这个元素后添加逗号来构建(圆括号里只有一个值的话不够明确)。丑陋,但是有效。

What can I say.

然而,有的时候——当我们习惯了括号出现的时候,Python的括号却消失得无影无踪了。让我们来对比一下:

1
2
int sum(int a, int b){ return a + b; } // function
[](int a, int b) -> int { return a + b; } // lambda expression
1
2
function sum(a, b){ return a + b; } // function
(a, b) => { return a + b; } // lambda expression
1
2
3
def sum(a, b): # function
return a + b
lambda a, b : a + b # lambda expression

请问:为什么到Python这里,参数列表的括号就消失了呢?同样地,为什么之前创建元组的时候,括号竟然可以省略呢?

当然,你可以说:这又不影响理解……而且还少打了两个字符。那好吧,我只是讨厌这种不一致性

有一种说法是:表示元组的是逗号,而非括号。那好吧,列表用方括号表示,字典用花括号表示,元组却要用逗号。而且,用逗号的时候,还要和圆括号掺和在一起。

自然,还会有下面的事情发生:

1
2
3
4
empty_list = []
empty_tuple = () # they say “it is commas that make tuple”, oh ok.
empty_set = set() # what?
empty_dict = {} # muhahaha, it's because of me

好吧,“无伤大雅”,可以少打很多字符,只是有点不一致罢了。

游标卡尺仙人

Python的这个缩进问题,可谓是老生常谈了。所谓老生常谈,意思就是饱受诟病

不少缩进支持者的逻辑是:反正你写C、Java之类的东西也一定要缩进,那还要大括号干什么呢?

我想他们搞错了一个事情:当我写C++的时候,我确实需要缩进,但是这件事情应该由formatter帮我来完成,而不是我手动去做。我过去不想,现在不想,将来也不会想要手动管理缩进。我只想在正确的位置放上正确的大括号,然后按下快捷键,让编辑器帮我把代码排成美观又清晰的格式,而不是对着解释器报错,一行一行地去找:这里应该缩进过去;那里应该缩进回来……

一句话:我写其它代码从不缩进。缩进的是编辑器,不是我。如果有人愿意手动去管理缩进层级,那他一定有受虐的嗜好。你只能祈祷缩进层级一定不要莫名其妙地出错,否则可有你的苦头吃了——毕竟,Python已经放弃了大括号的“冗余”了。

可问题是:缩进层级是很容易出错的,尤其是在复制粘贴代码的时候。这是因为自古以来连续的空白字符就被视作是无意义的,这些重复空格和换行,在传输过程中,不知什么时候就被压缩替换掉。你不得不接受这一事实,因为空白字符可以被忽略是计算机发展几十年来的约定俗成。

偏偏有一批一批的语言喜欢挑战这一传统,其中就有yaml。yaml本来是想要成为一种“人类友好”的描述语言,可惜它信仰了“游标卡尺神教”:未必对人类友好,对机器而言更糟。

Python对游标卡尺神教的热忱还导致了一个结果:为了弥补删去花括号的不足,冒号也漫天飞舞了。它一会儿出现在块的开头,一会儿出现在切片里,甚至还要出现在lambda表达式里……

最后叠甲

Python真是一门很棒的语言:强大,现代,敏捷……我只是希望它能不要这么丑,因为我还要与它作伴好多年。

Beautiful is better than ugly.