为什么你应该学 Python

人生苦短,我用Python

1 What & Why

1.1 What’s Python?

Python(英语发音:/ˈpaɪθən/,类似 『派森』), 是一种 面向对象解释型动态 强类型 程序设计语言。

由 Guido van Rossum 于 1989年底 发明,第一个公开发行版发行于 1991 年。

Python 语法 简洁而清晰,具有 丰富和强大的类库。常被称为 胶水语言,能够把用其他语言制作的各种模块(尤其是 C/C++)很轻松地联结在一起。

常见一种应用情形是,使用 Python 快速生成程序原型(有时是程序的最终界面),然后对其中有特别要求的部分,用更合适的语言改写,比如 3D 游戏中的图形渲染模块,性能要求特别高,就可以用 C++ 重写。

1.2 Why Python?

生产工具决定生产效率

理由很多,我列举一些普遍公认的好处,以及优秀特性。

1.2.1 明确、简单、优雅

这必须放在最前面,而且有可能是最重要的。

Python 在设计上坚持了 清晰划一 的风格,这使 Python 非常易读、易写、易维护。

Python 哲学里有这样一句话

In the face of ambiguity, refuse the temptation to guess.
当存在多种可能时,不要尝试去猜测
There should be one– and preferably only one –obvious way to do it.
应该有一个——而且最好只有一个——最明显的方法去完成

(Python 在语法上接近C语言,后面的例子会C/C++或者Java的人应该很快可以理解。)


以下问题应该多少遇过:

  • C语言 b = a+++++a; 的优先级问题
  • 纠结 while(){}do{}while(); 的差别。
  • 凌乱的括号和缩进,团队内难以统一
  • ……

于 Python,这些问题都不存在:

  • 没有 ++
  • 只有 while 没有 do
  • 推荐一行一句,不推荐分号
  • 没有花括号
  • 唯一缩进风格,缩进决定代码层级(换言之,缩进不仅仅是排版,而是语义的一部分)

一般语言缩进不对,是风格问题,影响可读性,不影响运行;Python 哪怕多一个空格,报错,罢工。

你可能会不习惯,甚至觉得蛮不讲理。可一旦你习惯并使用一段时间,需要阅读自己以前的代码,或者别人的代码:你会发现,可读性真好!

Python 有意设计 限制性很强的语法,使得不好的编程习惯直接不能通过编译(注:需要编译为字节码)。你只有两个选择:清晰易读的代码,和不能运行的代码,没有中间选项。同时也避免了初学者在多种写法中选择困难,在歧义中玩猜谜游戏。


去掉令人费解的特性同时,Python 加入了很多符合直觉的语法

同时赋值

(注:背后的机制是自动打包与解包)

1
2
3
4
// C code
temp = a;
a = b;
b = temp;


1
2
# Python code
a, b = b, a

五个变量按以下顺序交换,如果用 C 怎么写?多少个临时变量?按什么顺序赋值?

1
2
# Python
a, b, c, d, e = b, d, a, e, c

不仅是少了两行代码 和 一个临时变量,而是大大提升可读性!

列表推导
1
2
3
4
5
6
// C Code
int list[SIZE];
for(i = 0; i < SIZE; i++){
list[i] = i * 2;
}


1
2
3
# Python code
list = [i * 2 for i in range(SIZE)]
默认参数 和 命名参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Java code
class Foo {
int bar() {
bar(1);
}
int bar(int arg1) {
bar(arg1, 2);
}
int bar(int arg1, int arg2) {
System.out.println(arg1 + ", " + arg2)
}
}
// main() here
Foo f = new Foo();
f.bar(); // 1, 2
f.bar(11); // 11, 2
f.bar(11, 55); // 11, 55


严格来说,由于 Python 的参数表没有指定类型,无法基于参数表做重载。
不过由于 默认参数命名参数 的存在,Python 不需要重载,还更易用。

1
2
3
4
5
6
7
8
9
10
11
# Python code
class Foo:
def bar(self, arg1=1, arg2=2, arg3=3, arg4=4):
print(', '.join(arg1, arg2, arg3, arg4))
# main() here
f = Foo()
f.bar() # 1, 2, 3, 4
f.bar(56) # 56, 2, 3, 4
f.bar(56, 78) # 56, 78, 3, 4
f.bar(56, arg3=99) # 56, 2, 99, 4 # 如果跳过了中间的参数,后面的参数都要用命名参数
map() 与 匿名函数(λ 计算)

以下代码试图将一个列表的每个数变成自己的平方

1
2
3
4
// C code
for(i = 0; i < SIZE; i++){
list[i] = list[i] * list[i];
}


1
2
# Python code
list = map(lambda n : n**2, list)

map() 的两个参数分别是 函数列表。(Python一切皆对象,包括函数本身也可以赋值和作为参数传递)作用是将 列表 中的每一个元素,都放进函数运行,将结果重新构成一个 新的列表 返回。

其中,这个匿名函数等价于

1
2
def f(n):
return n**2
in 关键字

多条件判断

1
2
3
4
// C code
if((a == 1 || a == 2 || a == 4 || a == 9) && (b != 3 && b != 8)){
// so something
}


1
2
3
# Python code
if a in (1, 2, 4, 9) and b not in (3, 8):
# do something

容器遍历

1
2
3
4
5
6
// C code
for(i = 0; i < ROW_SIZE; i++){
for(j = 0; j < COL_SIZE; j++){
// do something with list[i][j]
}
}


1
2
3
4
# Python code
for row in list:
for x in row:
# do something with x
容器特性

按照一定间隔取元素

1
2
3
4
// C code
for(i = 3; i < 100; i += 4){
// do something with list[i]
}


1
2
3
# Python code
for x in list[3:100:4]:
# do something with x

访问尾部元素

1
2
// Java code
list[list.length - 1];


1
2
# Python code
list[-1]

一不小心就介绍了太多特性

好用的特性不止这些,像 自动打包与解包,装饰器,闭包这些特性,以后有机会再讨论。


大家可以发现,Python 代码非常接近自然语言,基本可以当作英语去阅读理解。所以 Python 又有 『可以运行的伪代码』 之称。

它的简单,让大脑从细节中解放,集中精力放在业务流程和算法上。

1.2.2 跨平台、胶水语言、丰富和强大的类库

跨平台

Python 是开源的语言,只要目标平台实现一个解析环境就能支持。

实际上 Mac 和 大多数 Linux 发行版 内置支持Python。只有 Windows 和 手机 需要安装一下。

胶水语言

Python 可以跟很多语言互相调用。首先是 C。

这意味着如果某些地方用 Python 实现不好(譬如太慢),你可以换成更适合的语言实现。

强大的类库

自带的库就包含大量高级数据类型,如 列表、元组、字典、集合、队列… 非常强大。
甚至于你要启动一个简单的 Server,一般的语言都要费点劲,Python 自带 HTTPServer ,跑起来就一两行代码。

至于各种第三方库,就强大到令人发指了。除了本身 Python 编写的库,由于 Python 对 C/C++ 友好,众多强大的开源软件包即使不是用 Python 写的,也往往提供 Python API。

  • GUI 库 Qt
  • 计算机视觉库 OpenCV
  • 三维可视化库 VTK
  • 医学图像处理库 ITK
  • 3个著名的科学计算库 NumPy / SciPy / matplotlib

良好的类库支持,聚集了一大批活跃的开发者,将开发成果继续开源发布出来……

强大的类库支持,让我们从重复造轮子的劳动中解放出来。

1.2.3 快!

这一点是前面两点的结果。

有网友实践,一个ASF XML 序列化工具,C++ 需要 1580 行,而Python只用 130 行。Python 作为一个高级语言的代码生产力高于多数语言的。(这里高级是指抽象层级更高,无好坏之分)

只要敲非常少的代码,引用强大的类库,就实现了需求;每次修改之后,不需要等待编译,马上可以运行。

这对于 快速原型流程自动化 很重要。

1.2.4 需求巨大

最新的 Github 语言排行,Python 已代替 Java 上升到第二的位置。

科学计算、数据挖掘、人工智能、自动化运维/测试 … 未来对于 Python 的需求非常大。

1.2.5 缺点

Python 没有缺点吗?有:

  • 慢: 相对于 C/C++ , Java 而言,抽象层级高的代价,是执行效率不高。
    但随着运算力越来越廉价 和 人的时间越来越宝贵,很多时候这变得不那么重要。
    何况:

    1. 自己写的 C/C++ 代码,算法效率未必比得上 Python 库里的实现
    2. Python 已经优化得越来越快了,某些特定领域甚至超过了 C(通过 PyPy 的 JIT 技术)
    3. 根据 20/80 定律,可以把性能瓶颈用 C/C++ 重写。为什么不一开始就用 C/C++ ?Python 可以快速实现原型。
      一般的自动化工具,根本感觉不到速度问题。
  • 动态语言难以维护大型项目:对于编程习惯不好的人,是的。

    但是同样的人,在静态语言也会面临问题。Java 之所以存在大量复杂的 Design Pattern ,很大一部分是为了绕过语言设置的限制,为此逻辑弄得晦涩难明。
    Python 语法上做了大量限制,逻辑上却给予了很大的自由,可以很简单就实现原本复杂的设计模式才有的功能。
    至于大型项目的可维护性,要依赖良好的设计 和 编码规范。另外也可以通过装饰器限制参数类型。不过从公司的角度,要找到合格的开发者,确实比 Java 要难。

2 How to Python

1
2
# Python 3.x
print("Hello world!")

That’s all!


是的,我没有打算展开讲。

语法接近C,而且非常直观。我到现在为止没有买过任何一本 Python 的书,大多数早期的问题, API 文档就够了。(注1:Windows 版 Python 安装时,会附带一份 API 文档。注2:这段话写于 2015年,后来我买了一本 《Python cookbook》)

文档还看不懂,请打开浏览器。(谷哥还是度娘,自己选择)

到不得不买书的时候,往往已经比较深入了。

Python 2.x VS Python 3.x

作为将 简洁清晰 视作生命的语言,为了减轻历史包袱,Python 3.0 以后的版本,并 不兼容 之前的版本。于是,关于用哪一个版本就分成了两派。

其实很简单

  • 如果有什么理由不得不用 Python 2.x,例如有个库只有 2.x 的版本,那就用 2.x (注:随着时间推移这种情况已经越来越少)
  • 否则,推荐从 3.x 开始。它代表未来 Python 的方向。到了今天,多数的库都已移植到 3.x ,官方宣布 2020 停止维护 2.x 。
  • 或者不得已,都用。差别没那么大。

Life is short, you need Python!
– Bruce Eckel, ANSI C++ Comitee member


文章的最后,一起来看一下 Python 之禅

The Zen of Python
——Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one– and preferably only one –obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea – let’s do more of those!


知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议
本文为本人原创,采用知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议进行许可。
本作品可自由复制、传播及基于本作品进行演绎创作。如有以上需要,请留言告知,在文章开头明显位置加上署名(Jayce Chant)、原链接及许可协议信息,并明确指出修改(如有),不得用于商业用途。谢谢合作。
详情请点击查看协议具体内容。