• Python基础之生成器、迭代器


    1.列表生成式

      现在有一个列表lis[0,1,2,3,4,5,6,7,8,9],现需要将里面每个元素+1,可以用过遍历、高阶函数map()都能实现,其实还有一个更简单的方法:列表生成式。

      列表遍历

    1 lis = [0,1,2,3,4,5,6,7,8,9]
    2 b = []
    3 for i in lis:
    4     b.append(i+1)
    5 print(b)
    6 结果:
    7 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

      高阶函数map()

    1 lis = [0,1,2,3,4,5,6,7,8,9]
    2 def fun(x):
    3     return x +1
    4 ret = map(fun,lis)
    5 print(list(ret))
    6 结果:
    7 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

      列表生成式

    1 lis = [0,1,2,3,4,5,6,7,8,9]
    2 b = [i + 1 for i in lis]
    3 print(b)
    4 结果:
    5 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

      上述方法都是建立在生成一个列表的基础上,当列表的元素贼多时,都加载到内存中会占用很多内存,而上述问题中后面的元素都是可以通过计算推导出来的。于是python中定义了生成器,即一边循环一边计算的机制称之为生成器。

    2.生成器

      生成器一次只能生成一个值,消耗的内存大大减少。

      创建生成器有很多种方法,最简单的一种就是将列表生成式中"[]"改成"()"即可。

    1 lis = [0,1,2,3,4,5,6,7,8,9]
    2 b = (i + 1 for i in lis)
    3 print(b)
    4 结果:
    5 <generator object <genexpr> at 0x000001E69D7DC938>

      列表生成式打印出来的是一个列表,而生成器打印出来的是:<generator object <genexpr> at 0x000001E69D7DC938>。

      若想获取生成器的值,需通过next()获取。

    1 lis = [0,1,2,3,4,5,6,7,8,9]
    2 b = (i + 1 for i in lis)
    3 print(next(b))
    4 结果:
    5 1

      此时每调用一次next()就会返回一个生成器的值,直到没有更多的元素时,报出StopIteration的错误。

      但是吧,如果一直重复用next()调用太low,可以用for循环来迭代,而且还不怕报StopIteration的错误。

     1 lis = [0,1,2,3,4,5,6,7,8,9]
     2 b = (i + 1 for i in lis)
     3 for i in b:
     4     print(i)
     5 结果:
     6 1
     7 2
     8 3
     9 4
    10 5
    11 6
    12 7
    13 8
    14 9
    15 10
    View Code

      生成器是一个特殊的函数,用关键字yield控制,一次只返回一个值,顺序同样从上往下依次执行,但是当遇到yield时返回一个值,且暂停执行,保存当前状态,当遇到另一个__next__()时从此处继续执行。

    1 def fun():
    2     yield 1
    3     yield 2
    4     yield 3
    5 f = fun()
    6 print(f.__next__())
    7 结果:
    8 1

      也可以用for循环迭代。

     1 def fun():
     2     yield 1
     3     yield 2
     4     yield 3
     5 for i in fun():
     6     print(i)
     7 结果:
     8 1
     9 2
    10 3

    3.可迭代对象

      可以直接用于for循环的对象统称为可迭代对象。

      集合数据类型:list、tuple、str、set以及生成器都时可迭代对象。

      判断是否时可迭代对象:

    1 from collections import Iterable
    2 lis = [1,2,3]
    3 print(isinstance(lis,Iterable))
    4 结果:
    5 True

    4.迭代器

      可以被next()函数调用,并不断返回下一个值的对象称迭代器。

      迭代器的对象表示的是一个数据流,迭代器可以被next()函数调用返回下一个数据,知道没有数据时,抛出异常错误。

      迭代器时惰性的,可以认为是一个有序序列,但是不知道长度。

      生成器是一种特殊的迭代器。

      list、dict、str是可迭代对象,但不是迭代器

    1 from collections import Iterable
    2 from collections import Iterator
    3 lis = [1,2,3]
    4 print(isinstance(lis,Iterable))
    5 print(isinstance(lis,Iterator))
    6 结果:
    7 True
    8 False

    5.迭代器的基本原理

      上文说过,可以直接用于for循环的对象统称为可迭代对象,实际上一个对象实现了__iter__方法,就可以用for,并且称之为可迭代对象。

    1 names = ["a","b","c"]
    2 for i in names:
    3     print(i)
    4 结果:
    5 a
    6 b
    7 c

      当一个实例对象没有__iter__方法时,使用for循环时,解释器会直接现实格式错误,即使用对象名classtest时,报色。

     1 class Classtest(object):
     2 
     3     def __init__(self):
     4         self.names = list()
     5 
     6     def add(self,name):
     7         self.names.append(name)
     8 
     9 
    10 classtest = Classtest()
    11 classtest.add("a")
    12 classtest.add("b")
    13 classtest.add("c")
    14 
    15 for i in classtest:
    16     print(i)
    View Code

      当加上__iter__时,则只有运行时会报错。

     1 class Classtest(object):
     2 
     3     def __init__(self):
     4         self.names = list()
     5 
     6     def add(self,name):
     7         self.names.append(name)
     8     
     9     def __iter__(self):
    10         pass
    11 
    12 classtest = Classtest()
    13 classtest.add("a")
    14 classtest.add("b")
    15 classtest.add("c")
    16 
    17 for i in classtest:
    18     print(i)
    View Code

      事实上,for循环是将__iter__的返回值返回。

     1 class Classtest(object):
     2 
     3     def __init__(self):
     4         self.names = list()
     5         self.count_num = 0
     6 
     7     def add(self,name):
     8         self.names.append(name)
     9 
    10     def __iter__(self):
    11         return ClassIterator(self)
    12 
    13 
    14 class ClassIterator(object):
    15     def __init__(self,obj):
    16         self.obj = obj
    17 
    18     def __iter__(self):
    19         pass
    20 
    21     def __next__(self):
    22         return 123
    23 
    24 
    25 classtest = Classtest()
    26 classtest.add("a")
    27 classtest.add("b")
    28 classtest.add("c")
    29 
    30 for i in classtest:
    31     print(i)
    32 结果:
    33 123
    34 123
    35 无限循环下去...
    View Code

      此时,我们通过类与类之间的调用,可以将需要循环的写入__next__方法中,就可以用for循环遍历出classtext对象中列表names的元素。

     1 class Classtest(object):
     2 
     3     def __init__(self):
     4         self.names = list()
     5         self.count_num = 0
     6 
     7     def add(self,name):
     8         self.names.append(name)
     9 
    10     def __iter__(self):
    11         return ClassIterator(self)
    12 
    13 class ClassIterator(object):
    14     def __init__(self,obj):
    15         self.obj = obj
    16         self.count_num = 0
    17 
    18     def __iter__(self):
    19         pass
    20 
    21     def __next__(self):
    22         if self.count_num < len(self.obj.names):
    23             ret = self.obj.names[self.count_num]
    24             self.count_num += 1
    25             return ret
    26         else:
    27             raise StopIteration
    28 
    29 
    30 classtest = Classtest()
    31 classtest.add("a")
    32 classtest.add("b")
    33 classtest.add("c")
    34 
    35 for i in classtest:
    36     print(i)
    37 结果:
    38 a
    39 b
    40 c
    View Code

      将两个类改进成一个类。

     1 class Classtest(object):
     2 
     3     def __init__(self):
     4         self.names = list()
     5         self.count_num = 0
     6 
     7     def add(self,name):
     8         self.names.append(name)
     9 
    10     def __iter__(self):
    11         return  self
    12 
    13     def __next__(self):
    14         if self.count_num < len(self.names):
    15             ret = self.names[self.count_num]
    16             self.count_num += 1
    17             return ret
    18         else:
    19             raise StopIteration
    20 
    21 
    22 classtest = Classtest()
    23 classtest.add("a")
    24 classtest.add("b")
    25 classtest.add("c")
    26 
    27 for i in classtest:
    28     print(i)
    View Code

  • 相关阅读:
    abstract关键字
    C#访问修饰符
    oracle客户端安装与配置
    Win10提示威胁服务已经停止,立即重启的解决方法
    什么是 Serverless 应用引擎?优势有哪些?
    Windows Server 2008 R2服务器系统安全设置参考指南
    Windows 2008 R2阿里云安全基线检查
    Windows Server 2008 R2 免费使用900天的方法
    Windows Server 2012 R2 英文版安装中文语言包教程
    七个穷人和富人不一样的地方
  • 原文地址:https://www.cnblogs.com/foxshu/p/12039646.html
Copyright © 2020-2023  润新知