第10章 | 充电时刻
本章主要介绍模块及其工作机制
------
模块
>>> import math
>>> math.sin(0)
0.0
模块是程序
一个简单的模块
#hello.py print ("Hello,World!") >>> import hello Traceback (most recent call last): File "<pyshell#56>", line 1, in <module> import hello ImportError: No module named hello >>> import sys >>> sys.path.append('d:/python')#这里所做的只是告诉解释器,除了从默认的目录寻找外,还需要从d:/python目录下寻找模块。或者将刚才的hello.py放到python的安装目录也是可以的。
>>> import hello Hello,World!注意:hello.pyc文件出现,该文件是平台无关的,经过处理的,已经转换成Python能够有效处理的文件。如果稍后导入同一模块,python会导入.pyc文件,而不是.py文件,除非.py文件已改变。删除.pyc文件不会损害程序,只要等效的.py文件存在即可。
>>> import hello
再次导入就什么都没有,这是因为导入模块并不意味着在导入时执行某些操作,比如说打印文件。它们主要用于定义,比如变量、函数和类等。此外,因为只需要定义这些东西一次,导入模块多次和导入一次的效果是一样的。只导入一次!如果坚持要导入的话,可以用reload(hello)
>>> reload(hello) Hello,World! <module 'hello' from 'd:/python\hello.pyc'>------
模块用于定义:
在模块中定义函数:
#hello2.py def hello(): print ("Hello,World!") >>> import hello2#可以用下面方式来访问函数
>>> hello2.hello() Hello,World!为什么不在主程序中写好一起呢?主要是为了代码的重用,如果把代码放到模块中的话,就可以多个模块使用它了。因为,请记住:如果让代码可重用,请将它模块化。
在模块中增加测试代码
#hello3.py def hello(): print ("Hello,World!") #A Test hello()#这看起来是合理的-如果将其作为普通程序运行,会发现它能够正常工作,但如果将其作为模块导入,然后再其他程序中使用hello函数,测试代码就会被执行.
>>> import hello3 Hello,World! >>> hello3.hello() Hello,World!这可能不是我们想要的。避免这种情况的关键在于:告知模块本身是作为程序运行呢? 还是导入到其他程序,为了实现这一点,需要使用__name__变量:
>>> __name__ '__main__' >>> hello3.__name__ 'hello3'在主程序(包括解释器的交互式提示符在内)中,变量__name__的值是'__main__',因此为了让测试模块更加好用,可以加入if条件进行判断,是主程序在掉的话,则运行测试模块,如果只是作为模块导入的话,则不运行测试模块,即整个程序.
#hello4.py def hello(): print ("Hello,World!") #A Test def test(): hello() if __name__=='__main__': test()输出结果:
>>> import hello4 >>> hello4.hello() Hello,World!这样更加灵活,即使将其作为模块导入其他程序中,依然可以对其进行测试。
>>> hello4.test() Hello,World!
NOTE: 如果需要编写更完善的测试代码,将其放置在单独的程序中,效果会更好。
------
让你的模块有用:
一是:将模块放置在正确的位置.
二是:告诉解释器去那里寻找需要的模块
将模块放置在正确的位置
目录列表可以再sys.path里面找到
>>> import sys,pprint >>> pprint.pprint(sys.path) ['', 'C:\\Python27\\Lib\\idlelib', 'C:\\WINDOWS\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 'C:\\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Python27\\lib\\site-packages', 'C:\\Python27\\lib\\site-packages\\wx-2.8-msw-unicode']尽管这些目录都可以使用,但site-packages目录是最佳选择,专门用来放置模块的,将之前的hello4.py放在这里
>>> import hello >>> hello.test() Hello,World!NOTE:如果数据结构过大,不能一行打印完,可用pprint函数。pprint是个非常的打印函数,可以提供更加智能的打印输出.
------
告诉编译器去那里找
1. 如果不希望将自己的模块填满Python解释器的目录.
2. 如果没有在Python解释器目录存放文件的权限
3. 如果想将模块放在其他地方。
那么就需要告诉解释器去哪里找。
一种是编辑sys.path,但这只是临时生效,所以不常用
>>> sys.path.append('d:/python')
一种是在PYTHONPATH中包含模块的目录.
Win: PYTHONPATH=C:\Python27;.; Lin: 设置.bashrc文件 export PYTHONPATH=$PYTHONPATH:~/python------
包
模块所在的目录。为了让Python将其作为包对待,必须包含一个__init__.py的模块。如果将它作为普通模块导入的话,文件的内容就是包的内容。比如说有个constants的包,文件constants/__init__.py包括语句PI=3.14,那么可以这样使用.
>>> import constants >>> constants.PI 3.14 >>> dir(constants) ['PI', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']假如drawing包下,包括color,shape,__init__模块,且都加到了PYTHONPATH里面了。
下面三种方式都可以
>>> import drawing >>> import drawing.color >>> from drawing import shape------
探究模块:
模块中有什么:
1.使用dir
#她会将对象的所有特性列出,包括模块的所有函数,类,变量
>>> import copy >>> dir(copy) ['Error', 'PyStringMap', '_EmptyClass', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_copy_dispatch', '_copy_immutable', '_copy_inst', '_copy_with_constructor', '_copy_with_copy_method', '_deepcopy_atomic', '_deepcopy_dict', '_deepcopy_dispatch', '_deepcopy_inst', '_deepcopy_list', '_deepcopy_method', '_deepcopy_tuple', '_keep_alive', '_reconstruct', '_test', 'copy', 'deepcopy', 'dispatch_table', 'error', 'name', 't', 'weakref']#其中很多是__开始的,用列表推导式filter过滤一下,就成了:
>>> [n for n in dir(copy) if not n.startswith('_')]
['Error', 'PyStringMap', 'copy', 'deepcopy', 'dispatch_table', 'error', 'name', 't', 'weakref']
------
2. __all__变量
#这个变量包含一个列表,可以看看
>>> copy.__all__
['Error', 'copy', 'deepcopy']
如何设置的呢? 它是在copy模块内部被设置的
__all__ = ['Error','copy','deepcopy']
那么它为什么在那呢? 它定义了模块的公有接口(public interface)。更准确地说,它告诉解释器:从模块导入所有名字代表什么含义。如果使用如下代码:
>>> from copy import *
那么只能使用__all__变量中的3个函数。如果要导入PyStringMap的话,就得copy.PyStringMap,或者from copy import PyStringMap.
NOTE: 在编写模块的时候,设置__all__是非常有用的.
如果设置的话,模块中一大陀不需要的变量,函数和类,下化线,__all__都会将他们过滤除去。
如果没设置的话,import *默认将输出所有模块中所有非_开头的全局名称.
------
用help获取帮助:
>>> help(copy) Help on module copy: NAME copy - Generic (shallow and deep) copying operations. FILE c:\python27\lib\copy.py DESCRIPTION Interface summary: import copy x = copy.copy(y) # make a shallow copy of y x = copy.deepcopy(y) # make a deep copy of y ... >>> help(copy.copy) Help on function copy in module copy: copy(x) Shallow copy operation on arbitrary Python objects. See the module's __doc__ string for more info. >>> copy.copy.__doc__ #copy模块的copy函数的文档 "Shallow copy operation on arbitrary Python objects.\n\n See the module's __doc__ string for more info.\n "------
文档:
如果要查看有关range的描述
>>> range.__doc__ 'range(stop) -> list of integers\nrange(start, stop[, step]) -> list of integers\n\nReturn a list containing an arithmetic progression of integers.\nrange(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.\nWhen step is given, it specifies the increment (or decrement).\nFor example, range(4) returns [0, 1, 2, 3]. The end point is omitted!\nThese are exactly the valid indices for a list of 4 elements.'如果想说明透彻描述这些模块,函数如何工作的,就得学会库参考。学习Python编程,最重要的莫过于Python库参考. https://www.python.org/doc/lib
可以在线查阅,也供下载
所有文档可以再此网站找到
https://www.python.org/doc/
------
使用源代码:
学些Python,最好的方法,首先是自己学代码,其次是学习源代码。
如何找首先在sys.path里面找,其次是检查__file__属性
>>> copy.__file__
'C:\\Python27\\lib\\copy.pyc'
NOTE:
1.如果是.pyc结尾的,找对应的.py就可以了。
2.有些模块并没有源代码,比如用C语言写的sys模块,她就嵌套在解释器中
WARN: 用编辑器打开源代码文件,可能修改文件,注意不要SAVE,以免修改文件.
------
标准库: 一些最爱
sys: 让你能够访问与Python解释器紧密联系的变量和函数
sys.argv: 传递到Python解释器的参数,包括脚本名称
sys.exit: 退出当前程序,如果在try/finally中调用,finally子句仍然会执行,在LINUX中,可以提供一个整数作为参数,标志程序运行正常与否,如exit 0,成功运行.
sys.modules: 将模块名映射到实际存在的模块上,它只应用于目前导入的模块.
sys.path: 目录字符串列表,import模块,Python解释器会从这些目录查找模块
sys.platform: 运行Python平台的名称
sys.stdin,sys.stdout,sys.stderr模块变量是类文件流对象.标准输入,标准输出,标准错误
#Filename: reverse.py import sys args = sys.argv[1:] args.reverse() print ' '.join(args) D:\Work\Python>python reverse.py A B C C B A------
os:
提供了访问多个操作系统服务的功能
表中列出os模块中最有用的函数和变量,此外os和它的子模块os.path还包括一些用于检查,删除,建文件及目录的函数,以及一些处理路径的函数(os.path.split,os.path.join。这两个函数联合使用可以替代os.pathsep)
os.environ 映射环境变量,比如要访问系统变量PYTHONPATH
>>> os.environ['PYTHONPATH']
'D:\\Work\\Python;'
os.system用于运行外部程序.也有一些函数可以执行外部程序:如execv,popen
execv,它会退出Python解释器,并且将控制权交给被执行程序
popen, 它可以创建与程序相连的类文件.
os.sep 用于路径名中的分割符号. Unix: '/'; Wins: '\\'
os.pathsep 在Unix中:, 在Windows系统中;
os.linesep Unix '\n', Windows: '\r\n'
os.urandom 使用一个依赖于系统的"真"随机数的源,如果平台不支持,返回NotImplementedError异常
os.system 可以执行外部命令
列出目录的内容
发送EMAIL
打开浏览器
...
>>> os.system('CMD')
-1073741510
>>> os.system('NOTEPAD')
0
>>> os.system(r'C:\Program Files (x86)\Mozilla Firefox\firefox.exe')
1
#整数表示打开不成功
>>> os.system(r'C:\"Program Files (x86)"\"Mozilla Firefox"\firefox.exe')
0
NOTE:"Program Files (x86)",用双引号,否则CMD会在空格处停顿,对于PYTHONPATH设置的目录而言,这点非常重要.
一个更好的函数是:接受一般路径,空格也没问题
>>> os.startfile(r'C:\Program Files (x86)\Mozilla Firefox\firefox.exe')
大多数情况下os.system很有用,但对于启动浏览器这种特殊的任务,比如希望用Web浏览器打开某网页,下面这样做更好些
>>> import webbrowser >>> webbrowser.open('http://www.python.org') True------
fileinput:
可以轻松遍历文本文件所有行
#对file1,file2,file3三个文件所有行进行遍历
$ python script.py f1.txt f2.txt f3.txt
#也可以执行管道命令,如下:
$ cat file.txt | python script.py //
input 最重要的函数.返回能够用于for循环遍历的对象.
#Filename: numberLine.py import fileinput for line in fileinput.input(inplace=1): line = line.rstrip() num = fileinput.lineno() print "%-50s #%2d" % (line,num)D:\Work\Python>python numberLine.py numberLine.py
#Filename: numberLine.py # 1
import fileinput # 2
# 3
for line in fileinput.input(inplace=1): # 4
line = line.rstrip() # 5
num = fileinput.lineno() # 6
print "%-50s #%2d" % (line,num) # 7
WARN:
inplace参数-它很容易破坏文件。应该在不使用inplace设置的情况下仔细测试自己的程序,在确保程序工作正常后再修改文件
------
集合,堆和双端队列:
Python中除了元祖,列表,字典等最重要的数据结构外,还有些有用的数据结构,可以派上用场.
1. 集合
集合是由序列或其他可迭代对象构建
>>> set(range(10))
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
因为集合是用于检查成员资格的,因此副本是忽略的
>>> set([0,1,4,2,2,3,4])
set([0, 1, 2, 3, 4])
因为集合是无序的,编程不可用其用于排序
>>> set(['fee','fie','foe'])
set(['foe', 'fee', 'fie'])
集合可用于求交集和并集
求并集, | 或者 union >>> a = set([1,3,4]) >>> b = set([2,3,5]) >>> a | b set([1, 2, 3, 4, 5]) >>> a.union(b) set([1, 2, 3, 4, 5]) 求交集, >>> a & b set([3])下面列出了一些其他方法和对应的运算符,方法的名称已经表明了其用途
>>> c = a & b >>> c.issubset(a) True >>> c <= a True >>> c.issuperset(a) False >>> c >=a False >>> a.intersection(b) set([3]) >>> a & b set([3]) >>> a.difference(b) set([1, 4]) >>> a - b set([1, 4]) >>> a.symmetric_difference(b) set([1, 2, 4, 5]) >>> a ^ b set([1, 2, 4, 5]) >>> a.copy() set([1, 3, 4]) >>> a.copy() is a False
------
Note: 如果需要一个函数,用于查找并且打印两个集合的并集,可以使用来自set类型的union方法来绑定版本。这种方法很有用,比如结合reduce来使用:
>>> mySets = [] >>> for i in range(10): mySets.append(set(range(i,i+5))) >>> reduce(set.union,mySets) set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])集合是可变的,所以不能用做字典中的键。另外一个问题,集合本身只能包含不可变的值,所以就不能包含其他集合。在实际当中,集合是很常用,这个时候就可以用frozenset类型
>>> a = set() >>> b = set() >>> a set([]) >>> a.add(b) Traceback (most recent call last): File "<pyshell#56>", line 1, in <module> a.add(b) TypeError: unhashable type: 'set' >>> a.add(frozenset(b)) >>> a set([frozenset([])])frozenset构造函数创建给定集合的副本,不管是将集合作为其他集合成员还是字典的键,frozenset都很有用.
------
堆:heap 数据结构,使用优先队列能够以任意顺序增加对象,并且能在任何时间找到最小的元素,它比用于列表的min方法效率要高的多。Python没有独立的堆类型,只有包含一些堆操作函数的模块,这个模块叫heapq,包括6个函数,其中4个直接和堆操作相关
>>> from heapq import *[0, 0.5, 2, 5, 1, 8, 4, 9, 6, 7, 3]
heappop函数弹出最小的元素--一般来说都是在索引为0除的元素,并且确保元素最小的那位占据这个位置
>>> heappop(heap)
0
>>> heappop(heap)
0.5
>>> heappop(heap)
1
>>> heap
[2, 3, 4, 5, 7, 8, 6, 9]
heapify: 使用任意列表作为参数,并且通过尽可能少的移位操作,将其转换为合法的堆.如果没有用heappush建立堆,那么在使用heappush和heappop前使用这个函数
>>> heap = [5,8,0,3,6,7,9,1,4,2]
>>> heapify(heap)
>>> heap
[0, 1, 5, 3, 2, 7, 9, 8, 4, 6]
heapreplace: 弹出堆的最小元素,并且将新元素推入。比调用heappop再调用heappush更高效.
>>> heapreplace(heap,0.5)
0
>>> heap
[0.5, 1, 5, 3, 2, 7, 9, 8, 4, 6]
nlargest(n,iter)和nsmallest(n,iter)分别用来寻找任何可迭代对象中第n大或第n小的元素.当然也可以用排序(sort)和分片来完成这个工作,但是堆算法更快且更有效地使用内存。
>>> nlargest(1,heap) #第一大元素
[9]
------
双端队列: 在需要元素增加的顺序来移除元素时非常有用. Python2.4增加了collections模块,它包括了deque类型。
NOTE: Python2.5中的collections模块只包括deque类型和defaultdict类型-----为不存在的键提供默认值的字典,
未来可能会加入二叉树和斐波那契堆。看下例如何创建,使用:
>>> from collections import deque
>>> q = deque(range(5))
>>> q.append(5)
>>> q
deque([0, 1, 2, 3, 4, 5])
>>> q.appendleft(6)
>>> q
deque([6, 0, 1, 2, 3, 4, 5])
>>> q.pop()
5
>>> q.popleft()
6
>>> q.rotate(3)
>>> q
deque([2, 3, 4, 0, 1])
>>> q.rotate(-1)
>>> q
deque([3, 4, 0, 1, 2])
双端队列好用的原因:它可以再开头增加和弹出元素。这是在列表中无法实现的。其他有效方法,旋转元素.
rotate(1): 从左往右移
rotage(-1): 从右往左移
------
time:
time模块所包括的函数能够实现以下功能: 获得当前时间、操作时间和日期、从字符串读取时间以及格式化时间为字符串。
time.asctime: 将当前时间格式化给字符串
>>> import time
>>> time.asctime()
'Sat Sep 27 16:37:01 2014'
time.localtime: 将实数转换为本地时间的日期元祖,如果想获得全球统一时间,则可以使用gmtime
time.mktime:将日期元祖转换为从新纪元开始计算的秒数,与localtime功能想法
time.sleep: 让解释器等待给定的秒数
time.strptime: 将asctime格式化过的字符串转换为日期元祖
time.time: 使用自新纪元开始计算的秒数返回当前时间.
此外,PYTHON还提供了两个和时间密切相关的模块:datetime和timeit
datetime: 支持日期和时间的算法
timeit : 帮助开发人员对代码段的执行时间进行计时
------
random:产生伪随机数
NOTE:如果需要真的随机数,应该使用os模块的urandom函数,random模块内的SystemRandom类也是基于同样功能,可以让数据接近真正的随机数字.
random.random: 返回0-1的伪随机数
>>> random.random()
0.20529916312566654
random.getrandbits: 以长整形返回给定的位数
>>> random.getrandbits(10)
26L
random.uniform(a,b): 返回a,b之间的随机数
>>> random.uniform(1,11)
6.067296188580553
random.randrange: 可以获得范围内的随机整数.
#如果想要获得0~11之间的随机数,可以1,12,1 最后一个代表步长,12-1才是最终
>>> random.randrange(1,12)
7
>>> random.randrange(1,12,1)
6
#如果想获得小于20的随机正基数,可以这样
>>> random.randrange(1,20,2)
11
random.choice: 从给定序列中选择随机元素
>>> l = range(10)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> random.choice(l)
3
random.shuffle: 将给定序列的元素进行随机移位,每种排列的可能性是近似相等的。
>>> random.shuffle(l)
>>> l
[3, 0, 1, 9, 5, 6, 2, 8, 4, 7]
random.sample: 从给定的序列中选择给定数目的元素,同时确保元素互不相同:
>>> random.sample(xrange(100),10)
[15, 77, 11, 8, 9, 28, 86, 16, 18, 13]
下面介绍random模块的例子
>>> date1 = (2008,1,1,0,0,0,-1,-1,-1)
>>> time1 = mktime(date1)
>>> date2 = (2009,1,1,0,0,0,-1,-1,-1)
>>> time2 = mktime(date2)
#然后就能在这一范围内生成一个随机数:
>>> random_time = uniform(time1,time2)
>>> random_time
1217204626.0219598
然后将数字转化为可读的日期模式:
>>> print asctime(localtime(random_time))
Mon Jul 28 08:23:46 2008
以下例子中,要求用户选择投掷的骰子数以及每个骰子具有的面数。由randrange和for循环实现:
from random import randrange num = input('How many dice?') sides = input('How many sides per die?') sum = 0 for i in range(num): sum += randrange(sides) + 1 print 'The result is:' , sum输出结果:
D:\Work\Python>python reverse.py How many dice?3 How many sides per die?6 The result is: 13例子3:从Word.txt单词中,随机抽取一个单词
#Word.txt 内容 Perl Python C/C++ Ruby Java #fortune.py import fileinput,random fortunes = list(fileinput.input()) print random.choice(fortunes) D:\Work\Python>python reverse.py word.txt C/C++------
shelve:简单的存储文件,里面有用的open,close方法.
潜在的陷阱
>>> import shelve >>> s = shelve.open('test.dat') >>> s['x'] = ['a','b','c'] >>> s['x'].append('d') >>> s['x'] ['a', 'b', 'c']d去哪里了呢?
1. ['a','b','c']存储在键'x'下
2. 获得存储的表示,并且根据它来创建新的列表。而'd'被添加到这个副本中。修改的内容还没有保存
3. 最终再次获得原始版本--没有'd'
为了正确使用slelve存储对象,必须将临时变量绑定到副本中,并且再修改后重新存储在这个副本中
>>> tmp = s['x'] >>> tmp.append('d') >>> s['x'] = tmp >>> s['x'] ['a', 'b', 'c', 'd']------
re:
re模块包含对正则表达式的支持
原始字符串的好处: r'python\.org' 如果不用的话'python\\.org'
r'(http://)?(www\.)?python\.org'
可以匹配到
http://www.python.org
http://python.org
www.python.org
python.org
从上述例子,可以学到
1. 对点号进行转义,防止它被作为通配符使用;
2. 使用原始字符串减少所需反斜线的数量;
3. 每个可选子模式都用();
4. 可选子模式出现与否均可,而且相互独立
(pattern)*: 允许模式重复0次或多次
(pattern)+: 允许模式重复1次或多次
(pattern){m,n}:允许模式重复m~n次
^: 匹配以什么开始
$: 匹配以什么结尾
一些重要函数
>>> import re >>> text = 'alpha, beta,,,gamma delta'#允许任意长度的逗号,空格来分割
>>> re.split('[, ]+',text) ['alpha', 'beta', 'gamma', 'delta']NOTE: 如果模式包含(),那么括起来的字符组合会散布在分割后的子字符串之间,例如:
>>> re.split('o(o)','foobar') ['f', 'o', 'bar']maxsplit表示字符串最多可分割的部分
>>> re.split('[, ]+',text,maxsplit=2) ['alpha', 'beta', 'gamma delta'] >>> re.split('[, ]+',text,maxsplit=1) ['alpha', 'beta,,,gamma delta']函数re.findall以列表形式返回给定模式的所有匹配项。比如说,要在字符串中查找所有的单词
>>> pat = '[a-zA-Z]+' >>> text= '"Hm...Err -- are your sure?" he said,sounding insecure.' >>> re.findall(pat,text) ['Hm', 'Err', 'are', 'your', 'sure', 'he', 'said', 'sounding', 'insecure'] >>> pat = r'[,.?\-"]+' >>> re.findall(pat,text) ['"', '...', '--', '?"', ',', '.']#横线被转义了.
re.sub: 使用给定的替换内容将匹配的子字符串替换掉
>>> pat = '{name}' >>> test= 'Hello,{name}...' >>> re.sub(pat,'Mr. Smith',test) 'Hello,Mr. Smith...'re.escape是一个很使用的函数,它可以对字符串中所有可能被解释为正则运算符的字符进行转义的应用函数.
>>> re.escape('www.python.org') 'www\\.python\\.org' >>> re.escape('[email protected]') 'test\\@163\\.com'------
匹配对象和组
'There (was a (wee) (cooper)) who (lived in Fyfe)'
包含下面这些组:
0 'There was a wee cooper who lived in Fyfe'
1 was a wee cooper
2 wee
3 cooper
4 lived in Fyfe
一般来说,如果组中包含诸如通配符或者重复运算符之类的特殊字符,那么你可能会对是什么与给定组实现了匹配感兴趣,比如在下面的模式中:
r'www\.(.+)\.com$'
组0包含整个字符串,而组1则包含位于'www.'和'.com'之间的所有内容。像这样创建模式的话,就可以取出对字符串中感兴趣的部分。
如果没有组号,默认是0,看下面例子
>>> m = re.match(r'www\.(.+)\..{3}','www.python.org') >>> m.group(1) 'python' >>> m.start(1) 4 >>> m.end(1) 10 >>> m.span(1) (4, 10)------
作为替换的组号和函数:
假如要将'*something*'替换为<em>something</em>,要如何做呢?
>>> pat = r'\*([^\*]+)\*' >>> re.sub(pat,r'<em>\1</em>','Hello,*world*!') 'Hello,<em>world</em>!'------
贪婪模式,非贪婪模式
贪婪模式:意味着尽可能多的匹配,还是刚才这个例子.
>>> pat = r'\*(.+)\*' >>> re.sub(pat,r'<em>\1</em>','*This* is *it*!') '<em>This* is *it</em>!'#其中的+就是贪婪运算符,她会一直匹配到最末一位满足的位置,如果让其变非贪婪呢?
>>> import re >>> pat = r'\*\*(.+?)\*\*' >>> re.sub(pat,r'<em>\1</em>','**This** is **it**') '<em>This</em> is <em>it</em>'------
找出EMAIL的发件人:
邮件内容:
From [email protected] Thu Dec 20 01:22:50 2008 Return-Path: <[email protected]> Received: from xyzzy42.bar.com (xyzzy.bar.baz [123.456.789.42]) by frozz.bozz.floop (8.9.3/8.9.3) with ESMTP id BAA25436 for <[email protected]>; Thu, 20 Dec 2004 01:22:50 +0100 (MET) Received: from [43.253.124.23] by bar.baz (InterMail vM.4.01.03.27 201-229-121-127-20010626) with ESMTP id <20041220002242.ADASD123.bar.baz@[43.253.124.23]>; Thu, 20 Dec 2004 00:22:42 +0000 User-Agent: Microsoft-Outlook-Express-Macintosh-Edition/5.02.2022 Date: Wed, 19 Dec 2008 17:22:42 -0700 Subject: Re: Spam From: Foo Fie <[email protected]> To: Magnus Lie Hetland <[email protected]> CC: <[email protected]> Message-ID: <B8467D62.84F%[email protected]> In-Reply-To: <[email protected]> Mime-version: 1.0 Content-type: text/plain; charset="US-ASCII" Content-transfer-encoding: 7bit Status: RO Content-Length: 55 Lines: 6 So long, and thanks for all the spam! Yours, Foo Fie代码清单
import fileinput,re pat = re.compile('From: (.*) <.*?>$') for line in fileinput.input(): m = pat.match(line) if m: print m.group(1)输出结果:
D:\>python findSender.py Content.txt Foo Fie#对于这个程序,有几点可以注意的地方:
1. 用compile函数处理了正则表达式,让处理过程更有效率.
2. 将需要取出的子模式放在()中作为组
3. 使用了非贪婪模式对邮件地址进行匹配,那么只有最后一对<>符合要求
4. 使用$表示我要匹配整行;
如果要找出所有邮件地址:
代码清单:
import fileinput,re pat = re.compile(r'[a-z\-\.]+@[a-z\-\.]+',re.IGNORECASE) addresses = set() for line in fileinput.input(): for address in pat.findall(line): addresses.add(address) for address in sorted(addresses): print address运行结果:
D:\>python findSender.py Content.txt [email protected] [email protected] [email protected] [email protected]Note: sorted之后,大写字母在前面
------
其他模块:
functools: 通过部分参数来使用某个函数
difflib: 计算两个序列的相似程度
hashlib: 该模块应用于大文本文件,同时在加密和安全性方面很有用途
csv: 该模块处理CSV文件经常用到
timeit: 衡量代码运行时间的工具
profile: 用于衡量代码效率的工具
trace: 提供总的分析,在写测试代码很有用
datetime: 如果time模块还不能满足需要的话,用datetime
itertools: 迭代工具
logging: 打印日志追踪信息很有用.
getopt,optparse: UNIX中针对不同的程序开关,参数选项方面很有用.
cmd: 使用这个模块可以编写命令行解释器
------
本章新函数
dir(obj) 返回按字母排序的属性名称列表
help(obj) 提供交互式帮助或特定对象的帮助信息
reload(module) 返回已经导入模块的重新载入版本