模块的编写
创建你自己的模块很简单,其实你一直在这样做!因为每个python脚本都是一个模块。你只需确保它带有.py扩展名即可。
下面的例子会让你对其有一个清晰的认识:
示例
1 2 3 4 5 6 7 8 9 def sayhi () : print('Hi, this is mymodule speaking.' ) __version__ = '0.1'
上面就是一个简单的模块,如你所见,这和我们平时的python程序相比没有什么特别之处。记住模块应该放到导入它的那个程序所在的目录下,或者放到sys.path列出的目录之一中。
模块的导入
使用 import 语句
可以使用 import 语句导入模块。
示例
1 2 3 4 5 6 7 import mymodulemymodule.sayhi() print ('Version' , mymodule.__version__)
输出
1 2 3 $ python mymodule_demo.py Hi, this is mymodule speaking. Version 0.1
import 会在哪些目录里查找模块呢?可以通过 sys.path
查看:
1 2 3 4 5 6 >>> import sys>>> sys.path['' , '/usr/bin' , '/usr/lib/python33.zip' , '/usr/lib/python3.3 ' , '/usr/lib/python3.3/plat-linux' , '/usr/lib/python3.3/lib-d ynload' , '/usr/lib/python3.3/site-packages' , '/usr/lib/python 3.3/site-packages/setuptools-0.6c11.egg-info' ]
要添加一个新的目录到 sys.path
列表的第一项(从而使其出现在python搜索路径的开头,并且优先级最高),可以使用sys.path.insert(0, newpath)
。
使用 from…import…语句
如果你希望将变量argv直接导入到你的程序中(避免每次输入sys.
),那么可以使用from sys import argv
语句。
如果希望导入sys模块中的所有名字(除了以__
开头的名字),则from sys import *
可以做到。此语句可以用于任何模块。
通常你应该避免 使用这个语句并用import语句代替之,因为使用后者可以避免名字冲突,程序的可读性也更好。
示例
下面是一个使用from…import语法的版本:
1 2 3 4 5 6 from mymodule import sayhi, __version__sayhi() print('Version' , __version__)Python en:Modules 59
mymodule_demo2.py
与mymodule_demo
的输出完全相同。
注意,如果导入mymodule的模块中已经存在同名的__version__
,则将发生名字冲突。
事实上这很可能发生,因为每个模块都用__version__
声明它的版本是一种常见的做法。
因此建议你优先考虑import
语句,虽然它可能会让你的程序变的更长一些。
你同样可以使用:
这将导入模块的所有公有名字,例如sayhi
,但是不会导入__version__
因为它以双下划线开头。
字节编译文件 .pyc
导入模块是一个相对昂贵的操作,所以python使用了一些技巧加速这个过程。
一个办法是创建后缀为.pyc的字节编译文件用于将程序转换为中间格式。(还记得介绍python如何工作的那一节吗?)
当你下次从其他文件导入模块时pyc文件会非常有用 – 它将大大增加导入速度,因为导入模块的部分操作已经预先完成了。
并且这个字节编译文件仍然是平台无关的。
.pyc文件一般被创建在与其对应的.py文件所在的相同目录下。如果python没有这个目录的写权限,则.pyc文件不会被创建。
### 模块的`__name__`属性 ###
每个模块都有一个名字,并且通过模块中的某些语句可以得到这个模块名。在一些想要搞清模块是独立运行还是被导入的情况下,这会非常方便。
如前所述当模块第一次被导入时模块中的代码会被执行。我们可以据此改变模块独立执行时的行为方式。这可以通过模块的`__name__`属性做到。(注:独立运行是指程序最开始运行的那个脚本文件(/模块))
#### 示例 ####
1 2 3 4 5 6 7 if __name__ == '__main__' : print('This program is being run by itself' ) else : print('I am being imported from another module' )
#### 输出 ####
1 2 3 4 5 6 7 8 9 10 $ python using_name.py This program is being run by itself $ python >>> import using_name I am being imported from another module >>>
### 重新加载模块 ###
因为效率的原因, 每个模块在每个解释器会话中只被导入一次. 一旦你修订了你的模块, 就需要重启解释器 —— 或者, 若你只是想交互式地测试一个模块,使用 imp.reload()
,例如 import imp; imp.reload(modulename)
查看已定义的所有标识符
你可以使用dir
函数列出一个对象定义的所有标识符。例如对于一个模块,标识符包括函数,类,变量。
当你为dir()
函数提供一个模块名,它将返回定义在其中的所有名字。
当dir()
的参数为空时,返回定义在当前模块中所有名字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 >>> import sys >>> dir(sys)['__displayhook__' , '__doc__' , '__excepthook__' , '__loader__' , '__name__' , '__package__' , '__stderr__' , '__stdin__' , '__stdout__' , '_clear_type_cache' , '_current_frames' , '_debugmallocstats' , '_getframe' , '_home' , '_mercurial' , '_xoptions' , 'abiflags' , 'api_version' , 'argv' , 'base_exec_prefix' , 'base_prefix' , 'builtin_module_names' , 'byteorder' , 'call_tracing' , 'callstats' , 'copyright' , 'displayhook' , 'dont_write_bytecode' , 'exc_info' , 'excepthook' , 'exec_prefix' , 'executable' , 'exit' , 'flags' , 'float_info' , 'float_repr_style' , 'getcheckinterval' , 'getdefaultencoding' , 'getdlopenflags' , 'getfilesystemencoding' , 'getprofile' , 'getrecursionlimit' , 'getrefcount' , 'getsizeof' , 'getswitchinterval' , 'gettrace' , 'hash_info' , 'hexversion' , 'implementation' , 'int_info' , 'intern' , 'maxsize' , 'maxunicode' , 'meta_path' , 'modules' , 'path' , 'path_hooks' , 'path_importer_cache' , 'platform' , 'prefix' , 'ps1' , 'ps2' , 'setcheckinterval' , 'setdlopenflags' , 'setprofile' , 'setrecursionlimit' , 'setswitchinterval' , 'settrace' , 'stderr' , 'stdin' , 'stdout' , 'thread_info' , 'version' , 'version_info' , 'warnoptions' ] >>> del sys >>> dir(sys)Traceback (most recent call last): File "<stdin>" , line 1 , in <module> NameError: name 'sys' is not defined >>> dir() ['__builtins__' , '__doc__' , '__loader__' , '__name__' , '__package__' ] >>> a = 5 >>> dir()['__builtins__' , '__doc__' , '__name__' , '__package__' , 'a' , 'sys' ] >>> del a >>> dir()['__builtins__' , '__doc__' , '__name__' , '__package__' , 'sys' ]
模块的组织:包
如今,你必须开始留心组织你的程序层次了。
变量在函数内部,函数和全局变量通常在模块内部。那么如何组织模块呢?这就轮到包登场了。
包仅仅是包含模块的文件夹,并带有一个特殊的文件__init__.py
用于指示python这个文件夹是特殊的,因为它包含python模块 。
让我们假设你需要创建一个叫做world
的包,里面包括诸如asia
,africa
等的子包。
下面告诉你应该如何组织文件夹结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 -<some folder present in the sys.path>/ - world/ - __init__.py - asia/ - __init__.py - india/ - __init__.py - foo.py - africa/ - __init__.py - madagascar/ - __init__.py - bar.py
包只是用来有层次的组织模块。你会在标准库中看到它的很多应用。
模块的发布
关于打包的详细信息,可以参考打包 。
第三方模块的安装
如果装了 Vitualenv 库,它也自带了 pip installer, 因此也可以使用:
常用库
下面简单介绍一些常用的库:
sys模块
sys
模块包含一些系统相关的功能。
获取参数列表
一个常见的功能是利用它获取 argv 变量 —— 具体说sys.argv是一个包含命令行参数的列表,其首项为该程序的名称,第二个参数及后续的参数为该程序的命令行参数(有点像shell语言的 $0
为程序名称,$1
之后为命令行参数)。
示例
1 2 3 4 5 6 7 8 9 10 11 import sysprint('The command line arguments are:' ) for i in sys.argv: print(i) print('\n\nThe PYTHONPATH is' , sys.path, '\n' )
输出
1 2 3 4 5 6 7 8 9 $ python using_sys.py we are arguments The command line arguments are: using_sys.py we are arguments The PYTHONPATH is ['' , '/usr/lib/python33.zip' , '/usr/lib/python3.3' , '/usr/lib/python3.3/plat-linux' , '/usr/lib/python3.3/lib-dynload' , '/usr/lib/python3.3/site-packages' , '/usr/lib/python3.3/site-packages/setuptools-0.6c11.egg-info' ]
说明
当python执行import sys
语句时,它将查找sys模块。本例中sys是内建模块之一,因此python知道在哪能找到它。如果导入的不是一个编译模块,即不是用python编写的模块,python解释器会在变量sys.path
中列出的目录中查找它。如果模块被找到,这个模块中的语句将被执行然后你就可以使用它了(注: 只有顶级语句才会执行 ,也就是主块中的语句)。
注意一个模块只有在第一次导入时会被初始化 。
sys模块中的argv通过点号引用即sys.argv
。它清晰的指出这个名字是sys模块中的一部分。这种语法的另一个优势是不会和你的程序中的同名argv变量发生冲突。
sys.path
包含一个目录名列表指示从哪里导入模块。观察程序输出,sys.path的第一个字符串为空 —— 其指出当前目录也是sys.path
的一部分,这与PYTHONPATH
环境变量是相同的。这意味着你可以直接导入当前目录下的模块,否则你就必须将你的模块放到sys.path
列出的目录中的一个了。
注意程序在哪个目录运行的,这个目录就是这个程序的当前目录。运行import os; print(os.getcwd())
可以看到你的程序的当前目录。
Windows用户注意 : windows下sys.path[0]可能不为空,而是显式指出当前路径。
#### 检查python版本 ####
假设我们想要检查所使用的python命令行的版本,比方说我们需要确定正在使用的版本不低于3。
诸如此类的功能正是sys模块所提供的。
##### 示例 #####
1 2 3 4 5 >>> import sys>>> sys.version_info(3 , 0 , 0 , 'beta' , 2 ) >>> sys.version_info[0 ] >= 3 True
##### 说明 #####
`sys`模块含有一个`version_info`元组用于提供版本信息。其第一个元素为主版本。
因此我们可以通过检查它确保程序只会运行在python 3.0和3.0以上:
##### 示例 #####
1 2 3 4 5 6 7 8 9 10 import sys, warningsif sys.version_info[0 ] < 3 : warnings.warn("Need Python 3.0 for this program to run" , RuntimeWarning) else : print('Proceed as normal' )
##### 输出 #####
1 2 3 4 5 $ python2.5 versioncheck.py versioncheck.py:6: RuntimeWarning: Need Python 3.0 for this program to run RuntimeWarning) $ python3 versioncheck.py Proceed as normal
### os 模块 ###
Python 3 带有一个模块叫做`os`,代表 “操作系统(operating system)。” `os` 模块 包含非常多的函数用于获取(和修改)本地目录、文件进程、环境变量等的信息。Python 尽最大的努力在所有支持的操作系统上提供一个统一的API, 这样你就可以在保证程序能够在任何的计算机上运行的同时尽量少的包含平台特定的代码。
##### 示例1: 处理当前工作目录 #####
`os` 模块提供了两个函数处理当前工作目录
1 2 3 4 5 6 >>> import os>>> print(os.getcwd())C:\Python31 >>> os.chdir('/Users/pilgrim/diveintopython3/examples' ) >>> print(os.getcwd())C:\Users\pilgrim\diveintopython3\examples
#### os.path ####
`os.path` 模块包含了操作文件名和目录名的函数。
| 函数名 | 用途 |
|-----------------------------|----------------------------------------------------------------------------------------------------------------------------------|
| `abspath(path)` | 返回绝对路径。 |
| `basename(p)` | 返回路径名最后的部分。 |
| `commonprefix(m)` | 给定一个路径列表,返回从起始算起最长的公共部分。 |
| `dirname(p)` | 返回给定路径名所在的目录的路径。 |
| `exits(p)` | 测试一个文件是否存在。如果不存在,返回`False`。 |
| `expanduser(path)` | 扩展`~`和`~user`为完整的路径。如果`user`或`$HOME`不存在,不做任何事情。 |
| `expandvars(path)` | 扩展形式为`$var`和`${var}`的shell变量,未知变量将保持不变。 |
| `getatime(filename)` | 返回指定文件的最近访问时间。 |
| `getctime(filename)` | 返回指定文件的元数据的修改时间。 |
| `getmtime(Filename)` | 返回指定文件的最近修改时间。 |
| `getsize(Filename)` | 返回文件的大小。 |
| `isabs(s)` | 测试一个路径是否为绝对路径。 |
| `isdir(s)` | 测试一个路径名是否指向一个存在的目录。 |
| `isfile(s)` | 测试一个路径是否为一个常规的文件。 |
| `islink(path)` | 测试一个路径是否为一个符号链接。 |
| `ismount(path)` | 测试一个路径是否为一个挂载点。 |
| `join(a, *p)` | 将两个或多个路径部分连接。必要时自动插入`/`。 |
| `lexists(path)` | 测试一个路径是否**不**存在。如果不存在,返回`True`。 |
| `normcase(s)` | 将路径名转为标准形式。在Posix标准文件系统下没有什么变化。 |
| `normpath(path)` | 将路径名标准化,例如消除双重斜杠,等。 |
| `realpath(Filename)` | 返回文件所在的真实路径,消除路径中遇到的任何符号连接。 |
| `relpath(path, start=None)` | 返回给定路径的相对路径。 |
| `samefile(f1, f2)` | 测试两个路径是否引用同一个文件。 |
| `sameopenfile(fp1, fp2)` | 测试两个打开的文件对象是否引用同一个文件。 |
| `samestat(s1, s2)` | 测试两个stat缓冲是否引用同一个文件。 |
| `split(p)` | 分割路径名,返回一个形式为`(head, tail)`的元组,其中,`tail`是最后一个斜杠后的所有内容,其他部分则为`head`。任一部分都允许为空。 |
| `splitdrive(p)` | 将路径名分割成驱动名`drive`和路径`path`。在Posix标准的文件系统下,`drive`部分为空。 |
| `splitext(p)` | 从路径名分割出扩展名和其他部分。返回`(root, ext)`元组。`ext`部分可能为空。 |
##### 示例2: 处理文件名和目录名 #####
1 2 3 4 5 6 7 8 9 >>> import os >>> print(os.path.join('/Users/pilgrim/diveintopython3/examples/' , 'humansize.py' ))/Users/pilgrim/diveintopython3/examples/humansize.py >>> print(os.path.join('/Users/pilgrim/diveintopython3/examples' , 'humansize.py' ))/Users/pilgrim/diveintopython3/examples\humansize.py >>> print(os.path.expanduser('~' )) c:\Users\pilgrim >>> print(os.path.join(os.path.expanduser('~' ), 'diveintopython3' , 'examples' , 'humansize.py' ))c:\Users\pilgrim\diveintopython3\examples\humansize.py
`os.path.expanduser()`用来将包含`~`符号(表示当前用户Home 目录)的路径扩展为完整的路径。在任何有 Home 目录概念的操作系统上(包括 Linux,Mac OS X 和 Windows),这个函数都能工作。返回的路径不以斜杠结尾,但是 `os.path.join()` 并不介意这一点。
##### 示例3: 分割完整路径名,目录名和文件名 #####
os.path 也包含用于分割完整路径名,目录名和文件名的函数:
1. `os.path.split`:分割一个完整路径并返回目录和文件名。
2. `os.path.splitext`: 分割一个文件名并返回短文件名和扩展名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 >>> pathname = '/Users/pilgrim/diveintopython3/examples/humansize.py' >>> os.path.split(pathname) ('/Users/pilgrim/diveintopython3/examples' , 'humansize.py' ) >>> (dirname, filename) = os.path.split(pathname) >>> dirname '/Users/pilgrim/diveintopython3/examples' >>> filename'humansize.py' >>> (shortname, extension) = os.path.splitext(filename) 5 >>> shortname 'humansize' >>> extension '.py'
##### 示例4: 获取文件元信息 #####
每一个现代文件系统都对文件存储了元信息: 创建时间,最后修改时间,文件大小等等。Python 单独提供了一个的 API 用于访问这些元信息。你不需要打开文件。知道文件名就足够了。
1. `os.stat(文件名)`:返回一个包含多种文件元信息的对象。
2. `os.st_mtime()`:获取最后修改时间
3. `os.st_size`:返回文件大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 >>> import os >>> print(os.getcwd()) c:\Users\pilgrim\diveintopython3\examples >>> metadata = os.stat('feed.xml' ) >>> metadata.st_mtime 1247520344.9537716 >>> import time >>> time.localtime(metadata.st_mtime)time.struct_time(tm_year=2009 , tm_mon=7 , tm_mday=13 , tm_hour=17 , tm_min=25 , tm_sec=44 , tm_wday=0 , tm_yday=194 , tm_isdst=1 ) >>> metadata.st_size 3070 >>> import humansize >>> humansize.approximate_size(metadata.st_size)'3.0 KiB'
##### 示例5:构造绝对路径 #####
当你希望构造一个从根目录开始或者是包含盘符的绝对路径时,可以使用`os.path.realpath()`函数。
1 2 3 4 5 >>> import os >>> print(os.getcwd()) c:\Users\pilgrim\diveintopython3\examples >>> print(os.path.realpath('feed.xml' )) c:\Users\pilgrim\diveintopython3\examples\feed.xml
### time 模块 ###
`time` 模块可用于获取当前日期和时间,比如 `time.strftime` 方法
1 time.strftime('%Y-%m-%d',time.localtime(time.time()))
time.strftime里面有很多参数,可以让你能够更随意的输出自己想要的东西:
* `%y` 两位数的年份表示(00-99)
* `%Y` 四位数的年份表示(000-9999)
* `%m` 月份(01-12)
* `%d` 月内中的一天(0-31)
* `%H` 24小时制小时数(0-23)
* `%I` 12小时制小时数(01-12)
* `%M` 分钟数(00=59)
* `%S` 秒(00-59)
* `%a` 本地简化星期名称
* `%A` 本地完整星期名称
* `%b` 本地简化的月份名称
* `%B` 本地完整的月份名称
* `%c` 本地相应的日期表示和时间表示
* `%j` 年内的一天(001-366)
* `%p` 本地A.M.或P.M.的等价符
* `%U` 一年中的星期数(00-53)星期天为星期的开始
* `%w` 星期(0-6),星期天为星期的开始
* `%W` 一年中的星期数(00-53)星期一为星期的开始
* `%x` 本地相应的日期表示
* `%X` 本地相应的时间表示
* `%Z` 当前时区的名称
* `%%` %号本身
### glob模块 ###
glob 模块是 Python 标准库中的另一个工具,它可以通过编程的方法获得一个目录的内容,并且它使用熟悉的命令行下的通配符。 glob 模块使用 shell 风格的通配符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 >>> os.chdir('/Users/pilgrim/diveintopython3/' ) >>> import glob >>> glob.glob('examples/*.xml' )['examples\\feed‐broken.xml' , 'examples\\feed‐ns0.xml' , 'examples\\feed.xml' ] >>> os.chdir('examples/' )>>> glob.glob('*test*.py' ) ['alphameticstest.py' , 'pluraltest1.py' , 'pluraltest2.py' , 'pluraltest3.py' , 'pluraltest4.py' , 'pluraltest5.py' , 'pluraltest6.py' , 'romantest1.py' , 'romantest10.py' , 'romantest2.py' , 'romantest3.py' , 'romantest4.py' , 'romantest5.py' , 'romantest6.py' , 'romantest7.py' , 'romantest8.py' , 'romantest9.py' ]
### re 模块 ###
正则表达式模块,常见的正则式有:
| 模式 | 说明 |
|------|--------|
| `.` | 匹配任意字符 |
| `^` | 匹配字符串开始位置。 |
| `$` | 匹配字符串结束位置。 |
| `\b` | 匹配一个单词边界。 |
| `\d` | 匹配一个数字。 |
| `\D` | 匹配一个任意的非数字字符。 |
| `x?` | 匹配可选的 x 字符。换句话说,就是 0 个或者 1 个 x 字符。 |
| `x*` | 匹配 0 个或更多的 x。 |
| `x+` | 匹配 1 个或者更多 x。 |
| `x{n,m}` | 匹配 n 到 m 个 x,至少 n 个,不能超过 m 个。 |
| `(a|b|c)` | 匹配单独的任意一个 a 或者 b 或者 c。 |
| `(x)` | 把括号里匹配得到的内容作为一个组,它会记忆它匹配到的字符串。你可以用`re.search`返回的匹配对象的`groups()`函数来获取到匹配的值。 |
更多支持的正则式请参见 `help(re)`。常用的正则式可以参见[正则表达式](/wiki/sundries.regexp.html#常用正则式)。
##### 示例一:查找 #####
查找地址中的单词 'ROAD':
1 2 3 4 5 6 7 8 9 10 11 12 13 >>> s = '100 BROAD ROAD. APT 3' >>> re.search(r'\bROAD\b' ,s)<_sre.SRE_Match object at 0x7f0f85cb17e8 > >>> pattern = '^M{0,3}$' >>> re.search(pattern, 'M' ) <_sre.SRE_Match object at 0x008EEB48 > >>> re.search(pattern, 'MM' ) <_sre.SRE_Match object at 0x008EE090 > >>> re.search(pattern, 'MMM' ) <_sre.SRE_Match object at 0x008EEDA8 > >>> re.search(pattern, 'MMMM' )>>> re.findall('[0-9]+' , '16 2-by-4s in rows of 8' ) ['16' , '2' , '4' , '8' ]
也可以先构造一个模式的类然后用它进行查找:
1 2 3 4 >>> s = '100 BROAD ROAD. APT 3' >>> mypattern = re.compile(r'\bROAD\b' )>>> mypattern.search(s)<_sre.SRE_Match object at 0x7f141e9cb7e8 >
##### 示例二:替换 #####
替换地址中的 'ROAD' 字符串为 'RD.':
1 2 3 >>> s = '100 BROAD ROAD. APT 3' >>> re.sub(r'\bROAD\b' , 'RD.' , s)'100 BROAD RD. APT 3'
##### 说明 #####
在 python 中,比较复杂的是 `\` 字符必须被转义,这有的时候会导致 `\` 字符传染(想想可能还要对`\`字符做转义的情况)。
为了解决 `\` 字符传染的问题,可以使用原始字符串。这只需要在字符串的前面添加一个字符`r`。它告诉 python,字符串中没有任何字符需要转义。`\t`是一个制表符,但 r`\t` 只是一个字符 `\` 紧跟着一个字符 t。
建议 :在处理正则表达式的时候总是使用原始字符串。否则,会因为理解正则表达式而消耗大量时间(本身正则表达式就已经够让人困惑的了)。
松散表达式
python 允许你使用松散正则表达式来达到目的。松散正字表达式和普通紧凑的正则表达式有两点不同:
空白符被忽略。空格、制表符和回车在正则表达式中并不会匹配空格、制表符、回车。如果你想在正则表达式中匹配他们,可以在前面加一个\
来转义。
注释信息被忽略。松散正字表达式中的注释和 python 代码中的一样,都是以#
开头直到行尾。它可以在多行正则表达式中增加注释信息,这就避免了在 python 代码中的多行注释。他们的工作方式是一样的。
示例
判断一串字符是否为合法的罗马数字:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 >>> pattern = ''' ^ # beginning of string M{0,3} # thousands ‐ 0 to 3 Ms (CM|CD|D?C{0,3}) # hundreds ‐ 900 (CM), 400 (CD), 0‐300 (0 to 3 Cs), # or 500‐800 (D, followed by 0 to 3 Cs) (XC|XL|L?X{0,3}) # tens ‐ 90 (XC), 40 (XL), 0‐30 (0 to 3 Xs), # or 50‐80 (L, followed by 0 to 3 Xs) (IX|IV|V?I{0,3}) # ones ‐ 9 (IX), 4 (IV), 0‐3 (0 to 3 Is), # or 5‐8 (V, followed by 0 to 3 Is) $ # end of string ''' >>> re.search(pattern, 'M' , re.VERBOSE) <_sre.SRE_Match object at 0x008EEB48 > >>> re.search(pattern, 'MCMLXXXIX' , re.VERBOSE)<_sre.SRE_Match object at 0x008EEB48 > >>> re.search(pattern, 'MMMDCCCLXXXVIII' , re.VERBOSE) <_sre.SRE_Match object at 0x008EEB48 > >>> re.search(pattern, 'M' )
说明
注意,如果要使用松散正则表达式,需要传递一个叫 re.VERBOSE
的参数。就像你看到的那样,正则表达式中有很多空白符,他们都被忽略掉了。还有一些注释信息,当然也被正则表达式忽略掉。当空白符和注释信息被忽略掉后,这个正则表达式和上面的是完全一样的,但是它有更高的可读性。
logging模块
如果你希望得到存储在某处的重要信息或调试信息,以便检查程序是否如期运行时该咋办呢?你如何将这些信息存储在某处呢?
这些可以通过logging
模块做到。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import os, platform, loggingif platform.platform().startswith('Windows' ): logging_file = os.path.join(os.getenv('HOMEDRIVE' ),os.getenv('HOMEPATH' ), 'test.log' ) else : logging_file = os.path.join(os.getenv('HOME' ), 'test.log' ) logging.basicConfig( level=logging.DEBUG, format='%(asctime)s : %(levelname)s : %(message)s' , filename = logging_file, filemode = 'w' , ) logging.debug("Start of the program" ) logging.info("Doing something" ) logging.warning("Dying now" )
输出
1 2 $python use_logging.pyLogging to C:/Users/swaroop/test.log
如果我们查看生成的日志文件 test.log ,它的内容如下:
1 2 3 2008-09-03 13:18:16,233 : DEBUG : Start of the program 2008-09-03 13:18:16,233 : INFO : Doing something 2008-09-03 13:18:16,233 : WARNING : Dying now
说明
我们使用了3个标准库模块 —— os
模块与系统交互,platform
模块取得平台信息,即操作系统信息。而logging
模块用于记录日志信息。
首先,我们通过platform.platform
(详见help(platform)
)返回的字符串检测操作系统类型。如果为windows系统,则分别计算出主驱动器,主目录与文件名,这个文件用于存储相关信息。然后将这三部分合并得到文件的全路径。对于其他平台,我们只需得到用户的主目录就能计算出文件的全路径了。
我们之所以没有简单的使用字符串连接合并这三部分而是利用os.path.join
,原因在于这个特殊的函数可以确保路径格式符合特定系统的规范。
之后我们配置logging模块,指示在我们指定的文件中以特殊的格式写入所有信息。最后,我们就能写入信息了,它们可以是调试信息,警告信息甚至是危机信息(critical messages)。
一但程序开始运行,我们就可以检查这个文件以了解程序发生了什么,而用户并不会看到这些信息。
Python之禅
执行import this
可以看到《Python 之禅》。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 >>> import thisThe Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you' re Dutch.Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let' s do more of those!
这里的讨论 列出了每个原则的范例。
常用模块不完全列表
Python增强
模块名
用途
re
实现了对正则表达式(regular expression)的支持
array
数组
queue
队列
copy
复制对象
string
定义了一些有用的常量,比如 ascii_letters
与ascii_lowercase
textwrap
提供了用于包裹与填充字符串的函数与方法
unicodedata
获取unicode字符和相关信息
logging
记录日志信息
pdb
调试
timeit
对代码进行即时
cProfile
用于比较函数与方法的性能。精确的展示了有什么被调用及每个调用耗费了多少时间。
itertools
为创建和使用迭代器提供很多便利工具,例如排列组合等。
unittest
单元测试模块
文件格式
模块名
用途
pickle
以二进制格式存储/读取对象
ElementTree
解析XML,详见解析XML 。
lxml
非标准库,提供比 ElementTree 更完善的XML Xpath支持
json
读写json
数值计算
模块名
用途
fractions
使用分数以及分数的运算
decimal
更精确的进行小数运算(速度慢一些)
random
产生随机数、随机取样等
math
补充了一些重要的数学常数和数学函数
cmath
专门提供复数使用的数学函数
numpy
非标准库中的包 ,但它的数组运算的良好支持,让它在基于Python的科研和计算方面得到相当广泛的应用。
系统交互
模块名
用途
sys
管理Python自身的运行环境
os
包含非常多用于获取(和修改)本地目录、文件进程、环境变量等的信息
time
管理时间
datetime
管理日期和时间
glob、shutil
文件管理
difflib
用于比较文件(或字符串)之间的区别
subprocess
执行外部命令,其功能相当于我们在操作系统的命令行中输入命令以执行
platform
获取平台信息
threading
多线程
multiprocessing
多进程
getopt
处理命令行选项
humansize
非标准库 ,获取文件大小信息,带kiB等单位
网络
模块名
用途
socket
网络可编程部分的底层
asyncore
实现异步处理
urlparse
URL理解和操作
sqlite3
数据库
http.client, BaseHTTPServer、urllib、urllib2
http服务
httplib2
http服务第三方开源库
Module of the Week
进一步研究标准库的最好办法就是阅读Python Module of the Week 系列,或者Python的官方文档 。