9 迭代器、生成器与装饰器
9.1 迭代器
凡是使用for语句,本质上都迭代器的应用
9.1.1 迭代器概述
__iter__() 返回对象本身,for语句使用迭代器的要求
__next__() 用于返回容器中下一个元素或数据,必须加StopIteration引发异常
任何一个类,只要它实现了上述两个方法,就称为迭代器,就可以rof来遍历它
for item in iterator
pass
9.1.2 自定义迭代器
In [4]:
class MyIterator: def __init__(self,x=2,xmax=100): self.__mul,self.__x=x,x self.__xmax=xmax def __iter__(self): return self def __next__(self): if self.__x and self.__x !=1: self.__mul *= self.__x if self.__mul <= self.__xmax: return self.__mul else: raise StopIteration else: raise StopIteration if __name__ == '__main__': myiter = MyIterator() for i in myiter: print('迭代的数据元素为:',i)
迭代的数据元素为: 4 迭代的数据元素为: 8 迭代的数据元素为: 16 迭代的数据元素为: 32 迭代的数据元素为: 64
9.1.3 内置迭代器工具
1、内建迭代器函数iter()
iter(iterable) iterable为可迭代的类型。
iter(callable,sentinel) callable可调用的类型,一般为函数;sentine称为‘哨兵’,即当第一个参数调用返回值等于第二个参数的值时,迭代或遍历停止。
In [14]:
class Counter: def __init__(self,x=0): self.x = x counter = Counter() def used_iter(): counter.x += 2 return counter.x #print(used_iter()) for i in iter(used_iter,8): print('本次遍历的数值:',i)
本次遍历的数值: 2 本次遍历的数值: 4 本次遍历的数值: 6
2、itertools
无限迭代器:
count(start,[step]) 从start开始,以step为步长
cycle(seq) 无限循环迭代seq
repeat(elem,[n]) 循环迭代elem
迭代短序列:
chain(p,q,...) 链接迭代
compress(data,selectors) 依据selectors中的值选择迭代data序列中的值
filterfalse(pred,seq) 当pred处理为假的元素
dropwhile(pred,seq) 依据pred对序列元素处理为假时开始迭代seq后所有的值
takewhile(pred,seq) 与dropwhile向反
tee(it,n) 将it重复n次进行迭代
zip_logest(p,q,...)
组合迭代序列:
product(p,q,...[,n]) 迭代排列出所有的排列
permuations(p,r) 迭代序列中r个元素的排列
combinations(p,r) 迭代序列中r个元素的组合
In [28]:
import itertools for i in itertools.count(1,3): print(i) if i >= 6: break print('------------------------------------') x = 0 for i in itertools.cycle(['a','b']): print(i) x += 1 if x >= 6: break print('------------------------------------') print(list(itertools.repeat(3,3))) print('------------------------------------') print(list(itertools.chain([1,3],[2,3]))) print('------------------------------------') print(list(itertools.dropwhile(lambda x:x>6,[8,9,1,2,8,9]))) print('------------------------------------') print(list(itertools.takewhile(lambda x:x>10,[18,19,1,21,8,9]))) print('------------------------------------') for its in itertools.tee([0,1],2): for it in its: print(it) print('------------------------------------') print(list(itertools.permutations('abc',2))) print('------------------------------------') print(list(itertools.combinations('abc',2)))
1 4 7 ------------------------------------ a b a b a b ------------------------------------ [3, 3, 3] ------------------------------------ [1, 3, 2, 3] ------------------------------------ [1, 2, 8, 9] ------------------------------------ [18, 19] ------------------------------------ 0 1 0 1 ------------------------------------ [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')] ------------------------------------ [('a', 'b'), ('a', 'c'), ('b', 'c')]
9.2 生成器
9.2.1 生成器创建
生成器对象是通过yield关键字定义的函数对象,生成器也是一个函数。
In [27]:
def myYield(n): while n > 0: print('开始生成:') yield n #yield用于返回给调用者其后表达式的值,组成一个序列 print('完成一次。。。') n -= 1 if __name__ == '__main__': for i in myYield(4): #遍历生成器 print('遍历得到的值:',i) print('---------------------------') my_yield = myYield(3) #实例化类 print('实例化生成器对象',my_yield.__next__()) #调用迭代器中的__next__方法 print('第二次调用__next__方法:',my_yield.__next__()) print('第三次调用__next__方法:',my_yield.__next__()) print(type(my_yield)) #查看数据类型,generator生成器的意思
开始生成: 遍历得到的值: 4 完成一次。。。 开始生成: 遍历得到的值: 3 完成一次。。。 开始生成: 遍历得到的值: 2 完成一次。。。 开始生成: 遍历得到的值: 1 完成一次。。。 --------------------------- <generator object myYield at 0x0417E030> 开始生成: 实例化生成器对象 3 完成一次。。。 开始生成: 第二次调用__next__方法: 2 完成一次。。。 开始生成: 第三次调用__next__方法: 1 <class 'generator'>
9.2.2 深入生成器
In [29]:
def myYield(n): while n > 0: rcv = yield n #定义了一个rcv来接收调用者传过来的值 n -= 1 if rcv is not None: n = rcv if __name__ == '__main__': my_yield = myYield(3) print(my_yield.__next__()) print(my_yield.__next__()) print('传给生成器一个值,重新初始化生成器。') print(my_yield.send(10)) #使用send方法传递值,也称为协程,看下一小节 print(my_yield.__next__())
3 2 传给生成器一个值,重新初始化生成器。 10 9
还可以使用一个类似列表推导的生成器表达式
In [35]:
a = (i for i in range(5)) a print(type(a)) list(a) #注意可以使用list()将其转化为列表,主句量太大和无序,不建议转化,会导致死机
<class 'generator'>
Out[35]:
[0, 1, 2, 3, 4]
9.2.3 生成器与协程
协程是一种解决程序并发的方法。
In [38]:
def consumer(): print('等待接收处理任务') while True: data = (yield) print('收到任务:',data) def producer(): c = consumer() c.__next__() for i in range(3): print('发送一个任务...','任务%d' % i) c.send('任务%d' % i) producer() #if __name__ == '__main__'这段其实可以不用写,忘记什么时候写请参看之前内容
等待接收处理任务 发送一个任务... 任务0 收到任务: 任务0 发送一个任务... 任务1 收到任务: 任务1 发送一个任务... 任务2 收到任务: 任务2
9.3 装饰器
9.3.1 装饰器概述
为了个不同的函数或类插入相同的功能
‘@’符号来实现
使用装饰器装饰对象,必须要先定义装饰器,装饰器的定义与普通函数的定义在形式上完全一致,只不过装饰器函数的参数必须要有函数或类对象,然后再装饰器函数中重新定义一个新的函数或类,并在其中执行某些功能前后或中间来使用被装饰的函数或类,最后返回这个新定义的函数或类。
In [39]:
def demo_decorater(fun): def new_fun(*args,**kwargs): pass fun(*args,**kwargs) pass return new_fun #完全摸不到头脑,看下例
9.3.2 装饰函数
In [43]:
#这个列子好看的多了 def abc(fun): def wrapper(*args,**kwargs): print('开始...') fun(*args,**kwargs) print('结束') return wrapper @abc def demo_decoration(x): a = [] for i in range(x): a.append(i) print(a) @abc def hello(name): print('hello ',name) demo_decoration(5) print() hello('默天')
开始... [0] [0, 1] [0, 1, 2] [0, 1, 2, 3] [0, 1, 2, 3, 4] 结束 开始... hello 默天 结束
9.3.3 装饰类
In [70]:
def abc(myclass): class InnerClass: def __init__(self,z=0): self.z = 0 self.wrapper = myclass() def position(self): self.wrapper.position() print('z axis:',self.z) return InnerClass @abc class coordination: def __init__(self,x=0,y=0): self.x = x self.y = y def position(self): print('x axis:',self.x) print('y axis:',self.y) if __name__ == '__main__': coor = coordination() coor.position()
x axis: 0 y axis: 0 z axis: 0