Python 简介

作者:Jeff Bauer

如果您一直在 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 模块,posixregsub

  • 6 --- 使用 posix 模块获取用户 ID。封闭的反引号 (`) 告诉 Python 将此值分配为字符串。

  • 7 --- 以读取模式打开 /etc/passwd 文件。

  • 8 --- 启动 for 循环,读取 /etc/passwd 的所有行。复合语句(例如条件语句)的标头以关键字(ifwhilefortry)开头,并以冒号结尾。

  • 9 --- 读取 /etc/passwd 中的每一行,并使用 string.splitfields() 基于冒号 : 分隔符将其拆分为数组 rec[]

  • 10 --- 如果 /etc/passwd 中的 rec[2] 与我们对 posix.getuid() 的调用匹配,则我们已识别出用户。/etc/passwd 的前 3 个字段是:rec[0] = namerec[1] = passwordrec[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 编程的基础。

  • 异常处理

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 提供了异常处理,包括内置异常(例如 ZeroDivisionErrorTypeErrorNameError 等)和用户定义的异常。后者在开发健壮的类时特别有用。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 代码的查找将在关系数据库中完成,但在应用程序中使用小型数据集也很方便。例如,给定字典 icd9subdivide

   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 系统连接以跟踪临床信息。

加载 Disqus 评论