我曾经和同事聊过 Python,告诉他为什么我之前对这个语言不感冒,他笑着问我“问什么不喜欢Python呢?因为它读起来很像英语?”。是的。因为这个语言做了很多底层的工作,有时候会不清楚发生了什么。举个读文件的例子,假设你想一行一行读取文件内容并打印出来。C 会这么做:
#include <stdio>
int main(void) {
FILE *fp;
char buff[256]; // assuming a line won't contain more than 256 chars
fp = fopen("hello.txt", "r");
while(fgets(buff, 256, fp)) {
printf("%s", buff);
}
fclose(fp);
return 0;
}
python 这么做:
with open('hello.txt') as f:
for line in f:
print(line)
现在,很多人会认为这是 python 的优势,然而,第一个例子中,干了什么一目了然:
获取一个文件指针
从文件读取每一行数据到缓存中,打印缓存中的内容
关闭文件流
python 的例子中看不到这些,它是一种 “魔法般的”过程。现在,有人认为这是好事,因为将程序员与底层实现细节隔离(我同意这个说法),但我想知道到底发生了什么。
有趣的是,我以上提到的缺点,我现在认为都是优点。为了公平起见,我强调,Python 里边没有魔法,如果你多了解一点,你会发现真的没有,有的只是语言解释代码的方式,从这点来看,我发现它挺有意思的。如果你也这么觉得,我建议你深入了解它的工作机制,如果有东西像魔法,就找出来到底发生了什么,事情就会变得清晰,魔法就变成了便利。
我的认识发生很大的变化,尤其是我决定使用 Python 后,事实上我现在是 Python 的死忠!现在你也许会想我将会在哪里说服你学 Python 是个好主意,不要担心,马上就到。作为引言的结尾,我想说明,这只是我对这个语言的个人感受,只是个人偏好。我没有试图以“如果你用 Python,你就不是真正的程序员(实际上,我不这么认为)”的理由劝说人们学 C。当有人问我他们的入门语言应该选哪个,我通常建议他们选 Python,基于我上边提到的“缺点”的原因。我的感觉来源于我的兴趣,我曾经在做一些很底层的东西,你能想到,Python 并不适用。
Python 语言精粹
在借用了JavaScript 畅销书 《JavaScript 语言精粹》作为本节标题后,我们开始讨论本文的主题:为什么你(没错,就是你!)应该学 Python。
1、通用脚本语言
这是我使用 Python 的主要原因。我曾经和很多人做过很多项目,不同的人用不同的系统。就我而言,我经常在windows系统和linux系统之间切换。举一个实际的例子,有一个项目,我写了项目的自动测试脚本,结果发现只有我能用,因为是用 PowerShell 写的,而我是项目中唯一使用 Windows 的。当时同事们自然认为 bash 是最好的,我还向他们解释 PowerShell 遵循一种不同的模式并且有它的强项(例如,它提供了 .NET 框架接口),它是面向对象的脚本语言,和 bash 完全不一样。现在我不想讨论哪个更好,因为这不是本文的重点。
那么这个问题怎么解决呢?嗯…现在,是否有一种脚本语言可以在所有主流平台上运行呢?你猜对了,它就是 Python。除了可以在主流平台上运行,它还是开箱即用的脚本语言。标准库包含不少实用程序,提供了独立于系统的常用接口。举一个简洁明了的例子,假设你想获取文件夹下所有文件的文件名,然后对其进行处理,在 UNIX下,你要这么做:
for f in *; do echo "Processing $f file..."; done
用 PowerShell 做类似的事情:
Get-ChildItem "." |
Foreach-Object {
$name = $_.Name
Write-Output "Processing $($name) file..."
}
An equivalent functionality in Python can be achieved with:
python 这么做:
from os import listdir
for f in listdir('.'):
print('Processing {} file...'.format(f))
现在我认为,Python 除了可以跑在 Linux,MacOSX 和 Windows 上,它也很易读。上边例子中的脚本很简单,在复杂的例子中不同语言的易读性差异会更明显。
就像我之前提到的,Python 自带了许多强大的库用来取代 shell 脚本,你会发现,最有用的是:
os – 提供系统无关功能,比如文件目录和文件读写。
subprocess – 产生新进程、与输入输出流和返回代码交互。可以用它来启动系统已安装的程序,但请记住如果你担心脚本的可移植性,这不是最好的选择。
shutil – 提供对文件和文件集合的高级操作。
argparse – 解析命令行参数,构建命令行接口。
好了,假设你 get 到了重点,跨平台和易读性听起来挺不错的,但是你真的喜欢类 UNIX shell 类似的语法怎么办?告诉你个好消息,鱼和熊掌可以兼得!看看 Plumbum,它是一个 Python 模块,它的座右铭是“ 再也不写 shell 脚本”。它模仿了 shell 语法,同时保持了跨平台。
不要完全抛弃 shell 脚本
即使 Python 可以完全取代 shell 脚本,但也不是必须这么做,因为 Python 脚本天生适合 Unix 命令行理念,你要做的就是让它们从 sys.stdin (标准输入)读数据,向 sys.stdout(标准输出)写数据。举个例子,假设你有一个文件,每行有一个单词,你想知道每个单词在文中出现的次数。这种情况就没必要全部是用Python,我们可以使用 cat 命令和我们的脚本,称它为 namecount.py 一起来完成这个任务。
假设有一个文件,名为 names.txt ,内容如下:
cat
dog
mouse
bird
cat
cat
dog
现在使用我们的脚本:
$> cat names.txt | namecount.py
Powershell:
$> Get-Content names.txt | python namecount.py
期望的输出如下(顺序可能会变化):
bird 1
mouse 1
cat 3
dog 2
namecount.py 源码:
#!/usr/bin/env python3
import sys
def count_names():
names = {}
for name in sys.stdin.readlines():
name = name.strip()
if name in names:
names[name] += 1
else:
names[name] = 1
for name, count in names.items():
sys.stdout.write("{0}\t{1}\n".format(name, count))
if __name__ == "__main__":
count_names()
无序的信息可读性差,你可能想按单词出现的次数对其排序,让我们试试。我们要用管道输出文件内容供内建命令处理。按数字降序排序,我们要做的就是 $> cat names.txt | namecount.py | sort -rn 。如果使用PowerShell 应该这样:$> Get-Content names.txt | python namecount.py | Sort-Object { [int]$_.split()[-1] } -Descending (你可能听到了 Unixer 的吐槽声了,PowerShell 怎么这么繁琐)。
这回我们的输出是确定的,如下所示:
cat 3
dog 2
bird 1
mouse 1
(旁注:如果你用 PowerShell,cat 是 Get-Content 的别名,sort 是 Sort_object 的别名,所以以上命令可以写成:$> cat names.txt | python namecount.py 和 $> cat names.txt | python namecount.py | sort { [int]$_.split()[-1] } -Descending )
但愿我成功说服你 python 是你某些脚本的替代品,你不必完全抛弃 shell 脚本,因为你可以将 Python 融合到你现有的工作流和工具箱中,还可以从它跨平台,更好的可读性,还有丰富的库中获益(后面会讲)。
2、大量优秀的库
3、用来做渗透测试很强大
4、黑客的语言
希望这篇文章,能够给你一个学习 Python 的理由。这篇文章来自一个为过去说了Python 的坏话而愧疚,如今在到处宣传 Python 的人。我先申明一点,这只是个人喜好问题,当有人问我先学哪门语言时,我通常推荐 Python。