title: 模块 create: 2016.12.7 modified: 2016.12.7 tags: python 标准库 sys os

  6

[TOC]

Python的标准安装包括一组模块(module),称为标准库(standard library)。本章将介绍标准库中模块的功能。

1 模块

现在你已经知道如何创建和执行自己的程序(或脚本)了,也学会了怎么用import从外部模块获取函数并且为自己的程序所用:


In [8]:
import math
math.sin(0)


Out[8]:
0.0

怎么编写自己的模块呢?

1.1 模块就是程序

任何Python程序都可以作为模块导入。假如你写了一个如下的程序,并且将它保存为hello.py文件。


In [1]:
#一个简单的模块
#hello.py     
print "Hello, world!"

程序保存的位置很重要,假如保存在c:/python。可以执行下面的代码,告诉解释器在哪里寻找模块了(以Windows目录为例):


In [10]:
import sys
sys.path.append('c:/python')

通过上步告诉解释器:除了从默认的目录中寻找之外,还需要从目录c:/python中寻找模块。完成之后,就能导入自己的模块了:

>>> import hello
Hello, world!

如你所见,在导入模块的时候,其中的代码被执行了。不过,如果再次导入该模块,就什么都不会发生了:
>>> import hello
>>>

为什么这次没用了?因为导入模块并不意味着在导入时执行某些操作(比如打印文本)。它们主要用于定义,比如变量、函数和类等。此外,因为只需要定义这些东西一次,导入模块多次和导入一次的效果是一样的。

1.2 模块用于定义

模块(像类一样)可以保持自己的作用域。这就意味着模块中定义的所有类和函数以及赋值后变量都成为了模块的特性。
1.2.1 在模块中定义函数


In [1]:
#包含函数的简单模块
#hello2.py     
def hello():      
    print "Hello, world!"

可以像下面这样导入:
>>>import hello2
模块会被执行,这意味着hello函数在模块的作用域内被定义了。因此可以通过以下方式来访问函数:
>>>hello2.hello()
Hello, world!

为什么要这样做呢?为什么不在主程序中定义好一切呢?主要原因是代码重用(code reuse)。如果把代码放在模块中,就可以在多个程序中使用这些代码了。因此请记住:为了让代码可重用,请将它模块化!

1.2.2 在模块中添加测试代码
模块用来定义函数、类和其他一些内容,但是有些时候,在模块中添加一些检查模块本身是否正常工作的测试代码是很有用的。如下:


In [ ]:
#带有问题测试代码的简单模块
#hello3.py     
def hello():      
    print "Hello, world!"
#A test:
hello()

>>>import hello3
Hello, world!
>>>hello3.hello()
Hello, world!

如果将hello3作为模块导入,测试代码就会被执行。为了避免这种情况关键在于:“告知”模块本身是作为程序运行还是导入到其他程序。为了实现这一点,需要使用__name__变量:


In [4]:
__name__


Out[4]:
'__main__'

hello3.__name__
'hello3'

如上,在“主程序”中,变量__name__的值是‘__main__’。而在导入的模块中,这个值就被设定为模块的名字。因此,为了让模块的测试代码更加好用,可以将其放置在if语句中:


In [ ]:
#使用条件测试代码的模块
#hello4.py     
def hello():      
    print "Hello, world!"
def test():
    hello()
if __name__=='__main__':
    test()

1.3 包

为了组织好模块,可以将它们分组为包(package)。当模块存储在文件中时(扩展名.py),包就是模块所在的目录。为了让Python将其作为包对待,它必须包含一个命名为__init__.py的文件(模块)。如果将它作为普通模块导入的话,文件的内容就是包的内容。比如有个名为constants的包,文件constants/__init__.py包括语句PI=3.14,那么你可以像下面这么做:


In [ ]:
import constants
print constants.PI

2 探究模块

探索模块最直接的方式就是在Python解释器中研究它们。当然,要做的第一件事就是导入它。比如:


In [5]:
import copy

没有引发异常—所以它是存在的。但是它能做什么?又有什么?

2.1 使用dir

查看模块包含的内容可以使用dir函数,它会将对象(模块的所有函数、类、变量等)的所有特性列出。一些特性以下划线开始—暗示(约定俗成)它们并不是为在模块外部使用而准备的。所以让我们用列表推导式过滤掉它们:


In [13]:
[n for n in dir(copy) if not n.startswith('_')]


Out[13]:
['Error',
 'PyStringMap',
 'copy',
 'deepcopy',
 'dispatch_table',
 'error',
 'name',
 't',
 'weakref']

In [7]:
copy.__name__


Out[7]:
'copy'

In [9]:
copy.__all__


Out[9]:
['Error', 'copy', 'deepcopy']

__all__是在copy模块内部被设置的,如下:
__all__=['Error', 'copy', 'deepcopy']
那么它为什么在那呢?它定义了模块的公有接口(public interface)。更准确地说,它告诉解释器:从模块导入所有名字代表什么含义。如果你使用如下代码:
from copy import *
那么,你只能使用__all__变量中的3个函数。要导入PyStringMap函数的话,你就得显式地实现,比如from copy import PyStringMap。
在编写模块的时候,像设置__all__这样的技术是相对有用的。因为模块中可能会有一大堆其他程序不需要或不想要的变量、函数和类,__all__会“客气地”将它们过滤掉。如果没有设定__all__,用import *语句默认将会输出模块中所有不以下划线开头的全局名称。

2.2 用help获取帮助


In [14]:
help(copy.copy)


Help on function copy in module copy:

copy(x)
    Shallow copy operation on arbitrary Python objects.
    
    See the module's __doc__ string for more info.


In [15]:
copy.copy.__doc__


Out[15]:
"Shallow copy operation on arbitrary Python objects.\n\n    See the module's __doc__ string for more info.\n    "

文档字符串是写在函数开头并且简述函数功能的字符串。这个字符串可以通过函数的__doc__属性引用。模块和类都有文档字符串(写在开头)。
使用help与直接检查文档字符串相比,它的好处在于会获得更多信息,比如函数签名(也就是所带的参数)。

2.3 阅读源代码

要了解模块,是不能脱离源代码的。阅读源代码,是学习Python最好的方式。那么源代码在哪里?如果希望阅读标准模块copy的源代码,可以通过检查模块的__file__属性:


In [17]:
copy.__file__


Out[17]:
'c:\\python27\\lib\\copy.pyc'

注意,一些模块并不包含任何可以阅读的Python源代码。它们可能已经融入到解释器内了(比如sys模块),或者可能是使用C语言写成的。

3 标准库

安装Python后,你就免费获得了很多有用的模块。

3.1 sys

sys模块让你能够访问与Python解释器联系紧密的变量和函数


In [ ]: