Python 简介
如果您一直在 Linux 系统上进行编程,您可能正在使用 C 或 C++ 编码。如果您是一名系统管理员,您可能正在使用 perl、Tcl、awk 或各种 (sh/csh/tsh/bash) shell 脚本语言进行编程。也许您编写了一个脚本来完成特定的工作,但现在发现它无法很好地扩展。您可能正在编写 C 应用程序,但现在希望不必陷入低级细节。或者,您可能只是对在友好的、解释型的环境中进行高级的、面向对象的编程的可能性感兴趣。
如果以上任何一种情况适用于您的情况,您可能会对 Python 感兴趣。Python 是一种功能强大的语言,可用于快速开发应用程序。解释器易于扩展,您可以将您最喜欢的 C 代码作为编译后的扩展模块嵌入。
Python 不是那种似乎仅仅出于教学原因而被推广的研究语言之一。几乎可以立即进行有用的编码。Python 似乎通过清除路径而不是竖起护墙来鼓励面向对象的编程。
要执行标准的 hello 程序,请在命令行中输入以下内容
$ python Python 1.2 (Jun 3, 1995) [GCC 2.6.3] Copyright 1991-1995 Sitchting Mathematisch Centrum, Amsterdam >> print "hello, bruce" hello, bruce >> [CONTROL]-D
大多数 Python 程序虽然是增量开发的,但都作为普通脚本执行。下一个程序说明了对原始程序的一些扩展。新版本将根据您在 /etc/passwd 中的用户帐户来识别您的身份。
1 #!/usr/local/bin/python 2 3 import posix 4 import string 5 6 uid = `posix.getuid()` 7 passwd = open(`/etc/passwd') 8 for line in passwd.readlines(): 9 rec = string.splitfields(line, `:') 10 if rec[2] == uid: 11 print `hello', rec[0], 12 print `mind if we call you bruce?' 13 break 14 else: 15 print "I can't find you in /etc/passwd"
程序的逐行解释如下
1 --- 要调用的命令解释器
3-4 --- 导入两个标准的 Python 模块,posix 和 regsub。
6 --- 使用 posix 模块获取用户 ID。封闭的反引号 (`) 告诉 Python 将此值分配为字符串。
7 --- 以读取模式打开 /etc/passwd 文件。
8 --- 启动 for 循环,读取 /etc/passwd 的所有行。复合语句(例如条件语句)的标头以关键字(if、while、for、try)开头,并以冒号结尾。
9 --- 读取 /etc/passwd 中的每一行,并使用 string.splitfields() 基于冒号 : 分隔符将其拆分为数组 rec[]
10 --- 如果 /etc/passwd 中的 rec[2] 与我们对 posix.getuid() 的调用匹配,则我们已识别出用户。/etc/passwd 的前 3 个字段是:rec[0] = name、rec[1] = password 和 rec[2] = uid。
11-12 --- 将用户的帐户名打印到 stdout。尾随逗号避免了输出后的换行符。
13 --- 中断 for 循环。
14-15 --- 如果我们在 /etc/passwd 中找不到用户,则打印消息。
细心的读者会注意到,控制语句缺少任何形式的 BEGIN/END 关键字或匹配的大括号。这是因为缩进定义了语句的分组方式。这不仅消除了对大括号的需求,而且还强制执行了一种可读的编码风格。毫无疑问,这种设计特点会让一些潜在的 Python 黑客感到不适,但在实践中,它很有用。我可以想到无数次我花费时间跟踪 C 中的错误,这些错误是由于误解了看起来像以下任何片段的代码(通常是深度嵌套的)而导致的
if (n == 0) x++; y--; z++; if (m == n || (n != o && o == q)) { j++; } k++; q = 0; while (y--) *ptr++; if (m == n) { x++; }
在语言定义中强制执行的编码风格本可以为我节省很多挫败感。另一个程序员编写的 Python 代码通常非常易读。
您可能会反对我们在上面的程序中做了很多工作只是为了演示 Python 语言特性。更好的方法是使用标准 Python 库中的 pwd 模块
print `hello', pwd.getpwuid(posix.getuid())[0]
这指出了 Python 的另一个优点,这对于任何新语言的成功都至关重要:其库的健壮性。如前所述,您可以通过将编译后的扩展模块添加到您的个人库来扩展 Python,但在大多数情况下,您不必这样做。
以 ftplib 模块为例。如果您想编写一个 Python 脚本来自动下载最新的 FAQ,您可以简单地在以下示例中使用 ftplib
#!/usr/local/bin/python from ftplib import FTP ftp = FTP(`ftp.python.org') # connect to host ftp.login() # login anonymous ftp.cwd(`pub/python/doc') # change directory ftp.retrlines(`LIST') # list python/doc F = open(`python.FAQ', `w') # file: python.FAQ ftp.retrbinary(`RETR FAQ', F.write, 1024) ftp.quit()
Python 有许多特性,这些特性使编程变得有趣,并恢复您对设计目标的看法。该语言鼓励您在程序开发过程中通过编写实验性函数来探索其特性。几个值得注意的 Python 特性
自动内存管理。不需要 malloc/free 或 new/delete——当对象变得不可达时,它们会被垃圾回收。
支持操作列表、元组和数组
关联数组,在 Python 中称为“字典 (Dictionaries)”
鼓励重用性的模块。Python 附带了大量的标准模块,这些模块可以用作学习 Python 编程的基础。
异常处理
类
在下一个示例中,我将尝试演示其中的一些特性。StackingThings 类将允许用户将物品堆叠在一起,直到达到断裂点。
1 #!/usr/local/bin/python 2 3 StackingException = `StackingException' 4 5 class StackingThings: 6 names = (`llama', `spam', `16 ton weight', 7 `dead parrot') 8 weights = {} 9 weights[`llama'] = 300 10 weights[`spam'] = 1 11 weights[`16 ton weight'] = 32000 12 weights[`dead parrot'] = 2 13 breakpt = {} # breaking points 14 breakpt[`llama'] = 200 15 breakpt[`spam'] = 1000 16 breakpt[`16 ton weight'] = 1000000 17 breakpt[`dead parrot'] = 15 18 19 def _ _init_ _(self): 20 self.items_stacked = [] 21 def add(self, item): 22 if item not in self.names: 23 raise StackingException, \ 24 item+`not a stackable object' 25 self.items_stacked.insert(0, item) 26 try: 27 self.test_strength(item) 28 except StackingException, val: 29 print item, val 30 def test_strength(self, item): 31 wt = 0 32 bp = 1000000 33 for i in self.items_stacked: 34 wt = wt + self.weights[i] 35 if wt > bp: 36 self.items_stacked.remove(item) 37 raise StackingException, \ 38 `exceeds breaking point!' 39 bp = self.breakpt[i] 40 41 # user code to test StackingThings class 42 43 s = StackingThings() 44 45 s.add(`llama') 46 s.add(`spam') 47 s.add(`spam') 48 s.add(`spam') 49 s.add(`dead parrot') 50 s.add(`16 ton weight') 51 52 print `items stacked = ', s.items_stacked 53 54 try: 55 s.add(`bad object') 56 except StackingException, msg: 57 print `exception:', msg
此脚本产生以下输出
16 ton weight exceeds breaking point! items stacked = [`dead parrot', `spam', `spam', `spam', `llama'] exception: bad object not a stackable object
StackingThings 类本身由 3 个方法组成:_ _init_ _()、add() 和 test_strength()。当初始化 StackingThings 时,我们使用特殊的 __init__ 方法通过初始化堆叠物品的列表来创建其初始状态:items_stacked = []。add() 方法基本上是 StackingThings 用户访问的唯一方法。test_strength() 由 add() 调用,以验证我们是否未超过断裂点。
我们示例中每个方法的第一个参数都称为 self。这只是一种约定,但它使我们的代码更具可读性。Python 方法的第一个参数以与 C++ 中的 this 关键字有些类似的方式使用。
Python 提供了异常处理,包括内置异常(例如 ZeroDivisionError、TypeError、NameError 等)和用户定义的异常。后者在开发健壮的类时特别有用。Python 使用 try/except 语法进行异常处理
try: DenominateZero() except ZeroDivisionError, val: print `Whoops:', val
我们的 add() 方法用于在 test_strength() 中尝试异常,并在我们传递给它一个非法堆叠物品时引发异常。
在第 25 行和第 36 行的示例中演示的 Python 列表的两个内置方法是 insert() 和 remove()。列表对象上支持的其他操作包括 append()、count()、index()、reverse() 和 sort()。
数据属性可以由类的方法以及用户代码访问:无论是 print self.names(在类方法中)还是 print s.names(来自用户代码)都将打印合法堆叠事物的列表
[`llama', `spam', `16 ton weight', `dead parrot']
字典 (Dictionaries)(对于所有 awk/perl 黑客来说,即关联数组)是最有用的 Python 数据类型之一。与按数字索引的普通数组不同,关联数组按字符串索引。这种实用程序的价值值得详细描述。
我经常在医疗应用中处理 ICD-9-CM 代码。这些代码通常是数字的,但有时是字母数字的。它们通常有一个小数点,但有时没有。某些代码可以进一步细分为额外的 ICD-9 代码。此外,代码会定期添加和删除,但大多数代码不会更改。通常,ICD-9 代码的查找将在关系数据库中完成,但在应用程序中使用小型数据集也很方便。例如,给定字典 icd9 和 subdivide
x subdivide[x] icd9[x] --- ------------ ------------------------- `692' 1 `Contact dermatitis' `692.0' 0 `Due to detergents' `692.2' 0 `Due to solvents' `692.7' 1 `Due to solar radiation' `692.70' 0 `Unspecified dermatitis' `692.71' 0 `Sunburn' `692.72' 0 `Other: Photodermatitis'
我们可以通过以下方式操作 ICD-9 代码
for code in icd9.keys(): if subdivide[code]: print `ICD-9',code,'may be further subdivided' else: print `Description for',code,`is:',icd9[code]
这将产生以下输出
ICD-9 692.7 may be further subdivided Description for 692.70 is: Unspecified dermatitis Description for 692.0 is: Due to detergents ICD-9 692 may be further subdivided Description for 692.71 is: Sunburn Description for 692.2 is: Due to solvents Description for 692.72 is: Other: Photodermatitis
我们的 StackingThings 示例的第 8-17 行使用了字典,但为了清晰起见,初始化被分成几行。这可以简化为
weights = {`llama':300, `spam':1, \ `16 ton weight':32000, `dead parrot':2} breakpt = {`llama':200, `spam':1000, \ `16 ton weight':1000000, `dead parrot':15}
最后,Python 中提供了继承,尽管在此示例中未演示。派生类可以覆盖其基类或多个基类的方法(是的,有限形式支持多重继承)。用 C++ 的说法,Python 类中的所有方法都是“虚 (virtual) ”方法。
Python 目前可以从 ftp.python.org 以源代码或 Linux 二进制文件的形式获得。各种模块已经开发出来,并成为标准 Python 库的一部分。仅举几个例子:对字符串、正则表达式、posix、套接字、线程、多媒体、密码学、STDWIN、Internet/WWW、Expect 以及大量其他贡献的支持,都会定期提交。
Python 是可扩展的。如果您会用 C 语言编程,则可以向解释器添加一个新的低级模块。我们公司目前正在为分布式数据库系统执行此操作。Python 解释器将成为许多应用程序的高级命令语言。
除了 Linux 之外,Python 还在其他几个平台上运行:OS/2、Windows、Macintosh 以及许多 Unix 版本。与 Linux 一样,所有这些版本都是免费提供和分发的。
Python 的文档质量非常高,由 Python 的创建者 Guido van Rossum 编写。在 Python ftp 站点上提供了四个独立的 postscript 格式用户手册(请参阅侧边栏 “Python 信息”)。这些文档也已转换为 HTML 和 Microsoft 帮助文件格式。Python FAQ、快速参考指南和用户评价也可用。O'Reilly and Associates 还计划在明年年初出版 Programming Python。
Python 有其自己的活跃新闻组 (comp.lang.python) 以及一个邮件列表,该邮件列表接收与新闻组相同的消息。要订阅邮件列表,请发送邮件至 python-list-request@cwi.nl。已经形成了各种 Python 特殊兴趣小组:Matrix-SIG、GUI-SIG 和 Locator-SIG。
最后,Python 软件基金会 (“PSA”) 的成立是为了促进 Python 开发社区的共同利益。PSA 与 GNU 项目不同,它不进行软件的实际开发(尽管它的许多成员可能这样做),而是充当其他人开发的 Python 软件模块的交换中心。它还举办研讨会和相关活动,以帮助推广 Python 语言的使用。有关 PSA 的更多信息,请访问 Python 主页:www.python.org。
特别感谢 Mark Lutz、Aaron Watters、PSA,当然还有 Guido van Rossum。
Jeff Bauer 在过去的 16 年中一直致力于开发医疗保健软件。他目前的项目涉及将基于笔的计算机与 Unix 系统连接以跟踪临床信息。