一、迭代器

1.1 可迭代对象

给定一个list或tuple,可以通过for循环来遍历整个list或者tuple,称为迭代(Iteration),被遍历的list或tuple称为可迭代对象。
可迭代对象有:str、list、tuple、set等

for 遍历可迭代对象,内部的过程:
将可迭代对象转化成迭代器。(调用对象的iter()方法)
内部使用next方法,一个一个取值(使用迭代器协议去实现循环访问)。
加了异常处理功能,取值到底后自动停止。
最重要的一点,转化成迭代器,在循环时,同一时刻在内存中只出现一条数据,极大限度的节省了内存。

  1. x = [100,200,300]
  2. y = iter(x)
  3. z = iter(x)
  4. print(next(y))
  5. print(next(y))
  6. print(next(z))
  7. print(type(y))
  8. ##结果
  9. 100
  10. 200
  11. 100
  12. <class 'list_iterator'>

y 和 z 是两个独立的迭代器,迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以便下次迭代的时候获取正确的元素。

1.2 迭代器

迭代器是一个可以记住遍历位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问结束。
迭代器的两个基本方法:iter() 和next()。
iter() 用于创建迭代器对象
next() 用于遍历对象的元素。
在遍历字符串、列表或元素对象的时候经常用到迭代器。
迭代器只能向前遍历元素,不能后退。

  1. list =['lhuan',"lars","gyon",'mj']
  2. name = iter(list) ##创建迭代器对象
  3. print(next(name))
  4. print(next(name))
  5. print(next(name))
  6. print(next(name))
  7. print(next(name))
  8. print(next(name)) ##超出遍历的范围会报错
  9. ##结果
  10. lhuan
  11. lars
  12. gyon
  13. mj
  14. Traceback (most recent call last):
  15. File "e:/pythonstduy/lei.py", line 407, in <module>
  16. print(next(name))
  17. StopIteration

使用for语句遍历迭代器对象

  1. list =['lhuan',"lars","gyon",'mj']
  2. Name = iter(list)
  3. for i in Name:
  4. print(i,end='-------')
  5. ###结果
  6. lhuan-------lars-------gyon-------mj-------

使用while语句遍历迭代器对象

  1. import sys
  2. list =['lhuan',"lars","gyon",'mj']
  3. Name = iter(list)
  4. while True:
  5. try:
  6. print(next(Name),end='*****')
  7. except StopIteration:
  8. sys.exit()
  9. ###结果
  10. lhuan*****lars*****gyon*****mj*****

1.3 自定义迭代器 ???

通过定义一个实现迭代器协议方法的类,既可自定义一个迭代器。

  1. class MyIterator:
  2. def __init__(self,x=3,xmax=300):
  3. self.__mul,self.__x=x,x
  4. self.__xmax= xmax
  5. def __iter__(self):
  6. return self
  7. def __next__(self):
  8. if self.__x and self.__x !=1:
  9. self.__mul *= self.__x
  10. if self.__mul <= self.__xmax:
  11. return self.__mul
  12. else:
  13. raise StopIteration
  14. else:
  15. raise StopIteration
  16. if __name__ =='__main':
  17. myiter = MyIterator()
  18. for i in myiter:
  19. print('迭代的数据元素为:',i)

1.4 内置迭代器工具

Pyhon已经内置产生迭代器的函数iter()。另外,在itertools模块中,也提供了丰富的迭代器工具。
itertools模块包含创建有效迭代器的函数,可以用各种方式对数据进行循环和操作,这个模块中的所有函数返回的迭代器都可以与for循环语句及其他包含迭代器(eg:生成器和生成器表达式)的函数联合使用。
itertools模块中提供了将近20个迭代器工具函数,主要分为三类。

1.4.1 无限迭代器

使用无限迭代器的时候,必须添加迭代退出的条件,否则会导致死循环。

1.count(start,[step])

从start开始,以step为步长进行计数迭代。起始参数start默认值为0,步长step默认值为1.

  1. import itertools
  2. ns = itertools.count(10,100)
  3. for n in ns:
  4. print(n,end="----")

输出结果
image.png
count() 会创建一个无限的迭代器,会打印出从10 开始,步长为100的序列,而且无法停止,ctrl+c都打断不了。

2.cycle(terable)

无限循环迭代terable。
terable是可以迭代对象,该函数的作用是保存迭代对象每个元素的副本,无限地重复返回每个元素的副本。

  1. import itertools
  2. ns = itertools.cycle(['溪云初起日沉阁','山雨欲来风满楼'])
  3. for i in ns:
  4. print(i)

终端不停地打印 ‘溪云初起日沉阁 ’和 ‘山雨欲来风满楼’
image.png

3.repeat(object,[n])

循环迭代object,次数为n次,如果不指定n的值,就默认为无限次。object是可迭代对象。

  1. import itertools
  2. ns = itertools.repeat("满目山河空念远,落花风雨更伤春。",3)
  3. for i in ns:
  4. print(i)
  5. ##结果
  6. 满目山河空念远,落花风雨更伤春。
  7. 满目山河空念远,落花风雨更伤春。
  8. 满目山河空念远,落花风雨更伤春。

1.4.2 迭代短序列

1.chain(* iterables)

将多个迭代器作为参数,但只返回单个迭代器,它产生所有参数迭代器的内容,就好像它们是来自于一个单一的序列。
*iterables 为一个或多个可迭代序列。

  1. import itertools
  2. ns = itertools.chain(['西风吹老洞庭波','一夜湘君白发多'],['龙阳县','青草湖','湘君'])
  3. for i in ns:
  4. print(i,end='****')
  5. ##结果
  6. 西风吹老洞庭波****一夜湘君白发多****龙阳县****青草湖****湘君****

2. compress(data,selectors)

根据selectors中的值选择迭代data序列中的值。如果selectors中的值为真,则输出对应data中的值,否则不输出。

  1. import itertools
  2. ns = itertools.compress(['千里黄云白日曛','北风吹雁雪纷纷','莫愁前路无知己','天下谁人不识君','六翮飘飖私自怜'],[0,1,False,True,5,False])
  3. for i in ns:
  4. print(i)
  5. ##结果
  6. 北风吹雁雪纷纷
  7. 天下谁人不识君
  8. 六翮飘飖私自怜
  9. 如果是0False的时候就不会输出,如果是其他大于0的值就会输出

3. dropwhile(pred,seq)

当pred对序列元素处理结果为的时候,开始迭代seq后的所有值。

  1. import itertools
  2. ns = itertools.dropwhile(lambda x: x<10,[2,5,6,11,'千里黄云白日曛','北风吹雁雪纷纷','莫愁前路无知己','天下谁人不识君'])
  3. for i in ns:
  4. print(i)
  5. ##结果
  6. 11
  7. 千里黄云白日曛
  8. 北风吹雁雪纷纷
  9. 莫愁前路无知己
  10. 天下谁人不识君

4.takewhile(pred,seq)

与dorpwhile的结果相反,当pred对序列元素处理结果为的时候,开始迭代seq后的所有值。

  1. import itertools
  2. ns = itertools.takewhile(lambda x: x>9,[12,15,11,6])
  3. for i in ns:
  4. print(i)
  5. ##结果
  6. 12
  7. 15
  8. 11

5.tee(it,n)

将it重复n次进行迭代

  1. import itertools
  2. for its in itertools.tee(['千里黄云白日曛','北风吹雁雪纷纷','莫愁前路无知己','天下谁人不识君'],4):
  3. for i in its:
  4. print(i)
  5. ##结果
  6. 千里黄云白日曛
  7. 北风吹雁雪纷纷
  8. 莫愁前路无知己
  9. 天下谁人不识君
  10. 千里黄云白日曛
  11. 北风吹雁雪纷纷
  12. 莫愁前路无知己
  13. 天下谁人不识君
  14. 千里黄云白日曛
  15. 北风吹雁雪纷纷
  16. 莫愁前路无知己
  17. 天下谁人不识君
  18. 千里黄云白日曛
  19. 北风吹雁雪纷纷
  20. 莫愁前路无知己
  21. 天下谁人不识君

1.4.3 组合迭代序列

1.product(*iterables)

迭代排列出所有的排列

  1. import itertools
  2. ns = itertools.product([2,5,6,11],['千里黄云白日曛','北风吹雁雪纷纷','莫愁前路无知己','天下谁人不识君','六翮飘飖私自怜'])
  3. for i in ns:
  4. print(i)
  5. ##结果
  6. (2, '千里黄云白日曛')
  7. (2, '北风吹雁雪纷纷')
  8. (2, '莫愁前路无知己')
  9. (2, '天下谁人不识君')
  10. (2, '六翮飘飖私自怜')
  11. (5, '千里黄云白日曛')
  12. (5, '北风吹雁雪纷纷')
  13. (5, '莫愁前路无知己')
  14. (5, '天下谁人不识君')
  15. (5, '六翮飘飖私自怜')
  16. (6, '千里黄云白日曛')
  17. (6, '北风吹雁雪纷纷')
  18. (6, '莫愁前路无知己')
  19. (6, '天下谁人不识君')
  20. (6, '六翮飘飖私自怜')
  21. (11, '千里黄云白日曛')
  22. (11, '北风吹雁雪纷纷')
  23. (11, '莫愁前路无知己')
  24. (11, '天下谁人不识君')
  25. (11, '六翮飘飖私自怜')

2.premutations(p,r)

迭代序列中r个元素的排列

  1. import itertools
  2. ns = itertools.permutations([2,5,6,11],3)
  3. for i in ns:
  4. print(i)
  5. ##结果
  6. (2, 5, 6)
  7. (2, 5, 11)
  8. (2, 6, 5)
  9. (2, 6, 11)
  10. (2, 11, 5)
  11. (2, 11, 6)
  12. (5, 2, 6)
  13. (5, 2, 11)
  14. (5, 6, 2)
  15. (5, 6, 11)
  16. (5, 11, 2)
  17. (5, 11, 6)
  18. (6, 2, 5)
  19. (6, 2, 11)
  20. (6, 5, 2)
  21. (6, 5, 11)
  22. (6, 11, 2)
  23. (6, 11, 5)
  24. (11, 2, 5)
  25. (11, 2, 6)
  26. (11, 5, 2)
  27. (11, 5, 6)
  28. (11, 6, 2)
  29. (11, 6, 5)

3.combinations(p,r)

迭代序列中r个元素的组合

  1. import itertools
  2. ns = itertools.combinations([2,5,6,11],3)
  3. for i in ns:
  4. print(i)
  5. ##结果
  6. (2, 5, 6)
  7. (2, 5, 11)
  8. (2, 6, 11)
  9. (5, 6, 11)

二、生成器

2.1 生成器

使用生成器可以生成一个值的序列用于迭代,并且这个值的序列并不是一次生成的,而是使用一个在生成一个,可以时程序节约大量的内存。
在Python中,使用了yield的函数被称为生成器。生成器将返回一个迭代器的函数,并且生成器只能用于迭代操作。
生成器是一种特殊的迭代器。
在调用生成器运行的过程中,每次遇到yield的时候,函数就会暂停,并保存当前所有的运行信息,返回yield的值。在下一次执行next()方法的时候,会从当前位置继续进行。

  1. list = [2,2,3,4,5,6] ##创建一个列表
  2. def qtlb(list): ##创建生成器
  3. for i in list:
  4. yield i
  5. for n in qtlb(list):
  6. print(n)

与return 返回值不同的是,yield 语句每产生一个值,函数就会暂停,返回yield的值,等待被重新唤醒后从当前位置继续运行。

  1. 生成器不会一下子在内存中生成太多数据
  2. 比如我想卖包子,让包子工厂开始加工10000个包子,但是如果一下子全部生产好,没地方放,而且容易坏。
  3. 那么可以让包子工厂在我需要的时候再生产
  4. def produce():
  5. '''生产包子'''
  6. for i in range(10000):
  7. yield '生产了第%s个包子'%i
  8. produce_g = produce()
  9. print(produce_g.__next__())
  10. print(produce_g.__next__())
  11. print(produce_g.__next__())
  12. # 与上面等同
  13. print(next(produce_g))
  14. print(next(produce_g))
  15. print(next(produce_g))
  16. print(next(produce_g))
  17. print(next(produce_g))
  18. # 需要一批包子
  19. num = 0
  20. for i in produce_g:
  21. print(i)
  22. num += 1
  23. if num == 5:
  24. break

2.2 自定义生成器

  1. def MyYield(n): ##定义一个生成器(函数)
  2. while n > 0:
  3. print("start-------")
  4. yield n ## yield语句,用于返回给调用者其后表达式的值
  5. print("finish -------")
  6. n-=1
  7. if __name__ == "__main__":
  8. for i in MyYield(6): ##for 语句遍历正采取
  9. print ("遍历后得到的值:",i)
  10. print()
  11. my_yield =MyYield(3)
  12. print('已经实例化生成器对象')
  13. my_yield.__next__()
  14. print("第二次调用__next__() 方法:")
  15. my_yield.__next__()
  16. ##结果
  17. start-------
  18. 遍历后得到的值: 6
  19. finish -------
  20. start-------
  21. 遍历后得到的值: 5
  22. finish -------
  23. start-------
  24. 遍历后得到的值: 4
  25. finish -------
  26. start-------
  27. 遍历后得到的值: 3
  28. finish -------
  29. start-------
  30. 遍历后得到的值: 2
  31. finish -------
  32. start-------
  33. 遍历后得到的值: 1
  34. finish -------
  35. 已经实例化生成器对象
  36. start-------
  37. 第二次调用__next__() 方法:
  38. finish -------
  39. start-------

2.3 send

send 获取下一个值的效果和next基本一致
只是在获取下一个值的时候,给上一yield的位置传递一个数据

使用send的注意事项
第一次使用生成器的时候 是用next获取下一个值
最后一个yield不能接受外部的

  1. def generator():
  2. print(123)
  3. content = yield 1
  4. print('=========',content)
  5. print(456)
  6. yield 2
  7. g = generator()
  8. ret = g.__next__()
  9. print('***',ret)
  10. ret = g.send('hello')
  11. print('***',ret)
  12. #结果
  13. 123
  14. *** 1
  15. ========= hello
  16. 456
  17. *** 2

2.4 生成器表达式 ???

把列表解析的[]换成()得到的就是生成器表达式

三、装饰器

3.1 装饰器

让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。
装饰器装饰一个函数,带一个或者多个参数的函数,带返回值的函数

装饰器的表示语法是在函数或者类的前面添加“@”符号。 @ 语法糖
@disp_ff
def dd_ff():
pass
disp_ff是装饰器的名称
使用装饰器之后,dd_ff()只定义自己所需要的功能就可以,而装饰器所定义的功能会自动插入到函数dd_ff()中,即使是不同目的,不同类的函数或类也可以插入相同的功能。
用装饰器来装饰对象,必须先定义装饰器。装饰器函数的参数必须有函数或类对象,然后再装饰器函数中重新定义一个新的函数或类,并在其中执行某些功能前后或者中间使用被装饰的函数或类,最后返回这个新定义的函数或类。

3.2 装饰函数

  1. def aa(fun): ##定义一个装饰器
  2. def ww(*args,**kwargs): ##定义装饰器函数
  3. print("---------开始运行------")
  4. fun(*args,**kwargs) ##调用被装饰函数
  5. print("---------运行结束------")
  6. return ww ##返回装饰器函数
  7. @aa ##装饰函数语句
  8. def dd(x): ##定义普通函数,被装饰器装饰
  9. a = []
  10. for i in range(x):
  11. a.append(i)
  12. print(a)
  13. @aa
  14. def hh(n): ##定义普通函数,被装饰器装饰
  15. print("最喜欢的水果:",n)
  16. if __name__ == "__main__":
  17. dd(6)
  18. print()
  19. hh("苹果")
  20. ##结果
  21. ---------开始运行------
  22. [0, 1, 2, 3, 4, 5]
  23. ---------运行结束------
  24. ---------开始运行------
  25. 最喜欢的水果: 苹果
  26. ---------运行结束------

3.3 装饰类

装饰器不仅可以装饰函数,还可以装饰类。定义装饰类的装饰类,需要定义内嵌类的函数并返回新类。

  1. def aa(mycalss): ##定义类装饰器
  2. class InnerClass: ##定义内嵌类
  3. def __init__(self,z=0):
  4. self.z = 0
  5. self.wrapper = mycalss() ##实例化被装饰类
  6. def position(self):
  7. self.wrapper.position()
  8. print('z axis:',self.z)
  9. return InnerClass ##返回新定义的类
  10. @aa ##装饰器修饰类
  11. class coordination:
  12. def __init__(self,x=100,y=100):
  13. self.x = x
  14. self.y = y
  15. def position(self):
  16. print("x axis:",self.x)
  17. print("y axis ",self.y)
  18. if __name__ == "__main__":
  19. coor = coordination()
  20. coor.position()
  21. ##结果
  22. x axis: 100
  23. y axis 100
  24. z axis: 0