初步介绍Python中的pydoc模块和distutils模块
pydoc
Ka-PingYee曾创建了一个相当著名的模块,名叫pydoc(比较而言:pydoc可以做到perldoc所能做的任何事,并且做得更好、更漂亮:-)。对于Python2.1来说,pydoc(以及它支持的inspect)是标准库的一部分。而对于使用Python1.5.2、1.6或者2.0版本的用户来说,下载并安装pydoc也很简单―请立即下载(请参阅参考资料)。
作为提供给阅读这篇Python文章的任何初学者的背景资料,Python一直有些半正式的文档标准。这些标准并没有试图过度地限制开发者,而是给开发者提供“一种明显的写文档的方法。”幸运的是,通常情况下,Python开发者所写的文档比使用其它语言的典型开发者所写的要好得多。
Python文档之所以“优秀”的主要因素是使用所谓的“docstring”。虽然docstring实际上只是一个被称为_doc_的变量,但还是有一个普遍使用的创建它们的快捷方式:只要在模块、函数def、类定义或方法def的头部放入一个简单的由(三重)引号括起来的字符串。此外,还有几个接近标准的模块级的“魔术”变量名被经常使用。尽管那些文档规则不太正式,但几乎所有第三方的模块和标准模块的文档都使用相同的模式。让我们来看一个使用大部分元素的简化示例:
清单1:附带典型文档的模块mymod.py
#!/usr/bin/python """Showofffeaturesof[pydoc]module Thisisasillymoduleto demonstratedocstrings """ __author__='DavidMertz' __version__='1.0' __nonsense__='jabberwocky' classMyClass: """Demonstrateclassdocstrings""" def__init__(self,spam=1,eggs=2): """Setdefaultattributevaluesonly Keywordarguments: spam―aprocessedmeatproduct eggs―afinebreakfastforlumberjacks """ self.spam=spam self.eggs=eggs
pydoc模块利用了Python文档的约定,又使用了一些有关Python导入、继承和其它类似的实用知识。此外,pydoc有绝对的天赋可以使自己在不同的操作模式下被使用(马上就能看到更多有关这个论点的资料)。让我们用一些时间,看看通过OS命令行调用的manpage风格的用法。
假设您已将上述模块mymod安装在您的系统上,但不知道它有什么用处(在示例中并不多)。您可以阅读源代码,不过更简单的方法可能是:
清单2:获取‘manpage'风格的文档
%pydoc.pymymod PythonLibraryDocumentation:modulemymod NAME mymod-Showofffeaturesof[pydoc]module FILE /articles/scratch/cp18/mymod.py DESCRIPTION Thisisasillymoduleto demonstratedocstrings CLASSES MyClass classMyClass |Demonstrateclassdocstrings | |__init__(self,spam=1,eggs=2) |Setdefaultattributevaluesonly | |Keywordarguments: |spam―aprocessedmeatproduct |eggs―afinebreakfastforlumberjacks DATA __author__='DavidMertz' __file__='./mymod.pyc' __name__='mymod' __nonsense__='jabberwocky' __version__='1.0' VERSION 1.0 AUTHOR DavidMertz
根据特定的平台和安装过程,上述样本可能会显示在一个允许滚屏、搜索等功能并突出显示某些关键字的文本查看器中。对于像这样简单的示例,只是比纯粹的阅读源代码好一点。但请考虑一下像下面这样简单的示例:
清单3:检查类的继承结构
%catmymod2.py frommymodimportMyClass classMyClass2(MyClass): """Childclass""" deffoo(self): pass %pydoc.pymymod2.MyClass2 PythonLibraryDocumentation:classMyClass2inmymod2 classMyClass2(mymod.MyClass) |Childclass | |__init__(self,spam=1,eggs=2)frommymod.MyClass | |foo(self)
在这个快速报告中,我们可以知道MyClass2有__init__()和foo()方法(以及相应的参数),哪个方法是类自身实现的以及其它哪些方法是继承而来(以及被继承的类所处的位置)。
另一个美妙的类似于manpage的功能是用来在模块中搜索关键字的-k选项。例如:
清单4:为任务定位适当的模块
%pydoc.py-kuuencode uu-ImplementationoftheUUencodeandUUdecodefunctions. %pydoc.pyuu PythonLibraryDocumentation:moduleuu NAME uu-ImplementationoftheUUencodeandUUdecodefunctions. [...]
pydoc除了它的命令行用法之外,还有其它四种“模式”可以显示被生成的同样的文档。
Shell模式:在Python交互式shell中,您可以导入pydoc的help()函数,这样就能够在不离开交互式会话的情况下获得任何对象的帮助。也可以只输入一个help进入交互式“help解释器”。例如:
清单5:shell模式下的交互式help解释器
#-------Interactiveshellwithhelpenhancements------# >>>frompydocimporthelp >>>importuu >>>help(uu.test) Helponfunctiontestinmoduleuu: test() uuencode/uudecodemainprogram >>>help WelcometoPython2.0!Thisistheonlinehelputility. [...introductorymessageabouthelpshell...] help>
- Web服务器模式:仅使用-p选项,pydoc就会在LOCALHOST上作为一个简单的Web服务器自启动。您可以使用任何Web浏览器浏览所有已安装在现有操作系统上的模块。这个服务器的主页是一张模块列表,根据目录(并用浏览器支持的醒目色块)将它们分组。此外,您查看其文档的每个模块也广泛分布着它导入的函数、方法以及指向任何模块的链接。
- HTML生成器模式:-w选项对于pydoc可以归档的任何文档都能生成HTML文档页面。这些页面与您在Web服务器模式下可能会浏览到的页面本质上是一回事,但页面是静态的,可以进行存档、传输等等。
- TK浏览器模式:-g选项将创建一个和xman或tkman风格很相似的“图形帮助浏览器。”
distutils
对于Python1.6来说,distutils包已经成为标准Python库的一部分。distutils包有两个目的。一方面,distutils希望让最终用户觉得安装新模块、包和工具的过程一致而轻松。另一方面,distutils还希望让新模块、包和工具的开发者觉得创建这些容易安装的分发包很轻松。让我们简要看一下这两个方面。
在最简单的情况下,开发者将已经选择为您特定的平台创建了安装程序。如果是这种情况,您其实根本不需要知道distutils的存在。目前,distutils能够为支持RPM的Linux系统创建RPM,为Win32系统创建WindowsEXE安装程序。虽然这两个平台是主角,但还存在着其它平台,要么开发者可能已经有了适用于您的平台的解决方法(要么有创建一个安装程序的时间和兴趣)。
虽然没有最简单的例子,但幸运的是下一个出色的例子并没有复杂太多。假设您获取了一个支持distutils的源代码分发包,您可以依靠大量的东西(当然,在一切正常的情况下)。分发包的归档文件必须按照标准归档文件格式―通常可以是.zip格式或.tgz/.tar.gz格式(偶尔会是.tbz格式或tar.Z格式,.sit格式支持很快会添加到MacOS中去)。多数时候,Windows用户使用zip格式文件,而Linux/UNIX用户使用tarball格式文件。不过要想在大多数平台上解包大部分的文件格式并不困难。一旦您将归档文件解包了,您就会获得一个文件集合,它被保存在与归档文件同名的目录里。例如:
清单6:将一个[distutils]归档文件解包
E:\Archive\devel>unzip-qDistutils-1_0_2.zip E:\Archive\devel>cdDistutils-1.0.2 E:\Archive\devel\Distutils-1.0.2>ls ThevolumelabelindriveEisARCHIVE. TheVolumeSerialNumberisE825:C814. DirectoryofE:\Archive\devel\Distutils-1.0.2 6-14-010:38a<DIR>0. 6-14-010:38a<DIR>0.. 5-03-016:30p153550CHANGES.txt 5-03-016:32p<DIR>0distutils 5-03-016:32p<DIR>0doc 5-03-016:32p<DIR>0examples 10-02-0011:47p3730MANIFEST.in 5-03-016:32p<DIR>0misc 5-03-016:32p4960PKG-INFO 4-20-012:30p144070README.txt 6-29-0011:45p16150setup.cfg 5-03-016:17p11200setup.py 4-20-012:29p91160TODO 4-11-009:40p8360USAGE.txt
大多数模块分发包的文件和目录会比这个例子中显示的要少。你真正需要的仅仅是文件setup.py,其中包含安装指令。但实际上,大家一致希望目录中有其它文件,这样setup.py就有可以安装的东西了。这里,您需要做的是:
E:\archive\devel\Distutils-1.0.2>pythonsetup.pyinstall
至少那应该是您该做的事情。如果出现问题,请阅读(很可能也包含在setup.py中的)README.txt或README文件。然后,再查阅GregWard的InstallingPythonModules文档。(请参阅参考资料)。
接下来该做什么呢?您可以通过名字来猜测,setup.py其实只是普通的Python脚本,所以当它运行时可以做任何事。但在大多数情况下setup.py会有一种相当固定的格式。可能看上去像这样:
清单7:最小的setup.py安装脚本
#!/usr/bin/envpython """Setupscriptforthesample#1moduledistribution: singletop-levelpurePythonmodule,namedexplicitly in'py_modules'.""" fromdistutils.coreimportsetup setup(#Distributionmeta-data name="sample", version="1.0", description="Distutilssampledistribution#1", #Descriptionofmodulesandpackagesinthedistribution py_modules=['sample'], )
这里真正的工作是由导入的distutils实现,特别是由setup()函数来实现。基本上,setup()函数采用一组包含一列需要安装的东西(除py_modules外还可能有packages或ext_modules或其它东西)的已命名的变量。
distutils的魔力在于创建模块分发包时利用安装时使用的完全相同的setup.py文件。一旦您―模块开发者―创建了一个setup.py脚本(也可能是‘setup.cfg'或其它扩展名)指定了需要安装的东西,创建分发包所要做的全部事情就是(下面的一步或几步):
清单8:创建模块分发包
%pythonsetup.pysdist %pythonsetup.pybdist_wininst %pythonsetup.pybdist_rpm
根据您指定的特定的分发包,您将创建一个标准的归档文件(tarball或zip格式文件,取决于平台类型)或者一个完整的安装程序(像上面讨论过的那样)。
把两者结合在一起
虽然我们还没有完全达到目的,但是Python已经逐步成为最容易使用的编程语言的一种,而且还是最容易使用的编程社区的一种。虽然某些新的工具还有一些需要克服的缺陷,但在普遍意义上,让Python对用户透明这个要求已经实现了。