'''Python Standard Library'''

''翻译: Python 江湖群''

2008-03-28 13:11:51

<<TableOfContents>>

----

[index.html 返回首页]

----

= 1. 核心模块 =
  "Since the functions in the C runtime library are not part of the Win32 API, 
  we believe the number of applications that will be affected by this bug to 
  be very limited."

  - Microsoft, January 1999

----

== 1.1. 介绍 ==
Python 的标准库包括了很多的模块, 从 Python 语言自身特定的类型和声明, 到一些只用于少数程序的不著名的模块. 

本章描述了一些基本的标准库模块. 任何大型 Python 程序都有可能直接或间接地使用到这类模块的大部分. 

=== 1.1.1. 内建函数和异常 ===
下面的这两个模块比其他模块加在一起还要重要: 定义内建函数(例如 len, int, range ...)的 
{{{_ _builtin_ _}}} 模块, 以及定义所有内建异常的 {{{exceptions}}} 模块. 

Python 在启动时导入这两个模块, 使任何程序都能够使用它们. 

=== 1.1.2. 操作系统接口模块 ===
Python 有许多使用了 POSIX 标准 API 和标准 C 语言库的模块. 它们为底层操作系统提供了平台独立的接口. 

这类的模块包括: 提供文件和进程处理功能的 {{{os}}} 模块; 提供平台独立的文件名处理
(分拆目录名, 文件名, 后缀等)的 {{{os.path}}} 模块; 以及时间日期处理相关的 {{{time/datetime}}} 模块. 

{{{
[!Feather注: datetime 为 Py2.3 新增模块, 提供增强的时间处理方法 ]
}}}

延伸一点说, 网络和线程模块同样也可以归为这一个类型. 不过 Python 并没有在所有的平台/版本实现这些. 

=== 1.1.3. 类型支持模块 ===
标准库里有许多用于支持内建类型操作的库. {{{string}}} 模块实现了常用的字符串处理. 
{{{math}}} 模块提供了数学计算操作和常量(pi, e都属于这类常量), {{{cmath}}} 模块为复数提供了和 
{{{math}}} 一样的功能. 

=== 1.1.4. 正则表达式 ===
{{{re}}} 模块为 Python 提供了正则表达式支持. 正则表达式是用于匹配字符串或特定子字符串的
有特定语法的字符串模式. 

=== 1.1.5. 语言支持模块 ===
sys 模块可以让你访问解释器相关参数,比如模块搜索路径,解释器版本号等. 
{{{operator}}} 模块提供了和内建操作符作用相同的函数. {{{copy}}} 模块允许
你复制对象, Python 2.0 新加入的 {{{gc}}} 模块提供了对垃圾收集的相关控制功能. 

----

== 1.2. _ _builtin_ _ 模块 ==
这个模块包含 Python 中使用的内建函数. 一般不用手动导入这个模块; Python会帮你做好一切. 

=== 1.2.1. 使用元组或字典中的参数调用函数 ===
Python允许你实时地创建函数参数列表. 只要把所有的参数放入一个元组中,
然后通过内建的 {{{apply}}} 函数调用函数. 如 [[#eg-1-1|Example 1-1]]. 

==== 1.2.1.1. Example 1-1. 使用 apply 函数 ====
{{{
File: builtin-apply-example-1.py

def function(a, b):
    print a, b

apply(function, ("whither", "canada?"))
apply(function, (1, 2 + 3))

*B*whither canada?
1 5*b*
}}}

要想把关键字参数传递给一个函数, 你可以将一个字典作为 {{{apply}}} 函数的第 3 个参数, 
参考 [[#eg-1-2|Example 1-2]]. 

==== 1.2.1.2. Example 1-2. 使用 apply 函数传递关键字参数 ====
{{{
File: builtin-apply-example-2.py

def function(a, b):
    print a, b

apply(function, ("crunchy", "frog"))
apply(function, ("crunchy",), {"b": "frog"})
apply(function, (), {"a": "crunchy", "b": "frog"})

*B*crunchy frog
crunchy frog
crunchy frog*b*
}}}

{{{apply}}} 函数的一个常见用法是把构造函数参数从子类传递到基类, 
尤其是构造函数需要接受很多参数的时候. 如 [[#eg-1-3|Example 1-3]] 所示. 

==== 1.2.1.3. Example 1-3. 使用 apply 函数调用基类的构造函数 ====
{{{
File: builtin-apply-example-3.py

class Rectangle:
    def _ _init_ _(self, color="white", width=10, height=10):
        print "create a", color, self, "sized", width, "x", height

class RoundedRectangle(Rectangle):
    def _ _init_ _(self, **kw):
        apply(Rectangle._ _init_ _, (self,), kw)

rect = Rectangle(color="green", height=100, width=100)
rect = RoundedRectangle(color="blue", height=20)

*B*create a green <Rectangle instance at 8c8260> sized 100 x 100
create a blue <RoundedRectangle instance at 8c84c0> sized 10 x 20*b*
}}}

Python 2.0 提供了另个方法来做相同的事. 你只需要使用一个传统的函数调用 , 
使用 {{{*}}} 来标记元组, {{{**}}} 来标记字典. 

下面两个语句是等价的:

{{{
result = function(*args, **kwargs)
result = apply(function, args, kwargs)
}}}

=== 1.2.2. 加载和重载模块 ===
如果你写过较庞大的 Python 程序, 那么你就应该知道 {{{import}}} 语句是用来导入外部模块的 
(当然也可以使用 {{{from-import}}} 版本). 不过你可能不知道 {{{import}}} 其实是靠调用内建
函数 {{{_ _import_ _}}} 来工作的. 

通过这个戏法你可以动态地调用函数. 当你只知道模块名称(字符串)的时候, 这将很方便. 
[[#eg-1-4|Example 1-4]] 展示了这种用法, 动态地导入所有以 "{{{-plugin}}}" 结尾的模块. 

==== 1.2.2.1. Example 1-4. 使用 _ _import_ _ 函数加载模块 ====
{{{
File: builtin-import-example-1.py

import glob, os

modules = []

for module_file in glob.glob("*-plugin.py"):
    try:
        module_name, ext = os.path.splitext(os.path.basename(module_file))
        module = _ _import_ _(module_name)
        modules.append(module)
    except ImportError:
        pass # ignore broken modules

# say hello to all modules
for module in modules:
    module.hello()

*B*example-plugin says hello*b*
}}}

注意这个 plug-in 模块文件名中有个 "-" (hyphens). 这意味着你不能使用普通的 {{{import}}} 命令, 因为 Python 的辨识符不允许有 "-" .

[[#eg-1-5|Example 1-5]] 展示了 [[#eg-1-4|Example 1-4]] 中使用的 plug-in .

==== 1.2.2.2. Example 1-5. Plug-in 例子 ====
{{{
File: example-plugin.py

def hello():
    print "example-plugin says hello"
}}}

[[#eg-1-6|Example 1-6]] 展示了如何根据给定模块名和函数名获得想要的函数对象.

==== 1.2.2.3. Example 1-6. 使用 _ _import_ _ 函数获得特定函数 ====
{{{
File: builtin-import-example-2.py

def getfunctionbyname(module_name, function_name):
    module = _ _import_ _(module_name)
    return getattr(module, function_name)

print repr(getfunctionbyname("dumbdbm", "open"))

*B*<function open at 794fa0>*b*
}}}

你也可以使用这个函数实现延迟化的模块导入 (lazy module loading). 例如在 [[#eg-1-7|Example 1-7]] 中
的 {{{string}}} 模块只在第一次使用的时候导入.

==== 1.2.2.4. Example 1-7. 使用 _ _import_ _ 函数实现 延迟导入 ====
{{{
File: builtin-import-example-3.py

class LazyImport:
    def _ _init_ _(self, module_name):
        self.module_name = module_name
        self.module = None
    def _ _getattr_ _(self, name):
        if self.module is None:
            self.module = _ _import_ _(self.module_name)
        return getattr(self.module, name)

string = LazyImport("string")

print string.lowercase

*B*abcdefghijklmnopqrstuvwxyz*b*
}}}

Python 也提供了重新加载已加载模块的基本支持. [Example 1-8 #eg-1-8 会加载 3 次 ''hello.py'' 文件.

==== 1.2.2.5. Example 1-8. 使用 reload 函数 ====
{{{
File: builtin-reload-example-1.py

import hello
reload(hello)
reload(hello)

*B*hello again, and welcome to the show
hello again, and welcome to the show
hello again, and welcome to the show*b*
}}}

reload 直接接受模块作为参数.

{{{
[!Feather 注:  ^ 原句无法理解, 稍后讨论.]
}}}

注意,当你重加载模块时, 它会被重新编译, 新的模块会代替模块字典里的老模块. 但是, 已经用原模块里的类建立的实例仍然使用的是老模块(不会被更新). 

同样地, 使用 {{{from-import}}} 直接创建的到模块内容的引用也是不会被更新的.

=== 1.2.3. 关于名称空间 ===
{{{dir}}} 返回由给定模块, 类, 实例, 或其他类型的所有成员组成的列表. 这可能在交互式 Python 解释器下很有用, 也可以用在其他地方. [[#eg-1-9|Example 1-9]]展示了 {{{dir}}} 函数的用法. 

==== 1.2.3.1. Example 1-9. 使用 dir 函数 ====
{{{
File: builtin-dir-example-1.py

def dump(value):
    print value, "=>", dir(value)

import sys

dump(0)
dump(1.0)
dump(0.0j) # complex number
dump([]) # list
dump({}) # dictionary
dump("string")
dump(len) # function
dump(sys) # module

*B*0 => []
1.0 => []
0j => ['conjugate', 'imag', 'real']
[] => ['append', 'count', 'extend', 'index', 'insert',
    'pop', 'remove', 'reverse', 'sort']
{} => ['clear', 'copy', 'get', 'has_key', 'items',
    'keys', 'update', 'values']
string => []
<built-in function len> => ['_ _doc_ _', '_ _name_ _', '_ _self_ _']
<module 'sys' (built-in)> => ['_ _doc_ _', '_ _name_ _',
    '_ _stderr_ _', '_ _stdin_ _', '_ _stdout_ _', 'argv',
    'builtin_module_names', 'copyright', 'dllhandle',
    'exc_info', 'exc_type', 'exec_prefix', 'executable',
...*b*
}}}

在例子 [[#eg-1-10|Example 1-10]]中定义的 {{{getmember}}} 函数返回给定类定义的所有类级别的属性和方法.

==== 1.2.3.2. Example 1-10. 使用 dir 函数查找类的所有成员 ====
{{{
File: builtin-dir-example-2.py

class A:
    def a(self):
        pass
    def b(self):
        pass

class B(A):
    def c(self):
        pass
    def d(self):
        pass

def getmembers(klass, members=None):
    # get a list of all class members, ordered by class
    if members is None:
        members = []
    for k in klass._ _bases_ _:
        getmembers(k, members)
    for m in dir(klass):
        if m not in members:
            members.append(m)
    return members

print getmembers(A)
print getmembers(B)
print getmembers(IOError)

*B*['_ _doc_ _', '_ _module_ _', 'a', 'b']
['_ _doc_ _', '_ _module_ _', 'a', 'b', 'c', 'd']
['_ _doc_ _', '_ _getitem_ _', '_ _init_ _', '_ _module_ _', '_ _str_ _']*b*
}}}

{{{getmembers}}} 函数返回了一个有序列表. 成员在列表中名称出现的越早, 
它所处的类层次就越高. 如果无所谓顺序的话, 你可以使用字典代替列表. 

{{{
[!Feather 注: 字典是无序的, 而列表和元组是有序的, 网上有关于有序字典的讨论]
}}}

{{{vars}}} 函数与此相似, 它返回的是包含每个成员当前值的字典. 如果你使用不带参数的 {{{vars}}} , 它将返回当前局部名称空间的可见元素(同 {{{locals()}}} 函数 ). 如 [[#eg-1-11|Example 1-11]]所表示. 

==== 1.2.3.3. Example 1-11. 使用 vars 函数 ====
{{{
File: builtin-vars-example-1.py

book = "library2"
pages = 250
scripts = 350


print "the %(book)s book contains more than %(scripts)s scripts" % vars()

*B*the library book contains more than 350 scripts*b*
}}}

=== 1.2.4. 检查对象类型 ===
Python 是一种动态类型语言, 这意味着给一个定变量名可以在不同的场合绑定到不同的类型上. 在接下面例子中, 同样的函数分别被整数, 浮点数, 以及一个字符串调用: 

{{{
def function(value):
    print value
function(1)
function(1.0)
function("one")
}}}
{{{type}}} 函数 (如 [[#eg-1-12|Example 1-12]] 所示) 允许你检查一个变量的类型. 这个函数会返回一个 
''type descriptor (类型描述符)'', 它对于 Python 解释器提供的每个类型都是不同的. 

==== 1.2.4.1. Example 1-12. 使用 type 函数 ====
{{{
File: builtin-type-example-1.py

def dump(value):
    print type(value), value

dump(1)
dump(1.0)
dump("one")

*B*<type 'int'> 1
<type 'float'> 1.0
<type 'string'> one*b*
}}}

每个类型都有一个对应的类型对象, 所以你可以使用 {{{is}}} 操作符 (对象身份?) 来
检查类型. (如 [[#eg-1-13|Example 1-13]]所示).

==== 1.2.4.2. Example 1-13. 对文件名和文件对象使用 type 函数 ====
{{{
File: builtin-type-example-2.py

def load(file):
    if isinstance(file, type("")):
        file = open(file, "rb")
    return file.read()

print len(load("samples/sample.jpg")), "bytes"
print len(load(open("samples/sample.jpg", "rb"))), "bytes"


*B*4672 bytes
4672 bytes*b*
}}}

{{{callable}}} 函数, 如 [[#eg-1-14|Example 1-14]] 所示, 可以检查一个对象是否是可调用的 
(无论是直接调用或是通过 {{{apply}}}). 对于函数, 方法, {{{lambda}}} 函式, 类, 
以及实现了 {{{_ _call_ _}}} 方法的类实例, 它都返回 True. 

==== 1.2.4.3. Example 1-14. 使用 callable 函数 ====
{{{
File: builtin-callable-example-1.py

def dump(function):
    if callable(function):
        print function, "is callable"
    else:
        print function, "is *not* callable"

class A:
    def method(self, value):
        return value

class B(A):
    def _ _call_ _(self, value):
        return value

a = A()
b = B()

dump(0) # simple objects
dump("string")
dump(callable)
dump(dump) # function

dump(A) # classes
dump(B)
dump(B.method)

dump(a) # instances
dump(b)
dump(b.method)

*B*0 is *not* callable
string is *not* callable
<built-in function callable> is callable
<function dump at 8ca320> is callable
A is callable
B is callable
<unbound method A.method> is callable
<A instance at 8caa10> is *not* callable
<B instance at 8cab00> is callable
<method A.method of B instance at 8cab00> is callable*b*
}}}

注意类对象 (A 和 B) 都是可调用的; 如果调用它们, 就产生新的对象(类实例). 但是 A 类的实例不可调用, 因为它的类没有实现 {{{_ _call_ _}}} 方法.

你可以在 {{{operator}}} 模块中找到检查对象是否为某一内建类型(数字, 序列, 或者字典等)
的函数. 但是, 因为创建一个类很简单(比如实现基本序列方法的类), 所以对这些
类型使用显式的类型判断并不是好主意. 

在处理类和实例的时候会复杂些. Python 不会把类作为本质上的类型对待; 相反地, 所有的类都属于一个特殊的类类型(special class type), 所有的类实例属于一个特殊的实例类型(special instance type). 

这意味着你不能使用 {{{type}}} 函数来测试一个实例是否属于一个给定的类; 所有的实例都是同样
的类型! 为了解决这个问题, 你可以使用 {{{isinstance}}} 函数,它会检查一个对象是
不是给定类(或其子类)的实例. [[#eg-1-15|Example 1-15]] 展示了 {{{isinstance}}} 函数的使用.

==== 1.2.4.4. Example 1-15. 使用 isinstance 函数 ====
{{{
File: builtin-isinstance-example-1.py

class A:
    pass

class B:
    pass

class C(A):
    pass

class D(A, B):
    pass

def dump(object):
    print object, "=>",
    if isinstance(object, A):
        print "A",
    if isinstance(object, B):
        print "B",
    if isinstance(object, C):
        print "C",
    if isinstance(object, D):
        print "D",
    print

a = A()
b = B()
c = C()
d = D()

dump(a)
dump(b)
dump(c)
dump(d)
dump(0)
dump("string")

*B*<A instance at 8ca6d0> => A
<B instance at 8ca750> => B
<C instance at 8ca780> => A C
<D instance at 8ca7b0> => A B D
0 =>
string =>*b*
}}}

{{{issubclass}}} 函数与此相似, 它用于检查一个类对象是否与给定类相同, 
或者是给定类的子类. 如 [[#eg-1-16|Example 1-16]] 所示. 

注意, {{{isinstance}}} 可以接受任何对象作为参数, 而 {{{issubclass}}} 函数在接受非类对象参
数时会引发 ''TypeError'' 异常. 

==== 1.2.4.5. Example 1-16. 使用 issubclass 函数 ====
{{{
File: builtin-issubclass-example-1.py

class A:
    pass

class B:
    pass

class C(A):
    pass

class D(A, B):
    pass

def dump(object):
    print object, "=>",
    if issubclass(object, A):
        print "A",
    if issubclass(object, B):
        print "B",
    if issubclass(object, C):
        print "C",
    if issubclass(object, D):
        print "D",
    print

dump(A)
dump(B)
dump(C)
dump(D)
dump(0)
dump("string")

*B*A => A
B => B
C => A C
D => A B D
0 =>
Traceback (innermost last):
  File "builtin-issubclass-example-1.py", line 29, in ?
  File "builtin-issubclass-example-1.py", line 15, in dump
TypeError: arguments must be classes*b*
}}}

=== 1.2.5. 计算 Python 表达式 ===
Python 提供了在程序中与解释器交互的多种方法. 例如 {{{eval}}} 函数将一个字符串
作为 Python 表达式求值. 你可以传递一串文本, 简单的表达式, 或者使用
内建 Python 函数. 如 [[#eg-1-17|Example 1-17]] 所示. 

==== 1.2.5.1. Example 1-17. 使用 eval 函数 ====
{{{
File: builtin-eval-example-1.py

def dump(expression):
    result = eval(expression)
    print expression, "=>", result, type(result)

dump("1")
dump("1.0")
dump("'string'")
dump("1.0 + 2.0")
dump("'*' * 10")
dump("len('world')")

*B*1 => 1 <type 'int'>
1.0 => 1.0 <type 'float'>
'string' => string <type 'string'>
1.0 + 2.0 => 3.0 <type 'float'>
'*' * 10 => ********** <type 'string'>
len('world') => 5 <type 'int'>*b*
}}}

如果你不确定字符串来源的安全性, 那么你在使用 {{{eval}}} 的时候会遇到些麻烦. 例如, 
某个用户可能会使用 {{{_ _import_ _}}} 函数加载 {{{os}}} 模块, 然后从硬盘删除文件 
(如 [[#eg-1-18|Example 1-18]] 所示). 

==== 1.2.5.2. Example 1-18. 使用 eval 函数执行任意命令 ====
{{{
File: builtin-eval-example-2.py

print eval("_ _import_ _('os').getcwd()")
print eval("_ _import_ _('os').remove('file')")

*B*/home/fredrik/librarybook
Traceback (innermost last):
 File "builtin-eval-example-2", line 2, in ?
 File "<string>", line 0, in ?
os.error: (2, 'No such file or directory')*b*
}}}

这里我们得到了一个 ''os.error'' 异常, 这说明 ''Python 事实上在尝试删除文件!''

幸运地是, 这个问题很容易解决. 你可以给 {{{eval}}} 函数传递第 2 
个参数, 一个定义了该表达式求值时名称空间的字典. 
我们测试下, 给函数传递个空字典:

{{{
>>> print eval("_ _import_ _('os').remove('file')", {})
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "<string>", line 0, in ?
os.error: (2, 'No such file or directory')
}}}

呃.... 我们还是得到了个 ''os.error'' 异常.

这是因为 Python 在求值前会检查这个字典, 如果没有发现名称为 {{{_ _builtins_ _}}} 
的变量(复数形式), 它就会添加一个:

{{{
>>> namespace = {}
>>> print eval("_ _import_ _('os').remove('file')", namespace)
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "<string>", line 0, in ?
os.error: (2, 'No such file or directory')
>>> namespace.keys()
['_ _builtins_ _']
}}}

如果你打印这个 namespace 的内容, 你会发现里边有所有的内建函数.

{{{
[!Feather 注: 如果我RP不错的话, 添加的这个_ _builtins_ _就是当前的_ _builtins_ _]
}}}

我们注意到了如果这个变量存在, Python 就不会去添加默认的, 那么我们的解决方法也来了, 
为传递的字典参数加入一个 {{{_ _builtins_ _}}} 项即可. 如 [[#eg-1-19|Example 1-19]] 所示.

==== 1.2.5.3. Example 1-19. 安全地使用 eval 函数求值 ====
{{{
File: builtin-eval-example-3.py

print eval("_ _import_ _('os').getcwd()", {})
print eval("_ _import_ _('os').remove('file')", {"_ _builtins_ _": {}})

*B*/home/fredrik/librarybook
Traceback (innermost last):
  File "builtin-eval-example-3.py", line 2, in ?
  File "<string>", line 0, in ?
NameError: _ _import_ _*b*
}}}

即使这样, 你仍然无法避免针对 CPU 和内存资源的攻击. (比如, 形如 
{{{eval("'*'*1000000*2*2*2*2*2*2*2*2*2")}}} 的语句在执行后会使你的程序耗尽系统资源). 

=== 1.2.6. 编译和执行代码 ===
{{{eval}}} 函数只针对简单的表达式. 如果要处理大块的代码, 你应该使用 {{{compile}}} 和 {{{exec}}} 函数 
(如 [[#eg-1-20|Example 1-20]] 所示). 

==== 1.2.6.1. Example 1-20. 使用 compile 函数检查语法 ====
{{{
File: builtin-compile-example-1.py

NAME = "script.py"

BODY = """
prnt 'owl-stretching time'
"""

try:
    compile(BODY, NAME, "exec")
except SyntaxError, v:
    print "syntax error:", v, "in", NAME

# syntax error: invalid syntax in script.py
}}}

成功执行后, {{{compile}}} 函数会返回一个代码对象, 你可以使用 {{{exec}}} 语句执行它, 
参见 [[#eg-1-21|Example 1-21]] .

==== 1.2.6.2. Example 1-21. 执行已编译的代码 ====
{{{
File: builtin-compile-example-2.py

BODY = """
print 'the ant, an introduction'
"""

code = compile(BODY, "<script>", "exec")

print code

exec code

*B*<code object ? at 8c6be0, file "<script>", line 0>
the ant, an introduction*b*
}}}

使用 [[#eg-1-22|Example 1-22]] 中的类可以在程序执行时实时地生成代码. {{{write}}} 方法用于添加代码, 
{{{indent}}} 和 {{{dedent}}} 方法用于控制缩进结构. 其他部分交给类来处理. 

==== 1.2.6.3. Example 1-22. 简单的代码生成工具 ====
{{{
File: builtin-compile-example-3.py

import sys, string

class CodeGeneratorBackend:
    "Simple code generator for Python"

    def begin(self, tab="\t"):
        self.code = []
        self.tab = tab
        self.level = 0

    def end(self):
        self.code.append("") # make sure there's a newline at the end 
        return compile(string.join(self.code, "\n"), "<code>", "exec")

    def write(self, string):
        self.code.append(self.tab * self.level + string)

    def indent(self):
        self.level = self.level + 1
        # in 2.0 and later, this can be written as: self.level += 1

    def dedent(self):
        if self.level == 0:
            raise SyntaxError, "internal error in code generator"
        self.level = self.level - 1
        # or: self.level -= 1

#
# try it out!

c = CodeGeneratorBackend()
c.begin()
c.write("for i in range(5):")
c.indent()
c.write("print 'code generation made easy!'")
c.dedent()
exec c.end()

*B*code generation made easy!
code generation made easy!
code generation made easy!
code generation made easy!
code generation made easy!*b*
}}}

Python 还提供了 {{{execfile}}} 函数, 一个从文件加载代码, 编译代码, 执行代码的快捷方式. 
[[#eg-1-23|Example 1-23]] 简单地展示了如何使用这个函数. 

==== 1.2.6.4. Example 1-23. 使用 execfile 函数 ====
{{{
File: builtin-execfile-example-1.py

execfile("hello.py")

def EXECFILE(filename, locals=None, globals=None):
    exec compile(open(filename).read(), filename, "exec") in locals, globals

EXECFILE("hello.py")

*B*hello again, and welcome to the show
hello again, and welcome to the show*b*
}}}

[[#eg-1-24|Example 1-24]] 中的代码是 [[#eg-1-23|Example 1-23]] 中使用的 hello.py 文件. 

==== 1.2.6.5. Example 1-24. hello.py 脚本 ====
{{{
File: hello.py

print "hello again, and welcome to the show"
}}}

=== 1.2.7. 从 _ _builtin_ _ 模块重载函数 ===
因为 Python 在检查局部名称空间和模块名称空间前不会检查内建函数, 所以有时候你可能要显式地引用 
{{{_ _builtin_ _}}} 模块. 例如 [[#eg-1-25|Example 1-25]] 重载了内建的 {{{open}}} 函数. 
这时候要想使用原来的 {{{open}}} 函数, 就需要脚本显式地指明模块名称. 

==== 1.2.7.1. Example 1-25. 显式地访问 _ _builtin_ _ 模块中的函数 ====
{{{
File: builtin-open-example-1.py

def open(filename, mode="rb"):
    import _ _builtin_ _
    file = _ _builtin_ _.open(filename, mode)
    if file.read(5) not in("GIF87", "GIF89"):
        raise IOError, "not a GIF file"
    file.seek(0)
    return file

fp = open("samples/sample.gif")
print len(fp.read()), "bytes"

fp = open("samples/sample.jpg")
print len(fp.read()), "bytes"

*B*3565 bytes
Traceback (innermost last):
  File "builtin-open-example-1.py", line 12, in ?
  File "builtin-open-example-1.py", line 5, in open
IOError: not a GIF file*b*
}}}

{{{
[!Feather 注: 明白这个open()函数是干什么的么? 检查一个文件是否是 GIF 文件, 
一般如这类的图片格式都在文件开头有默认的格式. 
另外打开文件推荐使用file()而不是open() , 虽然暂时没有区别]
}}}

----

== 1.3. exceptions 模块 ==
{{{exceptions}}} 模块提供了标准异常的层次结构. Python 启动的时候会自动导入这个模块, 
并且将它加入到 {{{_ _builtin_ _}}} 模块中. 也就是说, 一般不需要手动导入这个模块. 

在 1.5.2 版本时它是一个普通模块, 2.0 以及以后版本成为内建模块. 

该模块定义了以下标准异常:

 * ''Exception'' 是所有异常的基类. 强烈建议(但不是必须)自定义的异常异常也继承这个类. 

 * ''SystemExit(Exception)'' 由 {{{sys.exit}}} 函数引发. 如果它在最顶层没有被 {{{try-except}}} 语句捕获, 
那么解释器将直接关闭而不会显示任何跟踪返回信息. 

 * ''StandardError(Exception)'' 是所有内建异常的基类(除 ''SystemExit'' 外). 

 * ''KeyboardInterrupt(StandardError)'' 在用户按下 Control-C(或其他打断按键)后 被引发. 如果它可能会在你使用 "捕获所有" 的 {{{try-except}}} 语句时导致奇怪的问题. 

 * ''ImportError(StandardError)'' 在 Python 导入模块失败时被引发. 

 * ''EnvironmentError'' 作为所有解释器环境引发异常的基类. (也就是说, 这些异常一般不是由于程序 bug 引起). 

 * ''IOError(EnvironmentError)'' 用于标记 I/O 相关错误. 

 * ''OSError(EnvironmentError)'' 用于标记 {{{os}}} 模块引起的错误. 

 * ''WindowsError(OSError)'' 用于标记 {{{os}}} 模块中 Windows 相关错误. 

 * ''NameError(StandardError)'' 在 Python 查找全局或局部名称失败时被引发. 

 * ''UnboundLocalError(NameError)'' , 当一个局部变量还没有赋值就被使用时, 会引发这个异常. 这个异常只有在2.0及之后的版本有; 早期版本只会引发一个普通的 ''NameError'' . 

 * ''AttributeError(StandardError)'' , 当 Python 寻找(或赋值)给一个实例属性, 方法, 模块功能或其它有效的命名失败时, 会引发这个异常. 

 * ''SyntaxError(StandardError)'' , 当解释器在编译时遇到语法错误, 这个异常就被引发. 

 * (2.0 及以后版本) ''IndentationError(SyntaxError)'' 在遇到非法的缩进时被引发. 该异常只用于 2.0 及以后版本, 之前版本会引发一个 ''SyntaxError'' 异常. 

 * (2.0 及以后版本) ''TabError(IndentationError)'' , 当使用 {{{-tt}}} 选项检查不一致缩进时有可能被引发. 该异常只用于 2.0 及以后版本, 之前版本会引发一个 ''SyntaxError'' 异常. 

 * ''TypeError(StandardError)'' , 当给定类型的对象不支持一个操作时被引发. 

 * ''AssertionError(StandardError)'' 在 {{{assert}}} 语句失败时被引发(即表达式为 false 时). 

 * ''LookupError(StandardError)'' 作为序列或字典没有包含给定索引或键时所引发异常的基类. 

 * ''IndexError(LookupError)'' , 当序列对象使用给定索引数索引失败时(不存在索引对应对象)引发该异常.

 * ''KeyError(LookupError)'' 当字典对象使用给定索引索引失败时(不存在索引对应对象)引发该异常. 

 * ''ArithmeticError(StandardError)'' 作为数学计算相关异常的基类. 

 * ''OverflowError(ArithmeticError)'' 在操作溢出时被引发(例如当一个整数太大, 导致不能符合给定类型). 

 * ''ZeroDivisionError(ArithmeticError)'' , 当你尝试用 0 除某个数时被引发. 

 * ''FloatingPointError(ArithmeticError)'' , 当浮点数操作失败时被引发. 

 * ''ValueError(StandardError)'' , 当一个参数类型正确但值不合法时被引发. 

 * (2.0 及以后版本) ''UnicodeError(ValueError)'' , Unicode 字符串类型相关异常. 只使用在 2.0 及以后版本. 

 * ''RuntimeError(StandardError)'' , 当出现运行时问题时引发, 包括在限制模式下尝试访问外部内容, 未知的硬件问题等等. 

 * ''NotImplementedError(RuntimeError)'' , 用于标记未实现的函数, 或无效的方法. 

 * ''SystemError(StandardError)'' , 解释器内部错误. 该异常值会包含更多的细节 
(经常会是一些深层次的东西, 比如 "{{{eval_code2: NULL globals" )}}}. 
这本书的作者编了 5 年程序都没见过这个错误. (想必是没有用 {{{raise SystemError}}}). 

 * ''MemoryError(StandardError)'' , 当解释器耗尽内存时会引发该异常. 注意只有在底层内存分配抱怨时这个异常才会发生; 如果是在你的旧机器上, 这个异常发生之前系统会陷入混乱的内存交换中. 

你可以创建自己的异常类. 只需要继承内建的 ''Exception'' 类(或者它的任意一个合适的子类)即可, 有需要时可以再重载它的 {{{_ _str_ _}}} 方法. [[#eg-1-26|Example 1-26]] 展示了如何使用 {{{exceptions}}} 模块. 

==== 1.3.0.1. Example 1-26. 使用 exceptions 模块 ====
{{{
File: exceptions-example-1.py

# python imports this module by itself, so the following
# line isn't really needed
# python 会自动导入该模块, 所以以下这行是不必要的
# import exceptions

class HTTPError(Exception):
    # indicates an HTTP protocol error
    def _ _init_ _(self, url, errcode, errmsg):
        self.url = url
        self.errcode = errcode
        self.errmsg = errmsg
    def _ _str_ _(self):
        return (
            "<HTTPError for %s: %s %s>" %
            (self.url, self.errcode, self.errmsg)
            )

try:
    raise HTTPError("http://www.python.org/foo", 200, "Not Found")
except HTTPError, error:
    print "url", "=>", error.url
    print "errcode", "=>", error.errcode
    print "errmsg", "=>", error.errmsg
    raise # reraise exception

*B*url => http://www.python.org/foo
errcode => 200
errmsg => Not Found
Traceback (innermost last):
  File "exceptions-example-1", line 16, in ?
HTTPError: <HTTPError for http://www.python.org/foo: 200 Not Found>*b*
}}}

----

== 1.4. os 模块 ==
这个模块中的大部分函数通过对应平台相关模块实现, 比如 {{{posix}}} 和 
{{{nt. os}}} 模块会在第一次导入的时候自动加载合适的执行模块. 

=== 1.4.1. 处理文件 ===
内建的 {{{open / file}}} 函数用于创建, 打开和编辑文件, 如 [[#eg-1-27|Example 1-27]] 所示. 而 
{{{os}}} 模块提供了重命名和删除文件所需的函数. 

==== 1.4.1.1. Example 1-27. 使用 os 模块重命名和删除文件 ====
{{{
File: os-example-3.py

import os
import string

def replace(file, search_for, replace_with):
    # replace strings in a text file

    back = os.path.splitext(file)[0] + ".bak"
    temp = os.path.splitext(file)[0] + ".tmp"

    try:
        # remove old temp file, if any
        os.remove(temp)
    except os.error:
        pass

    fi = open(file)
    fo = open(temp, "w")

    for s in fi.readlines():
        fo.write(string.replace(s, search_for, replace_with))

    fi.close()
    fo.close()

    try:
        # remove old backup file, if any
        os.remove(back)
    except os.error:
        pass

    # rename original to backup...
    os.rename(file, back)

    # ...and temporary to original
    os.rename(temp, file)

#
# try it out!

file = "samples/sample.txt"

replace(file, "hello", "tjena")
replace(file, "tjena", "hello")
}}}

=== 1.4.2. 处理目录 ===
{{{os}}} 模块也包含了一些用于目录处理的函数. 

{{{listdir}}} 函数返回给定目录中所有文件名(包括目录名)组成的列表, 如 
[[#eg-1-28|Example 1-28]] 所示. 而 Unix 和 Windows 中使用的当前目录和父目录标记(. 和 .. )不包含在此列表中. 

==== 1.4.2.1. Example 1-28. 使用 os 列出目录下的文件 ====
{{{
File: os-example-5.py

import os

for file in os.listdir("samples"):
    print file

*B*sample.au
sample.jpg
sample.wav
...*b*
}}}

{{{getcwd}}} 和 {{{chdir}}} 函数分别用于获得和改变当前工作目录. 如 [[#eg-1-29|Example 1-29]] 所示. 

==== 1.4.2.2. Example 1-29. 使用 os 模块改变当前工作目录 ====
{{{
File: os-example-4.py

import os

# where are we?
cwd = os.getcwd()
print "1", cwd

# go down
os.chdir("samples")
print "2", os.getcwd()

# go back up
os.chdir(os.pardir)
print "3", os.getcwd()

*B*1 /ematter/librarybook
2 /ematter/librarybook/samples
3 /ematter/librarybook*b*
}}}

{{{makedirs}}} 和 {{{removedirs}}} 函数用于创建或删除目录层,如 [[#eg-1-30|Example 1-30]] 所示. 

==== 1.4.2.3. Example 1-30. 使用 os 模块创建/删除多个目录级 ====
{{{
File: os-example-6.py

import os

os.makedirs("test/multiple/levels")

fp = open("test/multiple/levels/file", "w")
fp.write("inspector praline")
fp.close()

# remove the file
os.remove("test/multiple/levels/file")

# and all empty directories above it
os.removedirs("test/multiple/levels")
}}}

{{{removedirs}}} 函数会删除所给路径中最后一个目录下所有的空目录. 
而 {{{mkdir}}} 和 {{{rmdir}}} 函数只能处理单个目录级. 如 [[#eg-1-31|Example 1-31]] 所示.

==== 1.4.2.4. Example 1-31. 使用 os 模块创建/删除目录 ====
{{{
File: os-example-7.py

import os

os.mkdir("test")
os.rmdir("test")

os.rmdir("samples") # this will fail

*B*Traceback (innermost last):
  File "os-example-7", line 6, in ?
OSError: [Errno 41] Directory not empty: 'samples'*b*
}}}

如果需要删除非空目录, 你可以使用 {{{shutil}}} 模块中的 {{{rmtree}}} 函数. 

=== 1.4.3. 处理文件属性 ===
{{{stat}}} 函数可以用来获取一个存在文件的信息, 如 [[#eg-1-32|Example 1-32]] 
所示. 它返回一个类元组对象(stat_result对象, 包含 10 个元素), 
依次是st_mode (权限模式), st_ino (inode number), st_dev (device), 
st_nlink (number of hard links), st_uid (所有者用户 ID), st_gid 
(所有者所在组 ID ), st_size (文件大小, 字节), st_atime (最近一次访问时间), 
st_mtime (最近修改时间), st_ctime (平台相关; Unix下的最近一次元数据/metadata修改时间, 
或者 Windows 下的创建时间) - 以上项目也可作为属性访问. 

{{{
[!Feather 注: 原文为 9 元元组. 另,返回对象并非元组类型,为 struct.]
}}}

==== 1.4.3.1. Example 1-32. 使用 os 模块获取文件属性 ====
{{{
File: os-example-1.py

import os
import time

file = "samples/sample.jpg"

def dump(st):
    mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime = st
    print "- size:", size, "bytes"
    print "- owner:", uid, gid
    print "- created:", time.ctime(ctime)
    print "- last accessed:", time.ctime(atime)
    print "- last modified:", time.ctime(mtime)
    print "- mode:", oct(mode)
    print "- inode/dev:", ino, dev

#
# get stats for a filename

st = os.stat(file)

print "stat", file
dump(st)
print

#
# get stats for an open file

fp = open(file)

st = os.fstat(fp.fileno())

print "fstat", file
dump(st)

*B*stat samples/sample.jpg
- size: 4762 bytes
- owner: 0 0
- created: Tue Sep 07 22:45:58 1999
- last accessed: Sun Sep 19 00:00:00 1999
- last modified: Sun May 19 01:42:16 1996
- mode: 0100666
- inode/dev: 0 2

fstat samples/sample.jpg
- size: 4762 bytes
- owner: 0 0
- created: Tue Sep 07 22:45:58 1999
- last accessed: Sun Sep 19 00:00:00 1999
- last modified: Sun May 19 01:42:16 1996
- mode: 0100666
- inode/dev: 0 0*b*
}}}

返回对象中有些属性在非 Unix 平台下是无意义的, 比如 ({{{st_inode}}} , {{{st_dev}}})为 
Unix 下的为每个文件提供了唯一标识, 但在其他平台可能为任意无意义数据 .

{{{stat}}} 模块包含了很多可以处理该返回对象的常量及函数. 下面的代码展示了其中的一些. 

可以使用 {{{chmod}}} 和 {{{utime}}} 函数修改文件的权限模式和时间属性,如 [[#eg-1-33|Example 1-33]] 所示. 

==== 1.4.3.2. Example 1-33. 使用 os 模块修改文件的权限和时间戳 ====
{{{
File: os-example-2.py

import os
import stat, time

infile = "samples/sample.jpg"
outfile = "out.jpg"

# copy contents
fi = open(infile, "rb")
fo = open(outfile, "wb")

while 1:
    s = fi.read(10000)
    if not s:
        break
    fo.write(s)

fi.close()
fo.close()

# copy mode and timestamp
st = os.stat(infile)
os.chmod(outfile, stat.S_IMODE(st[stat.ST_MODE]))
os.utime(outfile, (st[stat.ST_ATIME], st[stat.ST_MTIME]))

print "original", "=>"
print "mode", oct(stat.S_IMODE(st[stat.ST_MODE]))
print "atime", time.ctime(st[stat.ST_ATIME])
print "mtime", time.ctime(st[stat.ST_MTIME])

print "copy", "=>"
st = os.stat(outfile)
print "mode", oct(stat.S_IMODE(st[stat.ST_MODE]))
print "atime", time.ctime(st[stat.ST_ATIME])
print "mtime", time.ctime(st[stat.ST_MTIME])

*B*original =>
mode 0666
atime Thu Oct 14 15:15:50 1999
mtime Mon Nov 13 15:42:36 1995
copy =>
mode 0666
atime Thu Oct 14 15:15:50 1999
mtime Mon Nov 13 15:42:36 1995*b*
}}}

=== 1.4.4. 处理进程 ===
{{{system}}} 函数在当前进程下执行一个新命令, 并等待它完成, 如 [[#eg-1-34|Example 1-34]] 所示. 

==== 1.4.4.1. Example 1-34. 使用 os 执行操作系统命令 ====
{{{
File: os-example-8.py

import os

if os.name == "nt":
    command = "dir"
else:
    command = "ls -l"

os.system(command)

*B*-rwxrw-r--   1 effbot  effbot        76 Oct  9 14:17 README
-rwxrw-r--   1 effbot  effbot      1727 Oct  7 19:00 SimpleAsyncHTTP.py
-rwxrw-r--   1 effbot  effbot       314 Oct  7 20:29 aifc-example-1.py
-rwxrw-r--   1 effbot  effbot       259 Oct  7 20:38 anydbm-example-1.py
...*b*
}}}

命令通过操作系统的标准 shell 执行, 并返回 shell 的退出状态. 需要注意的是在 Windows 95/98 
下, shell 通常是 {{{command.com}}} , 它的推出状态总是 0. 

  由于 11os.system11 直接将命令传递给 shell , 所以如果你不检查传入参数的时候会很危险 
  (比如命令 {{{os.system("viewer %s" % file)}}}, 将 file 变量设置为 
  "{{{sample.jpg; rm -rf $HOME" ....}}}). 如果不确定参数的安全性, 那么最好使用
  {{{exec}}} 或 {{{spawn}}} 代替(稍后介绍).

{{{exec}}} 函数会使用新进程替换当前进程(或者说是"转到进程"). 在 [[#eg-1-35|Example 1-35]] 中, 
字符串 "goodbye" 永远不会被打印. 

==== 1.4.4.2. Example 1-35. 使用 os 模块启动新进程 ====
{{{
File: os-exec-example-1.py

import os
import sys

program = "python"
arguments = ["hello.py"]

print os.execvp(program, (program,) +  tuple(arguments))
print "goodbye"

*B*hello again, and welcome to the show*b*
}}}

Python 提供了很多表现不同的 {{{exec}}} 函数. [[#eg-1-35|Example 1-35]] 使用的是 
{{{execvp}}} 函数, 它会从标准路径搜索执行程序, 把第二个参数(元组)作为单独的参数传递给程序, 并使用当前的环境变量来运行程序. 其他七个同类型函数请参阅 ''Python Library Reference'' .

在 Unix 环境下, 你可以通过组合使用 {{{exec}}} , {{{fork}}} 以及 {{{wait}}} 函数来从当前程序调用另一个程序, 
如 [[#eg-1-36|Example 1-36]] 所示. {{{fork}}} 函数复制当前进程, {{{wait}}} 函数会等待一个子进程执行结束. 

==== 1.4.4.3. Example 1-36. 使用 os 模块调用其他程序 (Unix) ====
{{{
File: os-exec-example-2.py

import os
import sys

def run(program, *args):
    pid = os.fork()
    if not pid:
        os.execvp(program, (program,) +  args)
    return os.wait()[0]

run("python", "hello.py")

print "goodbye"

*B*hello again, and welcome to the show
goodbye*b*
}}}

{{{fork}}} 函数在子进程返回中返回 0 (这个进程首先从 {{{fork}}} 返回值), 
在父进程中返回一个非 0 的进程标识符(子进程的 PID ). 也就是说, 
只有当我们处于子进程的时候 "{{{not pid}}}" 才为真. 

{{{fork}}} 和 {{{wait}}} 函数在 Windows 上是不可用的, 但是你可以使用 {{{spawn}}} 函数, 
如 [[#eg-1-37|Example 1-37]] 所示. 不过, {{{spawn}}} 不会沿着路径搜索可执行文件, 
你必须自己处理好这些. 

==== 1.4.4.4. Example 1-37. 使用 os 模块调用其他程序 (Windows) ====
{{{
File: os-spawn-example-1.py

import os
import string

def run(program, *args):
    # find executable
    for path in string.split(os.environ["PATH"], os.pathsep):
        file = os.path.join(path, program) + ".exe"
        try:
            return os.spawnv(os.P_WAIT, file, (file,) + args)
        except os.error:
            pass
    raise os.error, "cannot find executable"

run("python", "hello.py")

print "goodbye"

*B*hello again, and welcome to the show
goodbye*b*
}}}

{{{spawn}}} 函数还可用于在后台运行一个程序. [[#eg-1-38|Example 1-38]] 给 {{{run}}} 函数添加了一个可选的 
{{{mode}}} 参数; 当设置为 {{{os.P_NOWAIT}}} 时, 这个脚本不会等待子程序结束, 
默认值 {{{os.P_WAIT}}} 时 {{{spawn}}} 会等待子进程结束. 

其它的标志常量还有 {{{os.P_OVERLAY}}} ,它使得 {{{spawn}}} 的行为和 {{{exec}}} 类似, 
以及 {{{os.P_DETACH}}} , 它在后台运行子进程, 与当前控制台和键盘焦点隔离. 

==== 1.4.4.5. Example 1-38. 使用 os 模块在后台执行程序 (Windows) ====
{{{
File: os-spawn-example-2.py

import os
import string

def run(program, *args, **kw):
    # find executable
    mode = kw.get("mode", os.P_WAIT)
    for path in string.split(os.environ["PATH"], os.pathsep):
        file = os.path.join(path, program) + ".exe"
        try:
            return os.spawnv(mode, file, (file,) + args)
        except os.error:
            pass
    raise os.error, "cannot find executable"

run("python", "hello.py", mode=os.P_NOWAIT)
print "goodbye"

*B*goodbye
hello again, and welcome to the show*b*
}}}

[[#eg-1-39|Example 1-39]] 提供了一个在 Unix 和 Windows 平台上通用的 {{{spawn}}} 方法. 

==== 1.4.4.6. Example 1-39. 使用 spawn 或 fork/exec 调用其他程序 ====
{{{
File: os-spawn-example-3.py

import os
import string

if os.name in ("nt", "dos"):
    exefile = ".exe"
else:
    exefile = ""

def spawn(program, *args):
    try:
        # possible 2.0 shortcut!
        return os.spawnvp(program, (program,) + args)
    except AttributeError:
        pass
    try:
        spawnv = os.spawnv
    except AttributeError:

        # assume it's unix
        pid = os.fork()
        if not pid:
            os.execvp(program, (program,) + args)
        return os.wait()[0]
    else:
        # got spawnv but no spawnp: go look for an executable
        for path in string.split(os.environ["PATH"], os.pathsep):
            file = os.path.join(path, program) + exefile
            try:
                return spawnv(os.P_WAIT, file, (file,) + args)
            except os.error:
                pass
        raise IOError, "cannot find executable"

#
# try it out!

spawn("python", "hello.py")

print "goodbye"

*B*hello again, and welcome to the show
goodbye*b*
}}}

[[#eg-1-39|Example 1-39]] 首先尝试调用 {{{spawnvp}}} 函数. 如果该函数不存在
(一些版本/平台没有这个函数), 它将继续查找一个名为 {{{spawnv}}} 的函数并且
开始查找程序路径. 作为最后的选择, 它会调用 {{{exec}}} 和 {{{fork}}} 函数完成工作. 

=== 1.4.5. 处理守护进程(Daemon Processes) ===
Unix 系统中, 你可以使用 {{{fork}}} 函数把当前进程转入后台(一个"守护者/daemon"). 一般来说, 你需要派生(fork off)一个当前进程的副本, 然后终止原进程, 如 [[#eg-1-40|Example 1-40]] 所示. 

==== 1.4.5.1. Example 1-40. 使用 os 模块使脚本作为守护执行 (Unix) ====
{{{
File: os-example-14.py

import os
import time

pid = os.fork()
if pid:
    os._exit(0) # kill original

print "daemon started"
time.sleep(10)
print "daemon terminated"
}}}

需要创建一个真正的后台程序稍微有点复杂, 首先调用 {{{setpgrp}}} 函数创建一个 "进程组首领/process group leader". 否则, 向无关进程组发送的信号(同时)会引起守护进程的问题: 

{{{
os.setpgrp()
}}}

为了确保守护进程创建的文件能够获得程序指定的 mode flags(权限模式标记?), 最好删除 user mode mask:

{{{
os.umask(0)
}}}

然后, 你应该重定向 ''stdout/stderr'' 文件, 而不能只是简单地关闭它们(如果你的程序需要 {{{stdout}}} 
或 {{{stderr}}} 写入内容的时候, 可能会出现意想不到的问题). 

{{{
class NullDevice:
    def write(self, s):
        pass
sys.stdin.close()
sys.stdout = NullDevice()
sys.stderr = NullDevice()
}}}

换言之, 由于 Python 的 {{{print}}} 和 C 中的 {{{printf/fprintf}}} 在设备(device)
没有连接后不会关闭你的程序, 此时守护进程中的 {{{sys.stdout.write()}}} 会抛出一个 ''IOError'' 异常, 而你的程序依然在后台运行的很好.... 

另外, 先前例子中的 {{{_exit}}} 函数会终止当前进程. 而 {{{sys.exit}}} 不同, 如果调用者(caller)
捕获了 ''SystemExit'' 异常, 程序仍然会继续执行. 如 [[#eg-1-41|Example 1-41]] 所示.

==== 1.4.5.2. Example 1-41. 使用 os 模块终止当前进程 ====
{{{
File: os-example-9.py

import os
import sys

try:
    sys.exit(1)
except SystemExit, value:
    print "caught exit(%s)" % value

try:
    os._exit(2)
except SystemExit, value:
    print "caught exit(%s)" % value

print "bye!"

*B*caught exit(1)*b*
}}}

----

== 1.5. os.path 模块 ==
{{{os.path}}} 模块包含了各种处理长文件名(路径名)的函数. 先导入 (import) {{{os}}} 
模块, 然后就可以以 {{{os.path}}} 访问该模块. 

=== 1.5.1. 处理文件名 ===
{{{os.path}}} 模块包含了许多与平台无关的处理长文件名的函数. 
也就是说, 你不需要处理前后斜杠, 冒号等. 我们可以看看 [[#eg-1-42|Example 1-42]] 中的样例代码. 

==== 1.5.1.1. Example 1-42. 使用 os.path 模块处理文件名 ====
{{{
File: os-path-example-1.py

import os

filename = "my/little/pony"

print "using", os.name, "..."
print "split", "=>", os.path.split(filename)
print "splitext", "=>", os.path.splitext(filename)
print "dirname", "=>", os.path.dirname(filename)
print "basename", "=>", os.path.basename(filename)
print "join", "=>", os.path.join(os.path.dirname(filename),
                                 os.path.basename(filename))

*B*using nt ...
split => ('my/little', 'pony')
splitext => ('my/little/pony', '')
dirname => my/little
basename => pony
join => my/little\pony*b*
}}}

注意这里的 {{{split}}} 只分割出最后一项(不带斜杠).

{{{os.path}}} 模块中还有许多函数允许你简单快速地获知文件名的一些特征,如 [[#eg-1-43|Example 1-43]] 所示。 

==== 1.5.1.2. Example 1-43. 使用 os.path 模块检查文件名的特征 ====
{{{
File: os-path-example-2.py

import os

FILES = (
    os.curdir,
    "/",
    "file",
    "/file",
    "samples",
    "samples/sample.jpg",
    "directory/file",
    "../directory/file",
    "/directory/file"
    )

for file in FILES:
    print file, "=>",
    if os.path.exists(file):
        print "EXISTS",
    if os.path.isabs(file):
        print "ISABS",
    if os.path.isdir(file):
        print "ISDIR",
    if os.path.isfile(file):
        print "ISFILE",
    if os.path.islink(file):
        print "ISLINK",
    if os.path.ismount(file):
        print "ISMOUNT",
    print

*B*. => EXISTS ISDIR
/ => EXISTS ISABS ISDIR ISMOUNT
file =>
/file => ISABS
samples => EXISTS ISDIR
samples/sample.jpg => EXISTS ISFILE
directory/file =>
../directory/file =>
/directory/file => ISABS*b*
}}}

{{{expanduser}}} 函数以与大部分Unix shell相同的方式处理用户名快捷符号(~, 
不过在 Windows 下工作不正常), 如 [[#eg-1-44|Example 1-44]] 所示. 

==== 1.5.1.3. Example 1-44. 使用 os.path 模块将用户名插入到文件名 ====
{{{
File: os-path-expanduser-example-1.py

import os

print os.path.expanduser("~/.pythonrc")

# /home/effbot/.pythonrc
}}}

{{{expandvars}}} 函数将文件名中的环境变量替换为对应值, 如 [[#eg-1-45|Example 1-45]] 所示. 

==== 1.5.1.4. Example 1-45. 使用 os.path 替换文件名中的环境变量 ====
{{{
File: os-path-expandvars-example-1.py

import os

os.environ["USER"] = "user"

print os.path.expandvars("/home/$USER/config")
print os.path.expandvars("$USER/folders")

*B*/home/user/config
user/folders*b*
}}}

=== 1.5.2. 搜索文件系统 ===
{{{walk}}} 函数会帮你找出一个目录树下的所有文件 (如 [[#eg-1-46|Example 1-46]]
 所示). 它的参数依次是目录名, 回调函数, 以及传递给回调函数的数据对象. 

==== 1.5.2.1. Example 1-46. 使用 os.path 搜索文件系统 ====
{{{
File: os-path-walk-example-1.py

import os

def callback(arg, directory, files):
    for file in files:
        print os.path.join(directory, file), repr(arg)

os.path.walk(".", callback, "secret message")

*B*./aifc-example-1.py 'secret message'
./anydbm-example-1.py 'secret message'
./array-example-1.py 'secret message'
...
./samples 'secret message'
./samples/sample.jpg 'secret message'
./samples/sample.txt 'secret message'
./samples/sample.zip 'secret message'
./samples/articles 'secret message'
./samples/articles/article-1.txt 'secret message'
./samples/articles/article-2.txt 'secret message'
...*b*
}}}

{{{walk}}} 函数的接口多少有点晦涩 (也许只是对我个人而言, 我总是记不住参数的顺序). 
[[#eg-1-47|Example 1-47]] 中展示的 {{{index}}} 函数会返回一个文件名列表, 
你可以直接使用 {{{for-in}}} 循环处理文件. 

==== 1.5.2.2. Example 1-47. 使用 os.listdir 搜索文件系统 ====
{{{
File: os-path-walk-example-2.py

import os

def index(directory):
    # like os.listdir, but traverses directory trees
    stack = [directory]
    files = []
    while stack:
        directory = stack.pop()
        for file in os.listdir(directory):
            fullname = os.path.join(directory, file)
            files.append(fullname)
            if os.path.isdir(fullname) and not os.path.islink(fullname):
                stack.append(fullname)
    return files

for file in index("."):
    print file

*B*.\aifc-example-1.py
.\anydbm-example-1.py
.\array-example-1.py
...*b*
}}}

如果你不想列出所有的文件 (基于性能或者是内存的考虑) , [[#eg-1-48|Example 1-48]] 展示了另一种方法. 
这里 ''DirectoryWalker'' 类的行为与序列对象相似, 一次返回一个文件. (generator?) 

==== 1.5.2.3. Example 1-48. 使用 DirectoryWalker 搜索文件系统 ====
{{{
File: os-path-walk-example-3.py

import os

class DirectoryWalker:
    # a forward iterator that traverses a directory tree

    def _ _init_ _(self, directory):
        self.stack = [directory]
        self.files = []
        self.index = 0

    def _ _getitem_ _(self, index):
        while 1:
            try:
                file = self.files[self.index]
                self.index = self.index + 1
            except IndexError:
                # pop next directory from stack
                self.directory = self.stack.pop()
                self.files = os.listdir(self.directory)
                self.index = 0
            else:
                # got a filename
                fullname = os.path.join(self.directory, file)
                if os.path.isdir(fullname) and not os.path.islink(fullname):
                    self.stack.append(fullname)
                return fullname

for file in DirectoryWalker("."):
    print file

*B*.\aifc-example-1.py
.\anydbm-example-1.py
.\array-example-1.py
...*b*
}}}

注意 ''DirectoryWalker'' 类并不检查传递给 {{{_ _getitem_ _}}} 方法的索引值. 
这意味着如果你越界访问序列成员(索引数字过大)的话, 这个类将不能正常工作. 

最后, 如果你需要处理文件大小和时间戳, [[#eg-1-49|Example 1-49]] 给出了一个类, 
它返回文件名和它的 {{{os.stat}}} 属性(一个元组). 这个版本在每个文件上都能节省一次或两次 
{{{stat}}} 调用( {{{os.path.isdir}}} 和 {{{os.path.islink}}} 内部都使用了 {{{stat}}} ), 
并且在一些平台上运行很快. 

==== 1.5.2.4. Example 1-49. 使用 DirectoryStatWalker 搜索文件系统 ====
{{{
File: os-path-walk-example-4.py

import os, stat

class DirectoryStatWalker:
    # a forward iterator that traverses a directory tree, and
    # returns the filename and additional file information

    def _ _init_ _(self, directory):
        self.stack = [directory]
        self.files = []
        self.index = 0

    def _ _getitem_ _(self, index):
        while 1:
            try:
                file = self.files[self.index]
                self.index = self.index + 1
            except IndexError:
                # pop next directory from stack
                self.directory = self.stack.pop()
                self.files = os.listdir(self.directory)
                self.index = 0
            else:
                # got a filename
                fullname = os.path.join(self.directory, file)
                st = os.stat(fullname)
                mode = st[stat.ST_MODE]
                if stat.S_ISDIR(mode) and not stat.S_ISLNK(mode):
                    self.stack.append(fullname)
                return fullname, st

for file, st in DirectoryStatWalker("."):
    print file, st[stat.ST_SIZE]

*B*.\aifc-example-1.py 336
.\anydbm-example-1.py 244
.\array-example-1.py 526*b*
}}}

----

== 1.6. stat 模块 ==
[[#eg-1-50|Example 1-50]] 展示了 {{{stat}}} 模块的基本用法, 
这个模块包含了一些 {{{os.stat}}} 函数中可用的常量和测试函数.

==== 1.6.0.1. Example 1-50. Using the stat Module ====
{{{
File: stat-example-1.py

import stat
import os, time

st = os.stat("samples/sample.txt")

print "mode", "=>", oct(stat.S_IMODE(st[stat.ST_MODE]))

print "type", "=>",
if stat.S_ISDIR(st[stat.ST_MODE]):
    print "DIRECTORY",
if stat.S_ISREG(st[stat.ST_MODE]):
    print "REGULAR",
if stat.S_ISLNK(st[stat.ST_MODE]):
    print "LINK",
print

print "size", "=>", st[stat.ST_SIZE]

print "last accessed", "=>", time.ctime(st[stat.ST_ATIME])
print "last modified", "=>", time.ctime(st[stat.ST_MTIME])
print "inode changed", "=>", time.ctime(st[stat.ST_CTIME])

*B*mode => 0664
type => REGULAR
size => 305
last accessed => Sun Oct 10 22:12:30 1999
last modified => Sun Oct 10 18:39:37 1999
inode changed => Sun Oct 10 15:26:38 1999*b*
}}}

----

== 1.7. string 模块 ==
{{{string}}} 模块提供了一些用于处理字符串类型的函数, 
如 [[#eg-1-51|Example 1-51]] 所示.

==== 1.7.0.1. Example 1-51. 使用 string 模块 ====
{{{
File: string-example-1.py

import string

text = "Monty Python's Flying Circus"

print "upper", "=>", string.upper(text)
print "lower", "=>", string.lower(text)
print "split", "=>", string.split(text)
print "join", "=>", string.join(string.split(text), "+")
print "replace", "=>", string.replace(text, "Python", "Java")
print "find", "=>", string.find(text, "Python"), string.find(text, "Java")
print "count", "=>", string.count(text, "n")

*B*upper => MONTY PYTHON'S FLYING CIRCUS
lower => monty python's flying circus
split => ['Monty', "Python's", 'Flying', 'Circus']
join => Monty+Python's+Flying+Circus
replace => Monty Java's Flying Circus
find => 6 -1
count => 3*b*
}}}

在 Python 1.5.2 以及更早版本中, {{{string}}} 使用 {{{strop}}} 中的函数来实现模块功能. 

在 Python1.6 和后继版本,更多的字符串操作都可以作为字符串方法来访问, 
如 [[#eg-1-52|Example 1-52]] 所示, {{{string}}} 模块中的许多函数只是对相对应字符串方法的封装.

==== 1.7.0.2. Example 1-52. 使用字符串方法替代 string 模块函数 ====
{{{
File: string-example-2.py

text = "Monty Python's Flying Circus"

print "upper", "=>", text.upper()
print "lower", "=>", text.lower()
print "split", "=>", text.split()
print "join", "=>", "+".join(text.split())
print "replace", "=>", text.replace("Python", "Perl")
print "find", "=>", text.find("Python"), text.find("Perl")
print "count", "=>", text.count("n")

*B*upper => MONTY PYTHON'S FLYING CIRCUS
lower => monty python's flying circus
split => ['Monty', "Python's", 'Flying', 'Circus']
join => Monty+Python's+Flying+Circus
replace => Monty Perl's Flying Circus
find => 6 -1
count => 3*b*
}}}

为了增强模块对字符的处理能力, 除了字符串方法, {{{string}}} 
模块还包含了类型转换函数用于把字符串转换为其他类型, (如 [[#eg-1-53|Example 1-53]] 所示).

==== 1.7.0.3. Example 1-53. 使用 string 模块将字符串转为数字 ====
{{{
File: string-example-3.py

import string

print int("4711"),
print string.atoi("4711"),
print string.atoi("11147", 8), # octal 八进制
print string.atoi("1267", 16), # hexadecimal 十六进制
print string.atoi("3mv", 36) # whatever...

print string.atoi("4711", 0),
print string.atoi("04711", 0),
print string.atoi("0x4711", 0)

print float("4711"),
print string.atof("1"),
print string.atof("1.23e5")

*B*4711 4711 4711 4711 4711
4711 2505 18193
4711.0 1.0 123000.0*b*
}}}

大多数情况下 (特别是当你使用的是1.6及更高版本时) ,你可以使用 {{{int}}} 和 {{{float}}} 
函数代替 {{{string}}} 模块中对应的函数。 

{{{atoi}}} 函数可以接受可选的第二个参数, 指定数基(number base). 
如果数基为 0, 那么函数将检查字符串的前几个字符来决定使用的数基: 
如果为 "0x," 数基将为 16 (十六进制), 如果为 "0," 则数基为 8 (八进制). 
默认数基值为 10 (十进制), 当你未传递参数时就使用这个值.

在 1.6 及以后版本中, {{{int}}} 函数和 {{{atoi}}} 一样可以接受第二个参数. 
与字符串版本函数不一样的是 , {{{int}}} 和 {{{float}}} 可以接受 Unicode 字符串对象.

----

== 1.8. re 模块 ==
  "Some people, when confronted with a problem, think 'I know, I'll use regular expressions.' Now they have two problems."

  - Jamie Zawinski, on comp.lang.emacs

{{{re}}} 模块提供了一系列功能强大的正则表达式 (regular expression) 工具, 
它们允许你快速检查给定字符串是否与给定的模式匹配 (使用 {{{match}}} 函数), 
或者包含这个模式 (使用 {{{search}}} 函数). 正则表达式是以紧凑(也很神秘)的语法写出的字符串模式. 

{{{match}}} 尝试从字符串的起始匹配一个模式, 如 [[#eg-1-54|Example 1-54]] 所示. 
如果模式匹配了某些内容 (包括空字符串, 如果模式允许的话) , 
它将返回一个匹配对象. 使用它的 {{{group}}} 方法可以找出匹配的内容. 

==== 1.8.0.1. Example 1-54. 使用 re 模块来匹配字符串 ====
{{{
File: re-example-1.py

import re

text = "The Attila the Hun Show"

# a single character 单个字符
m = re.match(".", text)
if m: print repr("."), "=>", repr(m.group(0))

# any string of characters 任何字符串
m = re.match(".*", text)
if m: print repr(".*"), "=>", repr(m.group(0))

# a string of letters (at least one) 只包含字母的字符串(至少一个)
m = re.match("\w+", text)
if m: print repr("\w+"), "=>", repr(m.group(0))

# a string of digits 只包含数字的字符串
m = re.match("\d+", text)
if m: print repr("\d+"), "=>", repr(m.group(0))

*B* '.' => 'T'
'.*' => 'The Attila the Hun Show'
'\\w+' => 'The'*b*
}}}

可以使用圆括号在模式中标记区域. 找到匹配后, {{{group}}} 方法可以抽取这些区域的内容,
如 [[#eg-1-55|Example 1-55]] 所示. {{{group(1)}}} 会返回第一组的内容, {{{group(2)}}} 
返回第二组的内容, 这样... 如果你传递多个组数给 {{{group}}} 函数, 它会返回一个元组. 

==== 1.8.0.2. Example 1-55. 使用 re 模块抽出匹配的子字符串 ====
{{{
File: re-example-2.py

import re

text ="10/15/99"

m = re.match("(\d{2})/(\d{2})/(\d{2,4})", text)
if m:
    print m.group(1, 2, 3)

*B*('10', '15', '99')*b*
}}}

{{{search}}} 函数会在字符串内查找模式匹配, 如 [[#eg-1-56|Example 1-56]] 所示. 
它在所有可能的字符位置尝试匹配模式, 从最左边开始, 一旦找到匹配就返回一个匹配对象. 
如果没有找到相应的匹配, 就返回 ''None'' . 

==== 1.8.0.3. Example 1-56. 使用 re 模块搜索子字符串 ====
{{{
File: re-example-3.py

import re

text = "Example 3: There is 1 date 10/25/95 in here!"

m = re.search("(\d{1,2})/(\d{1,2})/(\d{2,4})", text)

print m.group(1), m.group(2), m.group(3)

month, day, year = m.group(1, 2, 3)
print month, day, year

date = m.group(0)
print date

*B*10 25 95
10 25 95
10/25/95*b*
}}}

[[#eg-1-57|Example 1-57]] 中展示了 {{{sub}}} 函数, 它可以使用另个字符串替代匹配模式.

==== 1.8.0.4. Example 1-57. 使用 re 模块替换子字符串 ====
{{{
File: re-example-4.py

import re

text = "you're no fun anymore..."

# literal replace (string.replace is faster)
# 文字替换 (string.replace 速度更快)
print re.sub("fun", "entertaining", text)

# collapse all non-letter sequences to a single dash 
# 将所有非字母序列转换为一个"-"(dansh,破折号)
print re.sub("[^\w]+", "-", text)

# convert all words to beeps 
# 将所有单词替换为 BEEP
print re.sub("\S+", "-BEEP-", text)

*B*you're no entertaining anymore...
you-re-no-fun-anymore-
-BEEP- -BEEP- -BEEP- -BEEP-*b*
}}}

你也可以通过回调 (callback) 函数使用 {{{sub}}} 来替换指定模式. 
[[#eg-1-58|Example 1-58]] 展示了如何预编译模式. 

==== 1.8.0.5. Example 1-58. 使用 re 模块替换字符串(通过回调函数) ====
{{{
File: re-example-5.py

import re
import string

text = "a line of text\\012another line of text\\012etc..."

def octal(match):
    # replace octal code with corresponding ASCII character
    # 使用对应 ASCII 字符替换八进制代码
    return chr(string.atoi(match.group(1), 8))

octal_pattern = re.compile(r"\\(\d\d\d)")

print text
print octal_pattern.sub(octal, text)

*B*a line of text\012another line of text\012etc...
a line of text
another line of text
etc...*b*
}}}

如果你不编译, {{{re}}} 模块会为你缓存一个编译后版本, 所有的小脚本中, 
通常不需要编译正则表达式. Python1.5.2 中, 缓存中可以容纳 20 个匹配模式, 而在 2.0 中, 
缓存则可以容纳 100 个匹配模式. 

最后, [[#eg-1-59|Example 1-59]] 用一个模式列表匹配一个字符串. 这些模式将会组合为一个模式, 并预编译以节省时间. 

==== 1.8.0.6. Example 1-59. 使用 re 模块匹配多个模式中的一个 ====
{{{
File: re-example-6.py

import re, string

def combined_pattern(patterns):
    p = re.compile(
        string.join(map(lambda x: "("+x+")", patterns), "|")
        )
    def fixup(v, m=p.match, r=range(0,len(patterns))):
        try:
            regs = m(v).regs
        except AttributeError:
            return None # no match, so m.regs will fail
        else:
            for i in r:
                if regs[i+1] != (-1, -1):
                    return i
    return fixup

#
# try it out!

patterns = [
    r"\d+",
    r"abc\d{2,4}",
    r"p\w+"
]

p = combined_pattern(patterns)

print p("129391")
print p("abc800")
print p("abc1600")
print p("python")
print p("perl")
print p("tcl")

*B*0
1
1
2
2
None*b*
}}}

----

== 1.9. math 模块 ==
{{{math}}} 模块实现了许多对浮点数的数学运算函数. 这些函数一般是对平台 C 
库中同名函数的简单封装, 所以一般情况下, 不同平台下计算的结果可能稍微地有所不同, 
有时候甚至有很大出入. [[#eg-1-60|Example 1-60]] 展示了如何使用 {{{math}}} 模块.

==== 1.9.0.1. Example 1-60. 使用 math 模块 ====
{{{
File: math-example-1.py

import math

print "e", "=>", math.e
print "pi", "=>", math.pi
print "hypot", "=>", math.hypot(3.0, 4.0)

# and many others...

*B*e => 2.71828182846
pi => 3.14159265359
hypot => 5.0*b*
}}}

完整函数列表请参阅 ''Python Library Reference'' .

----

== 1.10. cmath 模块 ==
[[#eg-1-61|Example 1-61]] 所展示的 {{{cmath}}} 模块包含了一些用于复数运算的函数.

==== 1.10.0.1. Example 1-61. 使用 cmath 模块 ====
{{{
File: cmath-example-1.py

import cmath

print "pi", "=>", cmath.pi
print "sqrt(-1)", "=>", cmath.sqrt(-1)

pi => 3.14159265359
sqrt(-1) => 1j
}}}

完整函数列表请参阅 ''Python Library Reference'' .

----

== 1.11. operator 模块 ==
{{{operator}}} 模块为 Python 提供了一个 "功能性" 的标准操作符接口. 当使用 {{{map}}} 以及 
{{{filter}}} 一类的函数的时候, {{{operator}}} 模块中的函数可以替换一些 {{{lambda}}} 函式. 
而且这些函数在一些喜欢写晦涩代码的程序员中很流行. [[#eg-1-62|Example 1-62]] 展示了 
{{{operator}}} 模块的一般用法.

==== 1.11.0.1. Example 1-62. 使用 operator 模块 ====
{{{
File: operator-example-1.py

import operator

sequence = 1, 2, 4

print "add", "=>", reduce(operator.add, sequence)
print "sub", "=>", reduce(operator.sub, sequence)
print "mul", "=>", reduce(operator.mul, sequence)
print "concat", "=>", operator.concat("spam", "egg")
print "repeat", "=>", operator.repeat("spam", 5)
print "getitem", "=>", operator.getitem(sequence, 2)
print "indexOf", "=>", operator.indexOf(sequence, 2)
print "sequenceIncludes", "=>", operator.sequenceIncludes(sequence, 3)

*B*add => 7
sub => -5
mul => 8
concat => spamegg
repeat => spamspamspamspamspam

getitem => 4
indexOf => 1
sequenceIncludes => 0*b*
}}}

[[#eg-1-63|Example 1-63]] 展示了一些可以用于检查对象类型的 {{{operator}}} 函数.

==== 1.11.0.2. Example 1-63. 使用 operator 模块检查类型 ====
{{{
File: operator-example-2.py

import operator
import UserList

def dump(data):
    print type(data), "=>",
    if operator.isCallable(data):
        print "CALLABLE",
    if operator.isMappingType(data):
        print "MAPPING",
    if operator.isNumberType(data):
        print "NUMBER",
    if operator.isSequenceType(data):
        print "SEQUENCE",
    print
        
dump(0)
dump("string")
dump("string"[0])
dump([1, 2, 3])
dump((1, 2, 3))
dump({"a": 1})
dump(len) # function 函数
dump(UserList) # module 模块
dump(UserList.UserList) # class 类
dump(UserList.UserList()) # instance 实例

*B*<type 'int'> => NUMBER
<type 'string'> => SEQUENCE
<type 'string'> => SEQUENCE
<type 'list'> => SEQUENCE
<type 'tuple'> => SEQUENCE
<type 'dictionary'> => MAPPING
<type 'builtin_function_or_method'> => CALLABLE
<type 'module'> =>
<type 'class'> => CALLABLE
<type 'instance'> => MAPPING NUMBER SEQUENCE*b*
}}}

这里需要注意 {{{operator}}} 模块使用非常规的方法处理对象实例. 所以使用 
{{{isNumberType}}} , {{{isMappingType}}} , 以及 {{{isSequenceType}}} 函数的时候要小心, 
这很容易降低代码的扩展性.

同样需要注意的是一个字符串序列成员 (单个字符) 也是序列. 所以当在递归函数使用 isSequenceType 来截断对象树的时候, 别把普通字符串作为参数(或者是任何包含字符串的序列对象).

----

== 1.12. copy 模块 ==
{{{copy}}} 模块包含两个函数, 用来拷贝对象, 如 [[#eg-1-64|Example 1-64]] 所示. 

{{{copy(object) => object}}} 创建给定对象的 "浅/浅层(shallow)" 拷贝(copy). 这里 
"浅/浅层(shallow)" 的意思是复制对象本身, 但当对象是一个容器 (container) 时, 
它的成员仍然指向原来的成员对象. 

==== 1.12.0.1. Example 1-64. 使用 copy 模块复制对象 ====
{{{
File: copy-example-1.py

import copy

a = [[1],[2],[3]]
b = copy.copy(a)

print "before", "=>"
print a
print b

# modify original
a[0][0] = 0
a[1] = None

print "after", "=>"
print a
print b

*B*before =>
[[1], [2], [3]]
[[1], [2], [3]]
after =>
[[0], None, [3]]
[[0], [2], [3]]*b*
}}}

你也可以使用[:]语句 (完整切片) 来对列表进行浅层复制, 也可以使用 {{{copy}}} 方法复制字典. 

相反地, {{{deepcopy(object) => object}}} 创建一个对象的深层拷贝(deepcopy), 
如 [[#eg-1-65|Example 1-65]] 所示, 当对象为一个容器时, 所有的成员都被递归地复制了。 

==== 1.12.0.2. Example 1-65. 使用 copy 模块复制集合(Collections) ====
{{{
File: copy-example-2.py

import copy

a = [[1],[2],[3]]
b = copy.deepcopy(a)

print "before", "=>"
print a
print b

# modify original
a[0][0] = 0
a[1] = None

print "after", "=>"
print a
print b

*B*before =>
[[1], [2], [3]]
[[1], [2], [3]]
after =>
[[0], None, [3]]
[[1], [2], [3]]*b*
}}}

----

== 1.13. sys 模块 ==
{{{sys}}} 模块提供了许多函数和变量来处理 Python 运行时环境的不同部分.

=== 1.13.1. 处理命令行参数 ===
在解释器启动后, {{{argv}}} 列表包含了传递给脚本的所有参数, 如 [[#eg-1-66|Example 1-66]] 所示. 
列表的第一个元素为脚本自身的名称.

==== 1.13.1.1. Example 1-66. 使用sys模块获得脚本的参数 ====
{{{
File: sys-argv-example-1.py

import sys

print "script name is", sys.argv[0]

if len(sys.argv) > 1:
    print "there are", len(sys.argv)-1, "arguments:"
    for arg in sys.argv[1:]:
        print arg
else:
    print "there are no arguments!"

*B*script name is sys-argv-example-1.py
there are no arguments!*b*
}}}

如果是从标准输入读入脚本 (比如 "{{{python < sys-argv-example-1.py}}}"), 
脚本的名称将被设置为空串. 如果把脚本作为字符串传递给python (使用 {{{-c}}} 选项), 
脚本名会被设置为 "-c".

=== 1.13.2. 处理模块 ===
{{{path}}} 列表是一个由目录名构成的列表, Python 从中查找扩展模块( Python 源模块, 编译模块,或者二进制扩展). 
启动 Python 时,这个列表从根据内建规则, PYTHONPATH 环境变量的内容, 以及注册表( Windows 系统)等进行初始化. 
由于它只是一个普通的列表, 你可以在程序中对它进行操作, 如 [[#eg-1-67|Example 1-67]] 所示.

==== 1.13.2.1. Example 1-67. 使用sys模块操作模块搜索路径 ====
{{{
File: sys-path-example-1.py

import sys

print "path has", len(sys.path), "members"

# add the sample directory to the path
sys.path.insert(0, "samples")
import sample

# nuke the path
sys.path = []
import random # oops!

*B*path has 7 members
this is the sample module!
Traceback (innermost last):
  File "sys-path-example-1.py", line 11, in ?
    import random # oops!
ImportError: No module named random*b*
}}}

{{{builtin_module_names}}} 列表包含 Python 解释器中所有内建模块的名称, [[#eg-1-68|Example 1-68]] 
 给出了它的样例代码.

==== 1.13.2.2. Example 1-68. 使用sys模块查找内建模块 ====
{{{
File: sys-builtin-module-names-example-1.py

import sys

def dump(module):
    print module, "=>",
    if module in sys.builtin_module_names:
        print "<BUILTIN>"
    else:
        module = _ _import_ _(module)
        print module._ _file_ _

dump("os")
dump("sys")
dump("string")
dump("strop")
dump("zlib")

*B*os => C:\python\lib\os.pyc
sys => <BUILTIN>
string => C:\python\lib\string.pyc
strop => <BUILTIN>
zlib => C:\python\zlib.pyd*b*
}}}

{{{modules}}} 字典包含所有加载的模块. {{{import}}} 语句在从磁盘导入内容之前会先检查这个字典.

正如你在 [[#eg-1-69|Example 1-69]] 中所见到的, Python 在处理你的脚本之前就已经导入了很多模块.

==== 1.13.2.3. Example 1-69. 使用sys模块查找已导入的模块 ====
{{{
File: sys-modules-example-1.py

import sys

print sys.modules.keys()

*B*['os.path', 'os', 'exceptions', '_ _main_ _', 'ntpath', 'strop', 'nt',
'sys', '_ _builtin_ _', 'site', 'signal', 'UserDict', 'string', 'stat']*b*
}}}

=== 1.13.3. 处理引用记数 ===
{{{getrefcount}}} 函数 (如 [[#eg-1-70|Example 1-70]] 所示) 返回给定对象的引用记数 - 
也就是这个对象使用次数. Python 会跟踪这个值, 当它减少为0的时候, 就销毁这个对象.

==== 1.13.3.1. Example 1-70. 使用sys模块获得引用记数 ====
{{{
File: sys-getrefcount-example-1.py

import sys

variable = 1234

print sys.getrefcount(0)
print sys.getrefcount(variable)
print sys.getrefcount(None)

*B*50
3
192*b*
}}}

注意这个值总是比实际的数量大, 因为该函数本身在确定这个值的时候依赖这个对象.

== 检查主机平台===

[[#eg-1-71|Example 1-71]] 展示了 {{{platform}}} 变量, 它包含主机平台的名称.

==== 1.13.3.2. Example 1-71. 使用sys模块获得当前平台 ====
{{{
File: sys-platform-example-1.py

import sys

#
# emulate "import os.path" (sort of)...

if sys.platform == "win32":
    import ntpath
    pathmodule = ntpath
elif sys.platform == "mac":
    import macpath
    pathmodule = macpath
else:
    # assume it's a posix platform
    import posixpath
    pathmodule = posixpath

print pathmodule
}}}

典型的平台有Windows 9X/NT(显示为 {{{win32}}} ), 以及 Macintosh(显示为 {{{mac}}} ) . 
对于 Unix 系统而言, platform 通常来自 "{{{uname -r}}}" 命令的输出, 例如 {{{irix6}}} , {{{linux2}}} , 
或者 {{{sunos5}}} (Solaris).

=== 1.13.4. 跟踪程序 ===
{{{setprofiler}}} 函数允许你配置一个分析函数(profiling function). 
这个函数会在每次调用某个函数或方法时被调用(明确或隐含的), 
或是遇到异常的时候被调用. 让我们看看 [[#eg-1-72|Example 1-72]] 的代码.

==== 1.13.4.1. Example 1-72. 使用sys模块配置分析函数 ====
{{{
File: sys-setprofiler-example-1.py

import sys

def test(n):
    j = 0
    for i in range(n):
        j = j + i
    return n

def profiler(frame, event, arg):
    print event, frame.f_code.co_name, frame.f_lineno, "->", arg

# profiler is activated on the next call, return, or exception
# 分析函数将在下次函数调用, 返回, 或异常时激活
sys.setprofile(profiler)

# profile this function call
# 分析这次函数调用
test(1)

# disable profiler
# 禁用分析函数
sys.setprofile(None)

# don't profile this call
# 不会分析这次函数调用
test(2)

*B*call test 3 -> None
return test 7 -> 1*b*
}}}

基于该函数, {{{profile}}} 模块提供了一个完整的分析器框架. 

[[#eg-1-73|Example 1-73]] 中的 {{{settrace}}} 函数与此类似, 
但是 {{{trace}}} 函数会在解释器每执行到新的一行时被调用.

==== 1.13.4.2. Example 1-73. 使用sys模块配置单步跟踪函数 ====
{{{
File: sys-settrace-example-1.py

import sys

def test(n):
    j = 0
    for i in range(n):
        j = j + i
    return n

def tracer(frame, event, arg):
    print event, frame.f_code.co_name, frame.f_lineno, "->", arg
    return tracer

# tracer is activated on the next call, return, or exception
# 跟踪器将在下次函数调用, 返回, 或异常时激活
sys.settrace(tracer)

# trace this function call
# 跟踪这次函数调用
test(1)

# disable tracing
# 禁用跟踪器
sys.settrace(None)

# don't trace this call
# 不会跟踪这次函数调用
test(2)

*B*call test 3 -> None
line test 3 -> None
line test 4 -> None
line test 5 -> None
line test 5 -> None
line test 6 -> None
line test 5 -> None
line test 7 -> None
return test 7 -> 1*b*
}}}

基于该函数提供的跟踪功能, {{{pdb}}} 模块提供了完整的调试( debug )框架. 

=== 1.13.5. 处理标准输出/输入 ===
{{{stdin}}} , {{{stdout}}} , 以及 {{{stderr}}} 变量包含与标准 I/O 流对应的流对象. 
如果需要更好地控制输出,而 {{{print}}} 不能满足你的要求, 它们就是你所需要的. 
你也可以 ''替换'' 它们, 这时候你就可以重定向输出和输入到其它设备( device ), 
或者以非标准的方式处理它们. 如 [[#eg-1-74|Example 1-74]] 所示.

==== 1.13.5.1. Example 1-74. 使用sys重定向输出 ====
{{{
File: sys-stdout-example-1.py

import sys
import string

class Redirect:

    def _ _init_ _(self, stdout):
        self.stdout = stdout

    def write(self, s):
        self.stdout.write(string.lower(s))

# redirect standard output (including the print statement)
# 重定向标准输出(包括print语句)
old_stdout = sys.stdout
sys.stdout = Redirect(sys.stdout)

print "HEJA SVERIGE",
print "FRISKT HUM\303\226R"

# restore standard output
# 恢复标准输出
sys.stdout = old_stdout

print "M\303\205\303\205\303\205\303\205L!"

*B*heja sverige friskt hum\303\266r
M\303\205\303\205\303\205\303\205L!*b*
}}}

要重定向输出只要创建一个对象, 并实现它的 {{{write}}} 方法.

(除非 C 类型的实例外:Python 使用一个叫做 {{{softspace}}} 的整数属性来控制输出中的空白. 
如果没有这个属性, Python 将把这个属性附加到这个对象上. 你不需要在使用 Python 对象时担心, 
但是在重定向到一个 C 类型时, 你应该确保该类型支持 {{{softspace}}} 属性.)

=== 1.13.6. 退出程序 ===
执行至主程序的末尾时,解释器会自动退出. 但是如果需要中途退出程序, 你可以调用 {{{sys.exit}}} 函数, 
它带有一个可选的整数参数返回给调用它的程序. [[#eg-1-75|Example 1-75]] 给出了范例.

==== 1.13.6.1. Example 1-75. 使用sys模块退出程序 ====
{{{
File: sys-exit-example-1.py

import sys

print "hello"

sys.exit(1)

print "there"

*B*hello*b*
}}}

注意 {{{sys.exit}}} 并不是立即退出. 而是引发一个 ''SystemExit'' 异常. 
这意味着你可以在主程序中捕获对 {{{sys.exit}}} 的调用, 如 [[#eg-1-76|Example 1-76]] 所示.

==== 1.13.6.2. Example 1-76. 捕获sys.exit调用 ====
{{{
File: sys-exit-example-2.py

import sys

print "hello"

try:
    sys.exit(1)
except SystemExit:
    pass

print "there"

*B*hello
there*b*
}}}

如果准备在退出前自己清理一些东西(比如删除临时文件), 你可以配置一个 
"退出处理函数"(exit handler), 它将在程序退出的时候自动被调用. 如 [[#eg-1-77|Example 1-77]] 所示.

==== 1.13.6.3. Example 1-77. 另一种捕获sys.exit调用的方法 ====
{{{
File: sys-exitfunc-example-1.py

import sys

def exitfunc():
    print "world"

sys.exitfunc = exitfunc

print "hello"
sys.exit(1)
print "there" # never printed # 不会被 print

*B*hello
world*b*
}}}

在 Python 2.0 以后, 你可以使用 {{{atexit}}} 模块来注册多个退出处理函数.

----

== 1.14. atexit 模块 ==
(用于2.0版本及以上) {{{atexit}}} 模块允许你注册一个或多个终止函数(暂且这么叫), 
这些函数将在解释器终止前被自动调用.

调用 {{{register}}} 函数, 便可以将函数注册为终止函数, 如 [[#eg-1-78|Example 1-78]] 所示. 
你也可以添加更多的参数, 这些将作为 {{{exit}}} 函数的参数传递. 

==== 1.14.0.1. Example 1-78. 使用 atexit 模块 ====
{{{
File: atexit-example-1.py

import atexit

def exit(*args):
    print "exit", args

# register two exit handler
atexit.register(exit)
atexit.register(exit, 1)
atexit.register(exit, "hello", "world")

*B*exit ('hello', 'world')
exit (1,)
exit ()*b*
}}}

该模块其实是一个对 {{{sys.exitfunc}}} 钩子( hook )的简单封装. 

----

== 1.15. time 模块 ==
{{{time}}} 模块提供了一些处理日期和一天内时间的函数. 它是建立在 C 运行时库的简单封装. 

给定的日期和时间可以被表示为浮点型(从参考时间, 通常是 1970.1.1 到现在经过的秒数. 
即 Unix 格式), 或者一个表示时间的 struct (类元组). 

=== 1.15.1. 获得当前时间 ===
[[#eg-1-79|Example 1-79]] 展示了如何使用 {{{time}}} 模块获取当前时间.

==== 1.15.1.1. Example 1-79. 使用 time 模块获取当前时间 ====
{{{
File: time-example-1.py

import time

now = time.time()

print now, "seconds since", time.gmtime(0)[:6]
print
print "or in other words:"
print "- local time:", time.localtime(now)
print "- utc:", time.gmtime(now)

*B*937758359.77 seconds since (1970, 1, 1, 0, 0, 0)

or in other words:
- local time: (1999, 9, 19, 18, 25, 59, 6, 262, 1)
- utc: (1999, 9, 19, 16, 25, 59, 6, 262, 0)*b*
}}}

{{{localtime}}} 和 {{{gmtime}}} 返回的类元组包括年, 月, 日, 时, 分, 秒, 星期, 一年的第几天, 日光标志. 
其中年是一个四位数(在有千年虫问题的平台上另有规定, 但还是四位数), 星期从星期一(数字 0 代表)开始, 
1月1日是一年的第一天. 

=== 1.15.2. 将时间值转换为字符串 ===
你可以使用标准的格式化字符串把时间对象转换为字符串, 不过 {{{time}}} 模块已经提供了许多标准转换函数, 
如 [[#eg-1-80|Example 1-80]] 所示. 

==== 1.15.2.1. Example 1-80. 使用 time 模块格式化时间输出 ====
{{{
File: time-example-2.py

import time

now = time.localtime(time.time())

print time.asctime(now)
print time.strftime("%y/%m/%d %H:%M", now)
print time.strftime("%a %b %d", now)
print time.strftime("%c", now)
print time.strftime("%I %p", now)
print time.strftime("%Y-%m-%d %H:%M:%S %Z", now)

# do it by hand...
year, month, day, hour, minute, second, weekday, yearday, daylight = now
print "%04d-%02d-%02d" % (year, month, day)
print "%02d:%02d:%02d" % (hour, minute, second)
print ("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN")[weekday], yearday

*B*Sun Oct 10 21:39:24 1999
99/10/10 21:39
Sun Oct 10
Sun Oct 10 21:39:24 1999
09 PM
1999-10-10 21:39:24 CEST
1999-10-10
21:39:24
SUN 283*b*
}}}

=== 1.15.3. 将字符串转换为时间对象 ===
在一些平台上, {{{time}}} 模块包含了 {{{strptime}}} 函数, 它的作用与 {{{strftime}}} 相反. 
给定一个字符串和模式, 它返回相应的时间对象, 如 [[#eg-1-81|Example 1-81]] 所示. 

==== 1.15.3.1. Example 1-81. 使用 time.strptime 函数解析时间 ====
{{{
File: time-example-6.py

import time

# make sure we have a strptime function!
# 确认有函数 strptime
try:
    strptime = time.strptime
except AttributeError:
    from strptime import strptime

print strptime("31 Nov 00", "%d %b %y")
print strptime("1 Jan 70 1:30pm", "%d %b %y %I:%M%p")
}}}

只有在系统的 C 库提供了相应的函数的时候, {{{time.strptime}}} 函数才可以使用. 
对于没有提供标准实现的平台, [[#eg-1-82|Example 1-82]] 提供了一个不完全的实现. 

==== 1.15.3.2. Example 1-82. strptime 实现 ====
{{{
File: strptime.py

import re
import string

MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
          "Sep", "Oct", "Nov", "Dec"]

SPEC = {
    # map formatting code to a regular expression fragment
    "%a": "(?P<weekday>[a-z]+)",
    "%A": "(?P<weekday>[a-z]+)",
    "%b": "(?P<month>[a-z]+)",
    "%B": "(?P<month>[a-z]+)",
    "%C": "(?P<century>\d\d?)",
    "%d": "(?P<day>\d\d?)",
    "%D": "(?P<month>\d\d?)/(?P<day>\d\d?)/(?P<year>\d\d)",
    "%e": "(?P<day>\d\d?)",
    "%h": "(?P<month>[a-z]+)",
    "%H": "(?P<hour>\d\d?)",
    "%I": "(?P<hour12>\d\d?)",
    "%j": "(?P<yearday>\d\d?\d?)",
    "%m": "(?P<month>\d\d?)",
    "%M": "(?P<minute>\d\d?)",
    "%p": "(?P<ampm12>am|pm)",
    "%R": "(?P<hour>\d\d?):(?P<minute>\d\d?)",
    "%S": "(?P<second>\d\d?)",
    "%T": "(?P<hour>\d\d?):(?P<minute>\d\d?):(?P<second>\d\d?)",
    "%U": "(?P<week>\d\d)",
    "%w": "(?P<weekday>\d)",
    "%W": "(?P<weekday>\d\d)",
    "%y": "(?P<year>\d\d)",
    "%Y": "(?P<year>\d\d\d\d)",
    "%%": "%"
}

class TimeParser:
    def _ _init_ _(self, format):
        # convert strptime format string to regular expression
        format = string.join(re.split("(?:\s|%t|%n)+", format))
        pattern = []
        try:
            for spec in re.findall("%\w|%%|.", format):
                if spec[0] == "%":
                    spec = SPEC[spec]
                pattern.append(spec)
        except KeyError:
            raise ValueError, "unknown specificer: %s" % spec
        self.pattern = re.compile("(?i)" + string.join(pattern, ""))
    def match(self, daytime):
        # match time string
        match = self.pattern.match(daytime)
        if not match:
            raise ValueError, "format mismatch"
        get = match.groupdict().get
        tm = [0] * 9
        # extract date elements
        y = get("year")
        if y:
            y = int(y)
            if y < 68:
                y = 2000 + y
            elif y < 100:
                y = 1900 + y
            tm[0] = y
        m = get("month")
        if m:
            if m in MONTHS:
                m = MONTHS.index(m) + 1
            tm[1] = int(m)
        d = get("day")
        if d: tm[2] = int(d)
        # extract time elements
        h = get("hour")
        if h:
            tm[3] = int(h)
        else:
            h = get("hour12")
            if h:
                h = int(h)
                if string.lower(get("ampm12", "")) == "pm":
                    h = h + 12
                tm[3] = h
        m = get("minute")
        if m: tm[4] = int(m)
        s = get("second")
        if s: tm[5] = int(s)
        # ignore weekday/yearday for now
        return tuple(tm)

def strptime(string, format="%a %b %d %H:%M:%S %Y"):
    return TimeParser(format).match(string)

if _ _name_ _ == "_ _main_ _":
    # try it out
    import time
    print strptime("2000-12-20 01:02:03", "%Y-%m-%d %H:%M:%S")
    print strptime(time.ctime(time.time()))

*B*(2000, 12, 20, 1, 2, 3, 0, 0, 0)
(2000, 11, 15, 12, 30, 45, 0, 0, 0)*b*
}}}

=== 1.15.4. 转换时间值 ===
将时间元组转换回时间值非常简单, 至少我们谈论的当地时间 (local time) 如此. 
只要把时间元组传递给 {{{mktime}}} 函数, 如 [[#eg-1-83|Example 1-83]] 所示. 

==== 1.15.4.1. Example 1-83. 使用 time 模块将本地时间元组转换为时间值(整数) ====
{{{
File: time-example-3.py

import time

t0 = time.time()
tm = time.localtime(t0)

print tm

print t0
print time.mktime(tm)

*B*(1999, 9, 9, 0, 11, 8, 3, 252, 1)
936828668.16
936828668.0*b*
}}}

但是, 1.5.2 版本的标准库没有提供能将 UTC 时间
(Universal Time, Coordinated: 特林威治标准时间)转换为时间值的函数 
( Python 和对应底层 C 库都没有提供). [[#eg-1-84|Example 1-84]] 提供了该函数的一个 
Python 实现, 称为 {{{timegm}}} . 

==== 1.15.4.2. Example 1-84. 将 UTC 时间元组转换为时间值(整数) ====
{{{
File: time-example-4.py

import time

def _d(y, m, d, days=(0,31,59,90,120,151,181,212,243,273,304,334,365)):
    # map a date to the number of days from a reference point
    return (((y - 1901)*1461)/4 + days[m-1] + d +
        ((m > 2 and not y % 4 and (y % 100 or not y % 400)) and 1))

def timegm(tm, epoch=_d(1970,1,1)):
    year, month, day, h, m, s = tm[:6]
    assert year >= 1970
    assert 1 <= month <= 12
    return (_d(year, month, day) - epoch)*86400 + h*3600 + m*60 + s

t0 = time.time()
tm = time.gmtime(t0)

print tm

print t0
print timegm(tm)

*B*(1999, 9, 8, 22, 12, 12, 2, 251, 0)
936828732.48
936828732*b*
}}}

从 1.6 版本开始, {{{calendar}}} 模块提供了一个类似的函数 {{{calendar.timegm}}} . 

=== 1.15.5. Timing 相关 ===
{{{time}}} 模块可以计算 Python 程序的执行时间, 如 [[#eg-1-85|Example 1-85]] 所示. 
你可以测量 "wall time" (real world time), 或是"进程时间" (消耗的 CPU 时间). 

==== 1.15.5.1. Example 1-85. 使用 time 模块评价算法 ====
{{{
File: time-example-5.py

import time

def procedure():
    time.sleep(2.5)

# measure process time
t0 = time.clock()
procedure()
print time.clock() - t0, "seconds process time"

# measure wall time
t0 = time.time()
procedure()
print time.time() - t0, "seconds wall time"

*B*0.0 seconds process time
2.50903499126 seconds wall time*b*
}}}

并不是所有的系统都能测量真实的进程时间. 一些系统中(包括 Windows ), 
{{{clock}}} 函数通常测量从程序启动到测量时的 wall time. 

进程时间的精度受限制. 在一些系统中, 它超过 30 分钟后进程会被清理.
(原文: On many systems, it wraps around after just over 30 minutes.) 

另参见 {{{timing}}} 模块( Windows 下的朋友不用忙活了,没有地~), 它可以测量两个事件之间的 wall time. 

----

== 1.16. types 模块 ==
{{{types}}} 模块包含了标准解释器定义的所有类型的类型对象, 如 [[#eg-1-86|Example 1-86]] 所示. 
同一类型的所有对象共享一个类型对象. 你可以使用 {{{is}}} 来检查一个对象是不是属于某个给定类型.

==== 1.16.0.1. Example 1-86. 使用 types 模块 ====
{{{
File: types-example-1.py

import types

def check(object):
    print object,

    if type(object) is types.IntType:
        print "INTEGER",
    if type(object) is types.FloatType:
        print "FLOAT",
    if type(object) is types.StringType:
        print "STRING",
    if type(object) is types.ClassType:
        print "CLASS",
    if type(object) is types.InstanceType:
        print "INSTANCE",
    print

check(0)
check(0.0)
check("0")

class A:
    pass

class B:
    pass

check(A)
check(B)

a = A()
b = B()

check(a)
check(b)

*B*0 INTEGER
0.0 FLOAT
0 STRING
A CLASS
B CLASS
<A instance at 796960> INSTANCE
<B instance at 796990> INSTANCE*b*
}}}

注意所有的类都具有相同的类型, 所有的实例也是一样. 要测试一个类或者实例所属的类, 
可以使用内建的 {{{issubclass}}} 和 {{{isinstance}}} 函数.

{{{types}}} 模块在第一次引入的时候会破坏当前的异常状态. 也就是说, 
不要在异常处理语句块中导入该模块 (''或其他会导入它的模块'') . 

----

== 1.17. gc 模块 ==
(可选, 2.0 及以后版本) {{{gc}}} 模块提供了到内建循环垃圾收集器的接口. 

Python 使用引用记数来跟踪什么时候销毁一个对象; 一个对象的最后一个引用一旦消失, 这个对象就会被销毁. 

从 2.0 版开始, Python 还提供了一个循环垃圾收集器, 它每隔一段时间执行. 
这个收集器查找指向自身的数据结构, 并尝试破坏循环. 如 [[#eg-1-87|Example 1-87]] 所示.

你可以使用 {{{gc.collect}}} 函数来强制完整收集. 这个函数将返回收集器销毁的对象的数量. 

==== 1.17.0.1. Example 1-87. 使用 gc 模块收集循环引用垃圾 ====
{{{
File: gc-example-1.py

import gc

# create a simple object that links to itself
class Node:

    def _ _init_ _(self, name):
        self.name = name
        self.parent = None
        self.children = []

    def addchild(self, node):
        node.parent = self
        self.children.append(node)

    def _ _repr_ _(self):
        return "<Node %s at %x>" % (repr(self.name), id(self))

# set up a self-referencing structure
root = Node("monty")

root.addchild(Node("eric"))
root.addchild(Node("john"))
root.addchild(Node("michael"))

# remove our only reference
del root

print gc.collect(), "unreachable objects"
print gc.collect(), "unreachable objects"

*B*12 unreachable objects
0 unreachable objects*b*
}}}

如果你确定你的程序不会创建自引用的数据结构, 你可以使用 {{{gc.disable}}} 函数禁用垃圾收集, 
调用这个函数以后, Python 的工作方式将与 1.5.2 或更早的版本相同. 

----


## moin code generated by txt2tags 2.4 (http://txt2tags.sf.net)
## cmdline: txt2tags -t moin -o moin/chapter1.moin chapter1.t2t