面向初学者的 Python 编程
尽管汇编代码和 C 语言程序员可能会告诉我们什么,但高级语言在每个程序员的工具箱中都有其地位,其中一些语言不仅仅是计算机科学的好奇心。在当今我们可以选择的众多高级语言中,Python 似乎对于那些想要学习新事物并同时进行实际工作的人来说是最有趣的。它对面向对象编程的朴实实现以及其简洁易懂的语法使其成为一种有趣的学习和使用的语言,这对于大多数其他语言来说是不可想象的。
在本教程中,您将学习如何编写使用命令行选项、读取和写入管道、访问环境变量、处理中断、读取和写入文件、创建临时文件以及写入系统日志的应用程序。换句话说,您将找到编写实际应用程序而不是老式的无聊的Hello, World!程序的秘诀。
首先,如果您尚未在系统上安装 Python 解释器,那么现在是时候了。为了简化这一步骤,请使用与您的 Linux 发行版兼容的软件包安装最新的 Python 发行版。rpm、deb 和 tgz 也可在您的 Linux CD-ROM 或在线获取。如果您遵循标准安装程序,则不应有任何问题。
接下来,阅读由 Python 编程语言的创建者 Guido van Rossum 编写的优秀的Python Tutorial。本教程是官方 Python 文档的一部分,您可以在 /usr/doc/python-docs-1.5.2 或 /usr/local/doc/python-docs-1.5.2 目录中找到它。它可能以原始 LaTeX 格式交付,必须首先进行处理;如果您不知道如何执行此操作,请访问 https://pythonlang.cn/doc/ 下载其他格式的版本。
我还建议您手头备有Python Library Reference;当这里给出的解释不能满足您的需求时,您可能需要它。您可以在与Python Tutorial相同的位置找到它。
可以使用您喜欢的文本编辑器创建脚本,只要它以纯 ASCII 格式保存文本,并且当行长于编辑器窗口的宽度时,不会自动插入换行符。
始终以以下任一项开始您的脚本
#! /usr/local/bin/python
或
#! /usr/bin/python如果您的系统上 python 二进制文件的访问路径不同,请更改该行,保持前两个字符 (#!) 不变。确保此行确实是脚本中的第一行,而不仅仅是第一个非空白行——这将为您节省很多挫败感。
使用 chmod 设置脚本的文件权限,使其可执行。如果该脚本仅供您自己使用,请键入 chmod 0700 scriptfilename.py;如果您想与您所在组中的其他人共享它,但不让他们编辑它,请使用 0750 作为 chmod 值;如果您想向其他所有人授予访问权限,请使用值 0755。如需有关 chmod 命令的帮助,请键入 man chmod。
当我们想要告诉脚本如何运行或将一些参数(文件名、目录名、用户名等)传递给它们时,命令行选项和参数非常方便。所有程序都可以在需要时读取这些选项和参数,您的 Python 脚本也不例外。
实现适当的处理程序归结为读取 argv 列表并检查您希望脚本识别的选项和参数。有几种方法可以做到这一点。清单 1 是一个简单的选项处理程序,它可以识别常见的 -h、-help 和 --help 选项,当找到它们时,它会在显示帮助消息后立即退出。
复制并将此脚本另存为 help.py,使用 chmod 0755 help.py 命令使其可执行,并运行多次,指定不同的选项,包括处理程序识别的和未识别的选项;例如,使用其中一个选项,您将看到此消息:./help.py -h 或 ./help.py -o。如果选项处理程序确实识别出其中一个选项,您将看到此消息
help.py—does nothing useful (yet) options: -h, -help, or --help—display this help Copyright (c) Jacek Artymiak, 2000
如果您使用它无法识别的选项或根本不使用任何选项调用 help.py,它将显示“我不识别此选项”消息。
请注意,我们需要导入 sys 模块,然后才能检查 argv 列表的内容,然后才能调用 exit 函数。sys.exit 语句是一项安全功能,可防止在 argv 列表中找到帮助选项之一时进一步执行程序。这确保了用户在阅读帮助消息之前不会做一些危险的事情(否则他们就不需要帮助消息了)。
上面描述的简单帮助选项处理程序运行良好,您可以复制并更改它以识别其他选项,但这并不是识别带或不带参数的多个选项的最有效方法。“正确”的方法是使用 getopt 模块,它将选项和参数转换为一个很好的元组列表。清单 2 显示了它的工作原理。
复制此脚本,将其另存为 options.py 并使其可执行。如您所见,它使用了两个模块:sys 和 getopt,它们在开头就被导入。然后我们定义一个简单的函数,每当出现问题时,它都会显示帮助消息。
命令行参数的实际处理从 try 语句开始,我们在其中测试命令行选项和参数 (sys.argv) 列表是否存在定义为未知选项或缺少参数的错误;如果检测到错误,脚本将显示错误消息并立即退出(请参阅 except 语句组)。当未检测到错误时,我们的脚本会将选项及其参数列表拆分为 options 列表中的元组,并通过执行一系列循环开始解析它们,每个循环搜索一个选项及其预期的参数。
getopt.getopt 函数在我们的示例脚本中生成两个列表:options,其中包含选项及其参数;以及 xarguments,其中包含与任何选项无关的参数。在大多数情况下,我们可以安全地忽略它们。
为了识别短选项(如 -h)和长选项(以 -- 为前缀的选项),getopt.getopt 使用两个单独的参数。短选项列表包含在一个字符串中列出的所有选项,例如,getopt.getopt(sys.argv, 'ahoinmdwq')。可以在该字符串中指定绝对需要参数紧随其后的选项(例如,-vfilename)或在空格之后(例如,-v filename)。这是通过在选项后插入冒号 (:) 来完成的,如下所示:getopt.getopt(sys.argv, 'ahoiv:emwn')。但是,这会产生一个愚蠢的问题,可能会导致一些混淆并无谓地浪费您的时间;如果用户忘记为需要参数的选项指定参数,则紧随其后的选项将成为其参数。考虑这个例子
script.py -v -h
如果您在 getopt.getopt 函数的短选项字符串参数中放入 v:,则选项 -h 将被视为选项 -v 的参数。这是一个麻烦,并且使解析元组列表 选项,参数 变得更加困难。解决此问题的方法很简单:不要使用冒号,而是检查包含需要参数的选项(分析元组的第一项)的元组的第二项。如果它为空,则报告错误,就像 -a 选项处理程序一样。
以 -- 为前缀的长选项必须作为 getopt.getopt 的单独参数列出,例如,getopt.getopt(sys.argv, 'ah', ['view', 'file='])。它们可以由与短选项相同的处理程序提供服务。
在找到用户给出的选项后,您要做什么取决于您自己。清单 2 可以用作脚本的模板。
一个编写正确的应用程序,特别是打开文件进行写入或创建临时文件的应用程序,应该实现中断处理程序,以确保当用户或系统决定停止执行我们的脚本时,不会留下损坏或未删除的文件。
信号,例如在脚本执行期间按下 CTRL-C 时发送的信号,会被处理程序捕获,处理程序可能会忽略它们,允许执行默认处理程序或执行自定义操作。Python 实现了一些默认处理程序,但您可以使用 signal 模块用您自己的代码覆盖它们。
允许我们捕获信号的函数是 signal.signal。它的两个参数是您要捕获的信号的编号和信号处理程序的名称。清单 3 是一个简单的脚本,它捕获在您按下 CTRL-C 时发送给它的 SIGINT 信号(信号编号有其自己的符号等效项)。
SIGINT 信号不是您可以捕获的唯一信号。如果您想捕获其他信号,请添加更多 signal.signal 调用来处理它们,更改信号编号(signal.SIGxxx 常量)和处理程序的名称(可选;您可以将同一处理程序与多个信号一起使用)。要查看 Linux 中有哪些信号可用,请在命令行中键入 kill -l。
信号可以被忽略,如果您想防止其中一些信号干扰脚本的执行,这将非常有用。清单 4 显示了这样做的方法(小心;此脚本无法用 CTRL-C 停止)。
另一个值得记住的信号是 SIGALRM。为该信号设置处理程序允许您在给定的秒数后停止脚本的执行。这是通过 signal.alarm 完成的,如清单 5 所示。
许多脚本需要处理文件。请记住,在您可以读取或写入文件之前,文件必须存在并且已打开。清单 6 是一个打开文件进行读取的脚本示例。写入文件只需要稍作更改(参见清单 7)。
如您所见,清单 6 和 7 中显示的两个脚本中的第一个脚本无法打开文件进行读取(如果文件不存在)。这是正确的行为。第二个脚本尝试打开文件进行写入:如果文件存在,则会截断(即,其内容被删除);如果文件不存在,则会创建文件。这可能并不总是需要的行为。当您想要在文件末尾附加一些数据时,您应该打开文件进行写入,同时保留其原始内容。为此,请将 open 函数的第二个参数从 'w' 更改为 'a'。
文件打开后,我们可以使用以下方法读取或写入文件
read(n):最多从文件中读取 n 个字节(如果省略字节数,将读取整个文件),例如,fi.read(200),它最多读取 200 个字节。
readline:一次读取一行,例如,fi.readline()。
readlines:从文件中读取所有行,例如,fi.readlines()。
write(string):将 string 写入文件,例如,fo.write('alabama')。
writelines(list):将 list 字符串写入文件,例如,fo.writelines(['alaska<\n>', 'california<\n>', 'nevada<\n>'])
当您想要关闭文件时,请使用其 close 方法,例如,fo.close()。
如果您希望脚本创建临时文件,请使用 tempfile 模块。它通过自动创建基于变量 tempdir 和 template 中定义的模板的唯一文件名,简化了创建临时文件的任务。它本身不创建或删除临时文件,但您可以使用类似于清单 8 中使用的方法来实现此目的。
请注意,您需要同时使用 os.O_CREAT 和 os.RDWR 标志来告诉 os.open 函数创建用于读取和写入的临时文件。另外,请记住在退出脚本之前关闭并删除所有创建的临时文件。您将在 Python Library Reference Manual 的 os、posix 和 tempfile 部分找到有关该示例中使用的函数、常量和变量的更多信息。
实现一个在从脚本退出之前删除临时文件的单个处理程序是一个好主意,如清单 9 所示。
许多命令行工具允许我们创建管道来处理数据,并且在您自己的脚本中考虑实现此功能是一个好主意。管道允许我们从脚本的标准输入读取和写入其标准输出,以及从其他命令的标准输出读取和写入其标准输入。
我们在脚本中实现管道所需的一切都存储在 os 和 sys 模块中。让我们教我们的脚本从其自身的标准输入(由 sys.stdin 表示)读取数据,并将其原封不动地复制到其自身的标准输出 (sys.stdout)
#! /usr/local/bin/python import sys sys.stdout.write(sys.stdin.read())
这可以很好地工作,但不允许我们修改出现在脚本标准输入上的数据。这可以通过多种方式实现,具体取决于您想要一次处理多少数据。清单 10 一次读取一行,并在每行的开头插入 #。
如果您使用 read(n) 方法而不是 readline,您可以设置要从标准输入读取的字节数。清单 11 一次读取 256 个字节。
当您想要一次读取整个文件时,需要稍微不同的方法。我们使用 re 模块中的 sub 函数来执行简单的替换。请参阅清单 12。
这就是使用脚本的标准输入和输出所需的所有基本知识。但是,Python 可以读取外部管道的标准输出或写入其标准输入。这次,我们需要使用 os 模块及其 popen 函数。
清单 13 将一百行文本(每行包含 - 字符串)写入管道 sed 's/-/+/g' > output 的标准输入。传递给管道的数据随后由 sed 处理,并最终成为一百行带有 +++ 的文本。您也可以从管道读取。清单 14 向您展示了如何操作。
如果您开发了想要关注的应用程序,并以类似于在典型的 Linux 系统上运行的许多守护程序的方式,在系统日志中留下其活动轨迹,则可以使用 syslog 模块中的 syslog 函数来完成此操作。要启用写入系统日志,请导入 syslog 模块,并在需要在系统日志中记录的那些点添加对 syslog.syslog 函数的调用。有关示例,请参见清单 15。
要查看脚本的输出,请打开另一个 X 终端窗口或切换到另一个控制台并键入
tail -f /var/log/messages
以揭示您的脚本刚刚在做什么。输出看起来像清单 16。
请记住,如果您连续多次将相同的消息发送到系统日志,它将被缓冲,直到系统日志缓冲区中出现不同的消息。它将仅出现一次,并且系统日志中的下一行将指示它重复了多少次。这段代码,
#! /usr/local/bin/python import syslog # some code for a in ['a', 'b', 'c']: syslog.syslog('Hello from Python!')
将生成以下结果
Jan 20 00:04:33 localhost python: Hello from Python! Jan 20 00:04:49 localhost last message repeated 2 times不要将系统日志视为垃圾桶,您可以在其中发送任何类型的垃圾;仅将最重要的信息写入其中。
某些脚本可能需要访问存储在一个或多个环境变量中的信息。在脚本执行时它们的值存储在 os.environ 字典中,在您导入 os 模块后可用。这是打印出脚本执行时设置的所有环境变量的脚本。
#! /usr/local/bin/python import os for a in os.environ.keys(): print a, ' = ', os.environ.[a]
如果您有兴趣检查特定值并在您自己的脚本中使用它,请使用这段代码开始。
#! /usr/local/bin/python import os if os.environ['USER']: print 'Hello, '+os.environ['USER']清单 17
如果您想在脚本运行时修改特定环境变量的值,请使用清单 17 作为指南。
现在您已经掌握了足够的知识来编写一些行为良好的脚本,这些脚本的外观和工作方式与许多其他 Linux 命令类似。我鼓励您阅读 Python Library Reference 并查看仅使用基本 Python 发行版可以实现什么。如果标准 Python 库对您来说还不够,请访问官方 Python 网站,它将揭示大量的可能性和有用的代码包,您可以使用它们来学习和解决您的编程问题。
Jacek Artymiak (artymiak@safenet.pl) 是一位顾问,专门帮助公司和个人将 Linux 用作台式机或个人系统,以完成常见的日常工作。他的其他职业包括作家、记者、网页设计师、计算机图形艺术家和程序员。