第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參数-它非常easy破坏文件。应该在不使用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 *
>>> from random import shuffle
>>> data = range(10)
>>> shuffle(data)
>>> heap = []
>>> for n in data:
heappush(heap,n)
>>> heap
[0, 1, 2, 5, 3, 8, 4, 9, 6, 7]
>>> heappush(heap,0.5)
>>> heap
[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('test@163.com')
'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 foo@bar.baz Thu Dec 20 01:22:50 2008
Return-Path: <foo@bar.baz>
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 <magnus@bozz.floop>; 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 <foo@bar.baz>
To: Magnus Lie Hetland <magnus@bozz.floop>
CC: <Mr.Gumby@bar.baz>
Message-ID: <B8467D62.84F%foo@baz.com>
In-Reply-To: <20041219013308.A2655@bozz.floop>
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
Mr.Gumby@bar.baz
foo@bar.baz
foo@baz.com
magnus@bozz.floop
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) 返回已经导入模块的又一次加载版本号