- 核心模块
- 更多标准模块
- 2.1. 概览
- 2.2. fileinput 模块
- 2.3. shutil 模块
- 2.4. tempfile 模块
- 2.5. StringIO 模块
- 2.6. cStringIO 模块
- 2.7. mmap 模块
- 2.8. UserDict 模块
- 2.9. UserList 模块
- 2.10. UserString 模块
- 2.11. traceback 模块
- 2.12. errno 模块
- 2.13. getopt 模块
- 2.14. getpass 模块
- 2.15. glob 模块
- 2.16. fnmatch 模块
- 2.17. random 模块
- 2.18. whrandom 模块
- 2.19. md5 模块
- 2.20. sha 模块
- 2.21. crypt 模块
- 2.22. rotor 模块
- 2.23. zlib 模块
- 2.24. code 模块
- 线程和进程
- 数据表示
- 文件格式
- 邮件和新闻消息处理
- 网络协议
- 7.1. 概览
- 7.2. socket 模块
- 7.3. select 模块
- 7.4. asyncore 模块
- 7.5. asynchat 模块
- 7.6. urllib 模块
- 7.7. urlparse 模块
- 7.8. cookie 模块
- 7.9. robotparser 模块
- 7.10. ftplib 模块
- 7.11. gopherlib 模块
- 7.12. httplib 模块
- 7.13. poplib 模块
- 7.14. imaplib 模块
- 7.15. smtplib 模块
- 7.16. telnetlib 模块
- 7.17. nntplib 模块
- 7.18. SocketServer 模块
- 7.19. BaseHTTPServer 模块
- 7.20. SimpleHTTPServer 模块
- 7.21. CGIHTTPServer 模块
- 7.22. cgi 模块
- 7.23. webbrowser 模块
- 国际化
- 多媒体相关模块
- 数据储存
- 工具和实用程序
- 其他模块
- 执行支持模块
- 13.1. dospath 模块
- 13.2. macpath 模块
- 13.3. ntpath 模块
- 13.4. posixpath 模块
- 13.5. strop 模块
- 13.6. imp 模块
- 13.7. new 模块
- 13.8. pre 模块
- 13.9. sre 模块
- 13.10. py_compile 模块
- 13.11. compileall 模块
- 13.12. ihooks 模块
- 13.13. linecache 模块
- 13.14. macurl2path 模块
- 13.15. nturl2path 模块
- 13.16. tokenize 模块
- 13.17. keyword 模块
- 13.18. parser 模块
- 13.19. symbol 模块
- 13.20. token 模块
- 其他模块
- 14.1. 概览
- 14.2. pyclbr 模块
- 14.3. filecmp 模块
- 14.4. cmd 模块
- 14.5. rexec 模块
- 14.6. Bastion 模块
- 14.7. readline 模块
- 14.8. rlcompleter 模块
- 14.9. statvfs 模块
- 14.10. calendar 模块
- 14.11. sched 模块
- 14.12. statcache 模块
- 14.13. grep 模块
- 14.14. dircache 模块
- 14.15. dircmp 模块
- 14.16. cmp 模块
- 14.17. cmpcache 模块
- 14.18. util 模块
- 14.19. soundex 模块
- 14.20. timing 模块
- 14.21. posixfile 模块
- 14.22. bisect 模块
- 14.23. knee 模块
- 14.24. tzparse 模块
- 14.25. regex 模块
- 14.26. regsub 模块
- 14.27. reconvert 模块
- 14.28. regex_syntax 模块
- 14.29. find 模块
- Py 2.0 后新增模块
- 后记
"We'd like to pretend that 'Fredrik' is a role, but even hundreds of volunteers couldn't possibly keep up. No, 'Fredrik' is the result of crossing an http server with a spam filter with an emacs whatsit and some other stuff besides."
-Gordon McMillan, June 1998
Python 2.0发布附带了一个包含200个以上模块的可扩展的标准库. 本书简要地介绍每个模块并提供至少一个例子来说明如何使用它. 本书一共包含360个例子.
0.1. 关于本书
"Those people who have nothing better to do than post on the Internet all day long are rarely the ones who have the most insights."
- Jakob Nielsen, December 1998
五年前我偶然遇到了 Python, 开始了我的 Python 之旅, 我花费了大量的时间 在 comp.lang.python
新闻组里回答问题. 也许某个人发现一个模块正是他想要的, 但是却不知道如何使用它. 也许某个人为他的任务挑选的不合适的模块. 也许某个人已经厌 倦了发明新轮子. 大多时候, 一个简短的例子要比一份手册文档更有帮助.
本书是超过3,000个新闻组讨论的精华部分, 当然也有很多的新脚本, 为了涵盖标准库的每个角落.
我尽力使得每个脚本都易于理解, 易于重用代码. 我有意缩短注释的长度, 如果你想更深入地 了解背景, 那么你可以参阅每个 Python 发布中的参考手册. 本书的重要之处在于范例代码.
我们欢迎任何评论, 建议, 以及 bug 报告, 请将它们发送到 fredrik@pythonware.com. 我将阅读尽我所能阅读所有的邮件, 但可能回复不是那么及时.
本书的相关更新内容以及其他信息请访问 http://www.pythonware.com/people/fredrik/librarybook.htm
为什么没有Tkinter?
本书涵盖了整个标准库, 除了(可选的)Tkinter ui(user-interface : 用户界面) 库. 有很多原因, 更多是因为时间, 本书的空间, 以及我正在写另一本关于 Tkinter 的书.
关于这些书的信息, 请访问 http://www.pythonware.com/people/fredrik/tkinterbook.htm. (不用看了,又一404)
产品细节
本书使用DocBook SGML编写, 我使用了一系列的工具, 包括Secret Labs' PythonWorks, Excosoft Documentor, James Clark's Jade DSSSL processor, Norm Walsh's DocBook stylesheets, 当然,还有一些 Python 脚本.
感谢帮忙校对的人们: Tim Peters, Guido van Rossum, David Ascher, Mark Lutz, 和 Rael Dornfest, 以及 PythonWare 成员: Matthew Ellis, Håkan Karlsson, 和 Rune Uhlin.
感谢 Lenny Muellner, 他帮助我把SGML文件转变为你们现在所看到的这本书, 以及Christien Shangraw, 他将那些代码文件集合起来做成了随书CD (可以在 http://examples.oreilly.com/pythonsl 找到, 竟然没有404, 奇迹).
0.2. 代码约定
本书使用以下习惯用法:
斜体
用于文件名和命令. 还用于定义术语.
等宽字体 e.g. Python
用于代码以及方法,模块,操作符,函数,语句,属性等的名称.
等宽粗体
用于代码执行结果.
0.3. 关于例子
除非提到,所有例子都可以在 Python 1.5.2 和 Python 2.0 下运行. 能不能在 Python 2.4/2.5 下执行.....看参与翻译各位的了.
除了一些平台相关模块的脚本, 所有例子都可以在 Windows, Solaris, 以及 Linux 下正常执行.
所有代码都是有版权的. 当然,你可以自由地使用这些这些模块,别忘记你是从哪得到(?学会)这些的.
大多例子的文件名都包含它所使用的模块名称,后边是 "-example-
" 以及一个唯一的"序号". 注意有些例子并不是按顺序出现的, 这是为了匹配本书的较早版本 - (the eff-bot guide to) The Standard Python Library.
你可以在网上找到本书附带CD的内容 (参阅 http://examples.oreilly.com/pythonsl). 更多信息以及更新内容参阅 http://www.pythonware.com/people/fredrik/librarybook.htm. (ft, 又一404. 大家一定不要看~)
0.4. 如何联系我们
Python 江湖 QQ 群: 43680167
Feather (校对) QQ: 85660100
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
函数调用函数. 如 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))
whither canada?
1 5
要想把关键字参数传递给一个函数, 你可以将一个字典作为 apply
函数的第 3 个参数, 参考 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"})
crunchy frog
crunchy frog
crunchy frog
apply
函数的一个常见用法是把构造函数参数从子类传递到基类, 尤其是构造函数需要接受很多参数的时候. 如 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)
create a green <Rectangle instance at 8c8260> sized 100 x 100
create a blue <RoundedRectangle instance at 8c84c0> sized 10 x 20
Python 2.0 提供了另个方法来做相同的事. 你只需要使用一个传统的函数调用 , 使用 *
来标记元组, **
来标记字典.
下面两个语句是等价的:
result = function(*args, **kwargs)
result = apply(function, args, kwargs)
1.2.2. 加载和重载模块
如果你写过较庞大的 Python 程序, 那么你就应该知道 import
语句是用来导入外部模块的 (当然也可以使用 from-import
版本). 不过你可能不知道 import
其实是靠调用内建 函数 _ _import_ _
来工作的.
通过这个戏法你可以动态地调用函数. 当你只知道模块名称(字符串)的时候, 这将很方便. 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()
example-plugin says hello
注意这个 plug-in 模块文件名中有个 "-" (hyphens). 这意味着你不能使用普通的 import
命令, 因为 Python 的辨识符不允许有 "-" .
Example 1-5 展示了 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"
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"))
<function open at 794fa0>
你也可以使用这个函数实现延迟化的模块导入 (lazy module loading). 例如在 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
abcdefghijklmnopqrstuvwxyz
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)
hello again, and welcome to the show
hello again, and welcome to the show
hello again, and welcome to the show
reload 直接接受模块作为参数.
[!Feather 注: ^ 原句无法理解, 稍后讨论.]
注意,当你重加载模块时, 它会被重新编译, 新的模块会代替模块字典里的老模块. 但是, 已经用原模块里的类建立的实例仍然使用的是老模块(不会被更新).
同样地, 使用 from-import
直接创建的到模块内容的引用也是不会被更新的.
1.2.3. 关于名称空间
dir
返回由给定模块, 类, 实例, 或其他类型的所有成员组成的列表. 这可能在交互式 Python 解释器下很有用, 也可以用在其他地方. 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
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',
...
在例子 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)
['_ _doc_ _', '_ _module_ _', 'a', 'b']
['_ _doc_ _', '_ _module_ _', 'a', 'b', 'c', 'd']
['_ _doc_ _', '_ _getitem_ _', '_ _init_ _', '_ _module_ _', '_ _str_ _']
getmembers
函数返回了一个有序列表. 成员在列表中名称出现的越早, 它所处的类层次就越高. 如果无所谓顺序的话, 你可以使用字典代替列表.
[!Feather 注: 字典是无序的, 而列表和元组是有序的, 网上有关于有序字典的讨论]
vars
函数与此相似, 它返回的是包含每个成员当前值的字典. 如果你使用不带参数的 vars
, 它将返回当前局部名称空间的可见元素(同 locals()
函数 ). 如 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()
the library book contains more than 350 scripts
1.2.4. 检查对象类型
Python 是一种动态类型语言, 这意味着给一个定变量名可以在不同的场合绑定到不同的类型上. 在接下面例子中, 同样的函数分别被整数, 浮点数, 以及一个字符串调用:
def function(value):
print value
function(1)
function(1.0)
function("one")
type
函数 (如 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")
<type 'int'> 1
<type 'float'> 1.0
<type 'string'> one
每个类型都有一个对应的类型对象, 所以你可以使用 is
操作符 (对象身份?) 来 检查类型. (如 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"
4672 bytes
4672 bytes
callable
函数, 如 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)
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
注意类对象 (A 和 B) 都是可调用的; 如果调用它们, 就产生新的对象(类实例). 但是 A 类的实例不可调用, 因为它的类没有实现 _ _call_ _
方法.
你可以在 operator
模块中找到检查对象是否为某一内建类型(数字, 序列, 或者字典等) 的函数. 但是, 因为创建一个类很简单(比如实现基本序列方法的类), 所以对这些 类型使用显式的类型判断并不是好主意.
在处理类和实例的时候会复杂些. Python 不会把类作为本质上的类型对待; 相反地, 所有的类都属于一个特殊的类类型(special class type), 所有的类实例属于一个特殊的实例类型(special instance type).
这意味着你不能使用 type
函数来测试一个实例是否属于一个给定的类; 所有的实例都是同样 的类型! 为了解决这个问题, 你可以使用 isinstance
函数,它会检查一个对象是 不是给定类(或其子类)的实例. 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")
<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 =>
issubclass
函数与此相似, 它用于检查一个类对象是否与给定类相同, 或者是给定类的子类. 如 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")
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
1.2.5. 计算 Python 表达式
Python 提供了在程序中与解释器交互的多种方法. 例如 eval
函数将一个字符串 作为 Python 表达式求值. 你可以传递一串文本, 简单的表达式, 或者使用 内建 Python 函数. 如 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')")
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'>
如果你不确定字符串来源的安全性, 那么你在使用 eval
的时候会遇到些麻烦. 例如, 某个用户可能会使用 _ _import_ _
函数加载 os
模块, 然后从硬盘删除文件 (如 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')")
/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')
这里我们得到了一个 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_ _
项即可. 如 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_ _": {}})
/home/fredrik/librarybook
Traceback (innermost last):
File "builtin-eval-example-3.py", line 2, in ?
File "<string>", line 0, in ?
NameError: _ _import_ _
即使这样, 你仍然无法避免针对 CPU 和内存资源的攻击. (比如, 形如 eval("'*'*1000000*2*2*2*2*2*2*2*2*2")
的语句在执行后会使你的程序耗尽系统资源).
1.2.6. 编译和执行代码
eval
函数只针对简单的表达式. 如果要处理大块的代码, 你应该使用 compile
和 exec
函数 (如 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
语句执行它, 参见 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
<code object ? at 8c6be0, file "<script>", line 0>
the ant, an introduction
使用 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()
code generation made easy!
code generation made easy!
code generation made easy!
code generation made easy!
code generation made easy!
Python 还提供了 execfile
函数, 一个从文件加载代码, 编译代码, 执行代码的快捷方式. 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")
hello again, and welcome to the show
hello again, and welcome to the show
Example 1-24 中的代码是 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_ _
模块. 例如 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"
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
[!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_ _
方法. 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
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>
1.4. os 模块
这个模块中的大部分函数通过对应平台相关模块实现, 比如 posix
和 nt. os
模块会在第一次导入的时候自动加载合适的执行模块.
1.4.1. 处理文件
内建的 open / file
函数用于创建, 打开和编辑文件, 如 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
函数返回给定目录中所有文件名(包括目录名)组成的列表, 如 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
sample.au
sample.jpg
sample.wav
...
getcwd
和 chdir
函数分别用于获得和改变当前工作目录. 如 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()
1 /ematter/librarybook
2 /ematter/librarybook/samples
3 /ematter/librarybook
makedirs
和 removedirs
函数用于创建或删除目录层,如 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
函数只能处理单个目录级. 如 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
Traceback (innermost last):
File "os-example-7", line 6, in ?
OSError: [Errno 41] Directory not empty: 'samples'
如果需要删除非空目录, 你可以使用 shutil
模块中的 rmtree
函数.
1.4.3. 处理文件属性
stat
函数可以用来获取一个存在文件的信息, 如 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)
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
返回对象中有些属性在非 Unix 平台下是无意义的, 比如 (st_inode
, st_dev
)为 Unix 下的为每个文件提供了唯一标识, 但在其他平台可能为任意无意义数据 .
stat
模块包含了很多可以处理该返回对象的常量及函数. 下面的代码展示了其中的一些.
可以使用 chmod
和 utime
函数修改文件的权限模式和时间属性,如 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])
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
1.4.4. 处理进程
system
函数在当前进程下执行一个新命令, 并等待它完成, 如 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)
-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
...
命令通过操作系统的标准 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
函数会使用新进程替换当前进程(或者说是"转到进程"). 在 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"
hello again, and welcome to the show
Python 提供了很多表现不同的 exec
函数. Example 1-35 使用的是 execvp
函数, 它会从标准路径搜索执行程序, 把第二个参数(元组)作为单独的参数传递给程序, 并使用当前的环境变量来运行程序. 其他七个同类型函数请参阅 Python Library Reference .
在 Unix 环境下, 你可以通过组合使用 exec
, fork
以及 wait
函数来从当前程序调用另一个程序, 如 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"
hello again, and welcome to the show
goodbye
fork
函数在子进程返回中返回 0 (这个进程首先从 fork
返回值), 在父进程中返回一个非 0 的进程标识符(子进程的 PID ). 也就是说, 只有当我们处于子进程的时候 "not pid
" 才为真.
fork
和 wait
函数在 Windows 上是不可用的, 但是你可以使用 spawn
函数, 如 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"
hello again, and welcome to the show
goodbye
spawn
函数还可用于在后台运行一个程序. 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"
goodbye
hello again, and welcome to the show
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"
hello again, and welcome to the show
goodbye
Example 1-39 首先尝试调用 spawnvp
函数. 如果该函数不存在 (一些版本/平台没有这个函数), 它将继续查找一个名为 spawnv
的函数并且 开始查找程序路径. 作为最后的选择, 它会调用 exec
和 fork
函数完成工作.
1.4.5. 处理守护进程(Daemon Processes)
Unix 系统中, 你可以使用 fork
函数把当前进程转入后台(一个"守护者/daemon"). 一般来说, 你需要派生(fork off)一个当前进程的副本, 然后终止原进程, 如 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 异常, 程序仍然会继续执行. 如 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!"
caught exit(1)
1.5. os.path 模块
os.path
模块包含了各种处理长文件名(路径名)的函数. 先导入 (import) os
模块, 然后就可以以 os.path
访问该模块.
1.5.1. 处理文件名
os.path
模块包含了许多与平台无关的处理长文件名的函数. 也就是说, 你不需要处理前后斜杠, 冒号等. 我们可以看看 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))
using nt ...
split => ('my/little', 'pony')
splitext => ('my/little/pony', '')
dirname => my/little
basename => pony
join => my/little/pony
注意这里的 split
只分割出最后一项(不带斜杠).
os.path
模块中还有许多函数允许你简单快速地获知文件名的一些特征,如 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
. => EXISTS ISDIR
/ => EXISTS ISABS ISDIR ISMOUNT
file =>
/file => ISABS
samples => EXISTS ISDIR
samples/sample.jpg => EXISTS ISFILE
directory/file =>
../directory/file =>
/directory/file => ISABS
expanduser
函数以与大部分Unix shell相同的方式处理用户名快捷符号(~, 不过在 Windows 下工作不正常), 如 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
函数将文件名中的环境变量替换为对应值, 如 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")
/home/user/config
user/folders
1.5.2. 搜索文件系统
walk
函数会帮你找出一个目录树下的所有文件 (如 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")
./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'
...
walk
函数的接口多少有点晦涩 (也许只是对我个人而言, 我总是记不住参数的顺序). 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
./aifc-example-1.py
./anydbm-example-1.py
./array-example-1.py
...
如果你不想列出所有的文件 (基于性能或者是内存的考虑) , 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
./aifc-example-1.py
./anydbm-example-1.py
./array-example-1.py
...
注意 DirectoryWalker 类并不检查传递给 _ _getitem_ _
方法的索引值. 这意味着如果你越界访问序列成员(索引数字过大)的话, 这个类将不能正常工作.
最后, 如果你需要处理文件大小和时间戳, 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]
./aifc-example-1.py 336
./anydbm-example-1.py 244
./array-example-1.py 526
1.6. stat 模块
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])
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
1.7. string 模块
string
模块提供了一些用于处理字符串类型的函数, 如 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")
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
在 Python 1.5.2 以及更早版本中, string
使用 strop
中的函数来实现模块功能.
在 Python1.6 和后继版本,更多的字符串操作都可以作为字符串方法来访问, 如 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")
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
为了增强模块对字符的处理能力, 除了字符串方法, string
模块还包含了类型转换函数用于把字符串转换为其他类型, (如 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")
4711 4711 4711 4711 4711
4711 2505 18193
4711.0 1.0 123000.0
大多数情况下 (特别是当你使用的是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
尝试从字符串的起始匹配一个模式, 如
- 核心模块
- 更多标准模块
- 2.1. 概览
- 2.2. fileinput 模块
- 2.3. shutil 模块
- 2.4. tempfile 模块
- 2.5. StringIO 模块
- 2.6. cStringIO 模块
- 2.7. mmap 模块
- 2.8. UserDict 模块
- 2.9. UserList 模块
- 2.10. UserString 模块
- 2.11. traceback 模块
- 2.12. errno 模块
- 2.13. getopt 模块
- 2.14. getpass 模块
- 2.15. glob 模块
- 2.16. fnmatch 模块
- 2.17. random 模块
- 2.18. whrandom 模块
- 2.19. md5 模块
- 2.20. sha 模块
- 2.21. crypt 模块
- 2.22. rotor 模块
- 2.23. zlib 模块
- 2.24. code 模块
- 线程和进程
- 数据表示
- 文件格式
- 邮件和新闻消息处理
- 网络协议
- 7.1. 概览
- 7.2. socket 模块
- 7.3. select 模块
- 7.4. asyncore 模块
- 7.5. asynchat 模块
- 7.6. urllib 模块
- 7.7. urlparse 模块
- 7.8. cookie 模块
- 7.9. robotparser 模块
- 7.10. ftplib 模块
- 7.11. gopherlib 模块
- 7.12. httplib 模块
- 7.13. poplib 模块
- 7.14. imaplib 模块
- 7.15. smtplib 模块
- 7.16. telnetlib 模块
- 7.17. nntplib 模块
- 7.18. SocketServer 模块
- 7.19. BaseHTTPServer 模块
- 7.20. SimpleHTTPServer 模块
- 7.21. CGIHTTPServer 模块
- 7.22. cgi 模块
- 7.23. webbrowser 模块
- 国际化
- 多媒体相关模块
- 数据储存
- 工具和实用程序
- 其他模块
- 执行支持模块
- 13.1. dospath 模块
- 13.2. macpath 模块
- 13.3. ntpath 模块
- 13.4. posixpath 模块
- 13.5. strop 模块
- 13.6. imp 模块
- 13.7. new 模块
- 13.8. pre 模块
- 13.9. sre 模块
- 13.10. py_compile 模块
- 13.11. compileall 模块
- 13.12. ihooks 模块
- 13.13. linecache 模块
- 13.14. macurl2path 模块
- 13.15. nturl2path 模块
- 13.16. tokenize 模块
- 13.17. keyword 模块
- 13.18. parser 模块
- 13.19. symbol 模块
- 13.20. token 模块
- 其他模块
- 14.1. 概览
- 14.2. pyclbr 模块
- 14.3. filecmp 模块
- 14.4. cmd 模块
- 14.5. rexec 模块
- 14.6. Bastion 模块
- 14.7. readline 模块
- 14.8. rlcompleter 模块
- 14.9. statvfs 模块
- 14.10. calendar 模块
- 14.11. sched 模块
- 14.12. statcache 模块
- 14.13. grep 模块
- 14.14. dircache 模块
- 14.15. dircmp 模块
- 14.16. cmp 模块
- 14.17. cmpcache 模块
- 14.18. util 模块
- 14.19. soundex 模块
- 14.20. timing 模块
- 14.21. posixfile 模块
- 14.22. bisect 模块
- 14.23. knee 模块
- 14.24. tzparse 模块
- 14.25. regex 模块
- 14.26. regsub 模块
- 14.27. reconvert 模块
- 14.28. regex_syntax 模块
- 14.29. find 模块
- Py 2.0 后新增模块
- 后记
"We'd like to pretend that 'Fredrik' is a role, but even hundreds of volunteers couldn't possibly keep up. No, 'Fredrik' is the result of crossing an http server with a spam filter with an emacs whatsit and some other stuff besides."
-Gordon McMillan, June 1998
Python 2.0发布附带了一个包含200个以上模块的可扩展的标准库. 本书简要地介绍每个模块并提供至少一个例子来说明如何使用它. 本书一共包含360个例子.
0.1. 关于本书
"Those people who have nothing better to do than post on the Internet all day long are rarely the ones who have the most insights."
- Jakob Nielsen, December 1998
五年前我偶然遇到了 Python, 开始了我的 Python 之旅, 我花费了大量的时间 在 comp.lang.python
新闻组里回答问题. 也许某个人发现一个模块正是他想要的, 但是却不知道如何使用它. 也许某个人为他的任务挑选的不合适的模块. 也许某个人已经厌 倦了发明新轮子. 大多时候, 一个简短的例子要比一份手册文档更有帮助.
本书是超过3,000个新闻组讨论的精华部分, 当然也有很多的新脚本, 为了涵盖标准库的每个角落.
我尽力使得每个脚本都易于理解, 易于重用代码. 我有意缩短注释的长度, 如果你想更深入地 了解背景, 那么你可以参阅每个 Python 发布中的参考手册. 本书的重要之处在于范例代码.
我们欢迎任何评论, 建议, 以及 bug 报告, 请将它们发送到 fredrik@pythonware.com. 我将阅读尽我所能阅读所有的邮件, 但可能回复不是那么及时.
本书的相关更新内容以及其他信息请访问 http://www.pythonware.com/people/fredrik/librarybook.htm
为什么没有Tkinter?
本书涵盖了整个标准库, 除了(可选的)Tkinter ui(user-interface : 用户界面) 库. 有很多原因, 更多是因为时间, 本书的空间, 以及我正在写另一本关于 Tkinter 的书.
关于这些书的信息, 请访问 http://www.pythonware.com/people/fredrik/tkinterbook.htm. (不用看了,又一404)
产品细节
本书使用DocBook SGML编写, 我使用了一系列的工具, 包括Secret Labs' PythonWorks, Excosoft Documentor, James Clark's Jade DSSSL processor, Norm Walsh's DocBook stylesheets, 当然,还有一些 Python 脚本.
感谢帮忙校对的人们: Tim Peters, Guido van Rossum, David Ascher, Mark Lutz, 和 Rael Dornfest, 以及 PythonWare 成员: Matthew Ellis, Håkan Karlsson, 和 Rune Uhlin.
感谢 Lenny Muellner, 他帮助我把SGML文件转变为你们现在所看到的这本书, 以及Christien Shangraw, 他将那些代码文件集合起来做成了随书CD (可以在 http://examples.oreilly.com/pythonsl 找到, 竟然没有404, 奇迹).
0.2. 代码约定
本书使用以下习惯用法:
斜体
用于文件名和命令. 还用于定义术语.
等宽字体 e.g. Python
用于代码以及方法,模块,操作符,函数,语句,属性等的名称.
等宽粗体
用于代码执行结果.
0.3. 关于例子
除非提到,所有例子都可以在 Python 1.5.2 和 Python 2.0 下运行. 能不能在 Python 2.4/2.5 下执行.....看参与翻译各位的了.
除了一些平台相关模块的脚本, 所有例子都可以在 Windows, Solaris, 以及 Linux 下正常执行.
所有代码都是有版权的. 当然,你可以自由地使用这些这些模块,别忘记你是从哪得到(?学会)这些的.
大多例子的文件名都包含它所使用的模块名称,后边是 "-example-
" 以及一个唯一的"序号". 注意有些例子并不是按顺序出现的, 这是为了匹配本书的较早版本 - (the eff-bot guide to) The Standard Python Library.
你可以在网上找到本书附带CD的内容 (参阅 http://examples.oreilly.com/pythonsl). 更多信息以及更新内容参阅 http://www.pythonware.com/people/fredrik/librarybook.htm. (ft, 又一404. 大家一定不要看~)
0.4. 如何联系我们
Python 江湖 QQ 群: 43680167
Feather (校对) QQ: 85660100
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
函数调用函数. 如 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))
whither canada?
1 5
要想把关键字参数传递给一个函数, 你可以将一个字典作为 apply
函数的第 3 个参数, 参考 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"})
crunchy frog
crunchy frog
crunchy frog
apply
函数的一个常见用法是把构造函数参数从子类传递到基类, 尤其是构造函数需要接受很多参数的时候. 如 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)
create a green <Rectangle instance at 8c8260> sized 100 x 100
create a blue <RoundedRectangle instance at 8c84c0> sized 10 x 20
Python 2.0 提供了另个方法来做相同的事. 你只需要使用一个传统的函数调用 , 使用 *
来标记元组, **
来标记字典.
下面两个语句是等价的:
result = function(*args, **kwargs)
result = apply(function, args, kwargs)
1.2.2. 加载和重载模块
如果你写过较庞大的 Python 程序, 那么你就应该知道 import
语句是用来导入外部模块的 (当然也可以使用 from-import
版本). 不过你可能不知道 import
其实是靠调用内建 函数 _ _import_ _
来工作的.
通过这个戏法你可以动态地调用函数. 当你只知道模块名称(字符串)的时候, 这将很方便. 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()
example-plugin says hello
注意这个 plug-in 模块文件名中有个 "-" (hyphens). 这意味着你不能使用普通的 import
命令, 因为 Python 的辨识符不允许有 "-" .
Example 1-5 展示了 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"
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"))
<function open at 794fa0>
你也可以使用这个函数实现延迟化的模块导入 (lazy module loading). 例如在 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
abcdefghijklmnopqrstuvwxyz
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)
hello again, and welcome to the show
hello again, and welcome to the show
hello again, and welcome to the show
reload 直接接受模块作为参数.
[!Feather 注: ^ 原句无法理解, 稍后讨论.]
注意,当你重加载模块时, 它会被重新编译, 新的模块会代替模块字典里的老模块. 但是, 已经用原模块里的类建立的实例仍然使用的是老模块(不会被更新).
同样地, 使用 from-import
直接创建的到模块内容的引用也是不会被更新的.
1.2.3. 关于名称空间
dir
返回由给定模块, 类, 实例, 或其他类型的所有成员组成的列表. 这可能在交互式 Python 解释器下很有用, 也可以用在其他地方. 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
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',
...
在例子 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)
['_ _doc_ _', '_ _module_ _', 'a', 'b']
['_ _doc_ _', '_ _module_ _', 'a', 'b', 'c', 'd']
['_ _doc_ _', '_ _getitem_ _', '_ _init_ _', '_ _module_ _', '_ _str_ _']
getmembers
函数返回了一个有序列表. 成员在列表中名称出现的越早, 它所处的类层次就越高. 如果无所谓顺序的话, 你可以使用字典代替列表.
[!Feather 注: 字典是无序的, 而列表和元组是有序的, 网上有关于有序字典的讨论]
vars
函数与此相似, 它返回的是包含每个成员当前值的字典. 如果你使用不带参数的 vars
, 它将返回当前局部名称空间的可见元素(同 locals()
函数 ). 如 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()
the library book contains more than 350 scripts
1.2.4. 检查对象类型
Python 是一种动态类型语言, 这意味着给一个定变量名可以在不同的场合绑定到不同的类型上. 在接下面例子中, 同样的函数分别被整数, 浮点数, 以及一个字符串调用:
def function(value):
print value
function(1)
function(1.0)
function("one")
type
函数 (如 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")
<type 'int'> 1
<type 'float'> 1.0
<type 'string'> one
每个类型都有一个对应的类型对象, 所以你可以使用 is
操作符 (对象身份?) 来 检查类型. (如 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"
4672 bytes
4672 bytes
callable
函数, 如 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)
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
注意类对象 (A 和 B) 都是可调用的; 如果调用它们, 就产生新的对象(类实例). 但是 A 类的实例不可调用, 因为它的类没有实现 _ _call_ _
方法.
你可以在 operator
模块中找到检查对象是否为某一内建类型(数字, 序列, 或者字典等) 的函数. 但是, 因为创建一个类很简单(比如实现基本序列方法的类), 所以对这些 类型使用显式的类型判断并不是好主意.
在处理类和实例的时候会复杂些. Python 不会把类作为本质上的类型对待; 相反地, 所有的类都属于一个特殊的类类型(special class type), 所有的类实例属于一个特殊的实例类型(special instance type).
这意味着你不能使用 type
函数来测试一个实例是否属于一个给定的类; 所有的实例都是同样 的类型! 为了解决这个问题, 你可以使用 isinstance
函数,它会检查一个对象是 不是给定类(或其子类)的实例. 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",
a = A()
b = B()
c = C()
d = D()
dump(a)
dump(b)
dump(c)
dump(d)
dump(0)
dump("string")
<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 =>
issubclass
函数与此相似, 它用于检查一个类对象是否与给定类相同, 或者是给定类的子类. 如 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",
dump(A)
dump(B)
dump(C)
dump(D)
dump(0)
dump("string")
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
1.2.5. 计算 Python 表达式
Python 提供了在程序中与解释器交互的多种方法. 例如 eval
函数将一个字符串 作为 Python 表达式求值. 你可以传递一串文本, 简单的表达式, 或者使用 内建 Python 函数. 如 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')")
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'>
如果你不确定字符串来源的安全性, 那么你在使用 eval
的时候会遇到些麻烦. 例如, 某个用户可能会使用 _ _import_ _
函数加载 os
模块, 然后从硬盘删除文件 (如 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')")
/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')
这里我们得到了一个 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_ _
项即可. 如 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_ _": {}})
/home/fredrik/librarybook
Traceback (innermost last):
File "builtin-eval-example-3.py", line 2, in ?
File "<string>", line 0, in ?
NameError: _ _import_ _
即使这样, 你仍然无法避免针对 CPU 和内存资源的攻击. (比如, 形如 eval("'*'*1000000*2*2*2*2*2*2*2*2*2")
的语句在执行后会使你的程序耗尽系统资源).
1.2.6. 编译和执行代码
eval
函数只针对简单的表达式. 如果要处理大块的代码, 你应该使用 compile
和 exec
函数 (如 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
语句执行它, 参见 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
<code object ? at 8c6be0, file "<script>", line 0>
the ant, an introduction
使用 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()
code generation made easy!
code generation made easy!
code generation made easy!
code generation made easy!
code generation made easy!
Python 还提供了 execfile
函数, 一个从文件加载代码, 编译代码, 执行代码的快捷方式. 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")
hello again, and welcome to the show
hello again, and welcome to the show
Example 1-24 中的代码是 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_ _
模块. 例如 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"
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
[!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_ _
方法. 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
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>
1.4. os 模块
这个模块中的大部分函数通过对应平台相关模块实现, 比如 posix
和 nt. os
模块会在第一次导入的时候自动加载合适的执行模块.
1.4.1. 处理文件
内建的 open / file
函数用于创建, 打开和编辑文件, 如 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
函数返回给定目录中所有文件名(包括目录名)组成的列表, 如 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
sample.au
sample.jpg
sample.wav
...
getcwd
和 chdir
函数分别用于获得和改变当前工作目录. 如 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()
1 /ematter/librarybook
2 /ematter/librarybook/samples
3 /ematter/librarybook
makedirs
和 removedirs
函数用于创建或删除目录层,如 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
函数只能处理单个目录级. 如 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
Traceback (innermost last):
File "os-example-7", line 6, in ?
OSError: [Errno 41] Directory not empty: 'samples'
如果需要删除非空目录, 你可以使用 shutil
模块中的 rmtree
函数.
1.4.3. 处理文件属性
stat
函数可以用来获取一个存在文件的信息, 如 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)
#
# get stats for an open file
fp = open(file)
st = os.fstat(fp.fileno())
print "fstat", file
dump(st)
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
返回对象中有些属性在非 Unix 平台下是无意义的, 比如 (st_inode
, st_dev
)为 Unix 下的为每个文件提供了唯一标识, 但在其他平台可能为任意无意义数据 .
stat
模块包含了很多可以处理该返回对象的常量及函数. 下面的代码展示了其中的一些.
可以使用 chmod
和 utime
函数修改文件的权限模式和时间属性,如 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])
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
1.4.4. 处理进程
system
函数在当前进程下执行一个新命令, 并等待它完成, 如 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)
-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
...
命令通过操作系统的标准 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
函数会使用新进程替换当前进程(或者说是"转到进程"). 在 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"
hello again, and welcome to the show
Python 提供了很多表现不同的 exec
函数. Example 1-35 使用的是 execvp
函数, 它会从标准路径搜索执行程序, 把第二个参数(元组)作为单独的参数传递给程序, 并使用当前的环境变量来运行程序. 其他七个同类型函数请参阅 Python Library Reference .
在 Unix 环境下, 你可以通过组合使用 exec
, fork
以及 wait
函数来从当前程序调用另一个程序, 如 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"
hello again, and welcome to the show
goodbye
fork
函数在子进程返回中返回 0 (这个进程首先从 fork
返回值), 在父进程中返回一个非 0 的进程标识符(子进程的 PID ). 也就是说, 只有当我们处于子进程的时候 "not pid
" 才为真.
fork
和 wait
函数在 Windows 上是不可用的, 但是你可以使用 spawn
函数, 如 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"
hello again, and welcome to the show
goodbye
spawn
函数还可用于在后台运行一个程序. 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"
goodbye
hello again, and welcome to the show
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"
hello again, and welcome to the show
goodbye
Example 1-39 首先尝试调用 spawnvp
函数. 如果该函数不存在 (一些版本/平台没有这个函数), 它将继续查找一个名为 spawnv
的函数并且 开始查找程序路径. 作为最后的选择, 它会调用 exec
和 fork
函数完成工作.
1.4.5. 处理守护进程(Daemon Processes)
Unix 系统中, 你可以使用 fork
函数把当前进程转入后台(一个"守护者/daemon"). 一般来说, 你需要派生(fork off)一个当前进程的副本, 然后终止原进程, 如 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 异常, 程序仍然会继续执行. 如 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!"
caught exit(1)
1.5. os.path 模块
os.path
模块包含了各种处理长文件名(路径名)的函数. 先导入 (import) os
模块, 然后就可以以 os.path
访问该模块.
1.5.1. 处理文件名
os.path
模块包含了许多与平台无关的处理长文件名的函数. 也就是说, 你不需要处理前后斜杠, 冒号等. 我们可以看看 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))
using nt ...
split => ('my/little', 'pony')
splitext => ('my/little/pony', '')
dirname => my/little
basename => pony
join => my/little/pony
注意这里的 split
只分割出最后一项(不带斜杠).
os.path
模块中还有许多函数允许你简单快速地获知文件名的一些特征,如 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",
. => EXISTS ISDIR
/ => EXISTS ISABS ISDIR ISMOUNT
file =>
/file => ISABS
samples => EXISTS ISDIR
samples/sample.jpg => EXISTS ISFILE
directory/file =>
../directory/file =>
/directory/file => ISABS
expanduser
函数以与大部分Unix shell相同的方式处理用户名快捷符号(~, 不过在 Windows 下工作不正常), 如 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
函数将文件名中的环境变量替换为对应值, 如 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")
/home/user/config
user/folders
1.5.2. 搜索文件系统
walk
函数会帮你找出一个目录树下的所有文件 (如 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")
./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'
...
walk
函数的接口多少有点晦涩 (也许只是对我个人而言, 我总是记不住参数的顺序). 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
./aifc-example-1.py
./anydbm-example-1.py
./array-example-1.py
...
如果你不想列出所有的文件 (基于性能或者是内存的考虑) , 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
./aifc-example-1.py
./anydbm-example-1.py
./array-example-1.py
...
注意 DirectoryWalker 类并不检查传递给 _ _getitem_ _
方法的索引值. 这意味着如果你越界访问序列成员(索引数字过大)的话, 这个类将不能正常工作.
最后, 如果你需要处理文件大小和时间戳, 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]
./aifc-example-1.py 336
./anydbm-example-1.py 244
./array-example-1.py 526
1.6. stat 模块
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 "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])
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
1.7. string 模块
string
模块提供了一些用于处理字符串类型的函数, 如 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")
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
在 Python 1.5.2 以及更早版本中, string
使用 strop
中的函数来实现模块功能.
在 Python1.6 和后继版本,更多的字符串操作都可以作为字符串方法来访问, 如 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")
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
为了增强模块对字符的处理能力, 除了字符串方法, string
模块还包含了类型转换函数用于把字符串转换为其他类型, (如 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")
4711 4711 4711 4711 4711
4711 2505 18193
4711.0 1.0 123000.0
大多数情况下 (特别是当你使用的是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
尝试从字符串的起始匹配一个模式, 如