Python之迭代器&装饰器&生成器&正则

时间:2023-03-08 15:05:34
Python之迭代器&装饰器&生成器&正则

1、迭代器

迭代器是访问数据集合的一种方式,它只能从集合的第一个元素开始顺序访问,直到最后一个元素结束。类似于linux里的cat命令,只能挨行读取文本内容,不可以跳到中间或者尾部读取(不会把所有的数据都读到内存中),对于上G的文件,比较节约内存。该迭代的好处就是它事先不需要准备好集合里的所有元素,遍历到该元素时才会计算处理该元素,这点与列表有很大的不同。

示例1:

a = iter(['add','dfdf','dfdfd'])
print a.next()#取第一个值
print a.next()#取第二个值
print a.next()#取第三个值# a = iter(['add','dfdf','dfdfd'])

迭代器关键字iter(),读取集合元素时,只能使用next()方法挨个读取,每次读取一个值,不能随机读取。

示例2:


for line in open("test.txt").readlines():
  print line

for line in open("test.txt"):   #use file iterators
print line

区别:

for line in open("test.txt").readlines()方法是将整个文件读到内存,然后每行读取;
for line in open("test.txt")方法利用迭代器,每次读取一行。

2、生成器

生成器也是一种迭代器,拥有next()方法并且行为与迭代器完全相同。当一个函数中包含yield关键字时,该函数就是一个生成器函数。这里的yield相当于普通函数里的return,只不过yield返回的是一个生成器。第一次执行next()方法时,才会调用生成器函数。当该函数执行到yied语句时会中止,并以yield的参数作为此次next()方法的返回值返回。之后每次调用next()方法时,生成器函数接着上次中止的yield语句往下继续执行,直到遇到yield语句再此中止。

示例:

def Get_Number():#1#4
yield 0#5#7
yield 1#8#10
yield 2#11#12 a = Get_Number()#
print a.next()#
print a.next()#
print a.next()#

程序第一次执行到print a.next()语句时会调用Get_Number函数,该函数执行到yield 0 时会返回yield后面的参数0,并中止函数的执行。然后程序继续执行第二句print a.next(),继续调用Get_Number函数,然后执行yield 1语句返回1,然后中止函数体的执行,再继续执行第三句print a.next()。。。

示例:单线程并发运算

import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了2个包子!")
c.send(i)
c2.send(i) producer("ahaii")

3、装饰器

详细示例,参照银角大王博客:http://www.cnblogs.com/wupeiqi/articles/4980620.html

示例1:

需求: 在调用tv()函数时,需要添加一个登录验证的环节,且不能修改tv()函数内部的代码。

def login(func):
print 'login'
return func#只返回func函数的内存地址,不调用func def tv(name):
print '%s to tvpage' % name f = login(tv)
f('ahaii')

示例中,login()函数返回func参数,该参数只是一个函数的内存地址。执行 f = login(tv)时,将tv作为参数传给login(),然后执行login()函数内部代码(登录验证模块)。执行完成后返回tv函数在内存的位置,此时 f = tv。当执行f('ahaii')时,即tv('ahaii'),调用tv()函数,执行该函数代码。

示例2:

def login(func):
def inner(arg):#执行tv('ahaii')语句时第二次调用的tv
print '验证'
return func(arg)#第一次调用的tv
return inner @login
#装饰器,调用login函数,并以被装饰的函数(tv)的函数名为参数,即login(tv),效果如下:
# def login(tv):
# def inner(arg):
# print '验证'
# return tv(arg)
def tv(name):
print '%s to tvpage' tv('ahaii')#调用inner()函数

上例中,@login语句即为装饰器,该语句下面的tv()函数就是被装饰的函数。该程序执行流程是:1、def login(func):,将该函数加载到内存,不执行。2、@login。

@login背后的故事:

.1 当程序执行到@login语句时,会把@login装饰的函数(即该语句下面的函数tv())当作参数传递给login()函数,此时会执行login(tv)。

.2 login(tv),执行内部语句def inner(arg) 和 return inner,因没有调用inner()函数,所以函数体 print '验证' 和return func(arg) 不会被执行。该句的执行结果是inner函数体。

.3 将第2步执行的返回值赋值给被login修饰的函数,即将inner函数体赋值给tv()函数。

即 新tv=def inner(arg):

    print ...

    return func(arg) #返回原来的tv

执行 tv('ahaii') 时,会将 'ahaii'参数传给inner()函数。

综上,装饰器的功能就是,当执行tv()函数时,需要先执行另外一个新的tv()函数,在新的tv()函数里可以添加新的功能模块(执行tv函数之前,先执行新的tv函数( inner函数))。比如登录验证,然后再执行原来的tv()函数。这样,即未改动原来的tv()函数,又添加了新功能。

4、递归

示例1:

def calc(n):
print n
if n/2 >1:
res = calc(n/2)
print res
print n
return n calc(10)

将函数执行的结果作为参数再传递给函数本身。

示例2 斐波那契数列:

def func(arg1,arg2,stop):
arg3 = arg1 + arg2
if arg1 == 0:
print arg1,arg2
print arg3
if arg3 < stop:
func(arg2,arg3,stop) func(0,1,50)

示例3 找有序数列中某一值:

def find(List,Number):
mid = len(List)/2#取中间值
if len(List)>=1:
if List[mid] >Number:
print 'in the left %s' % List[mid]
find(List[:mid],Number)#切片,取列表左半
elif List[mid] <Number:
print 'in the right %s' % List[mid]
find(List[mid:],Number)
else:
print 'find the number,,, %s' % Number
else:
print 'cannot find the number,,,' find(range(1,100000),9)

思路:先取有序数列的中间值与要查找的值x比较大小,若大于x,则说明x在该中间值的左边。利用切片取数列左半部门,然后递归继续查找中间值与x比较。

5、算法

示例 二维列表90度旋转:

array=[[col for col in range(5)] for row in range(5)] #初始化一个4*4数组
#array=[[col for col in 'abcde'] for row in range(5)] for row in array: #旋转前先看看数组长啥样
print(row) print('-------------')
for i,row in enumerate(array): for index in range(i,len(row)):
tmp = array[index][i] #get each rows' data by column's index
array[index][i] = array[i][index] #
array[i][index] = tmp
for r in array:print r print('--one big loop --')

6、正则表达式

匹配格式

模式 描述
^ 匹配字符串的开头
$ 匹配字符串的末尾。
. 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
[...] 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'
[^...] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re* 匹配0个或多个的表达式。
re+ 匹配1个或多个的表达式。
re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re{ n}  
re{ n,} 精确匹配n个前面表达式。
re{ n, m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a| b 匹配a或b
(re) G匹配括号内的表达式,也表示一个组
(?imx) 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx) 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re) 类似 (...), 但是不表示一个组
(?imx: re) 在括号中使用i, m, 或 x 可选标志
(?-imx: re) 在括号中不使用i, m, 或 x 可选标志
(?#...) 注释.
(?= re) 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re) 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
(?> re) 匹配的独立模式,省去回溯。
\w 匹配字母数字
\W 匹配非字母数字
\s 匹配任意空白字符,等价于 [\t\n\r\f].
\S 匹配任意非空字符
\d 匹配任意数字,等价于 [0-9].
\D 匹配任意非数字
\A 匹配字符串开始
\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
\z 匹配字符串结束
\G 匹配最后匹配完成的位置。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\n, \t, 等. 匹配一个换行符。匹配一个制表符。等
\1...\9 匹配第n个分组的子表达式。
\10 匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式。