zoukankan      html  css  js  c++  java
  • python 迭代器 生成器

    迭代器 与 生成器

    """
    什么是迭代器
        迭代:更新换代(重复)的过程,每次的迭代都必须基于上一次的结果
        迭代器:迭代取值的工具
    
    为什么要用
        迭代器给你提供了一种不依赖于索引取值的方式
    
    如何用
    """
     不算 因为只是简单的重复
     n = 0
     while True:
         print(n)
    
    
     重复 + 每次迭代都是基于上一次的结果而来的
     l = [1,2,3,4]
     s = 'hello'
     n = 0
     while n < len(s):
         print(s[n])
         n += 1
    """
    需要迭代取值的数据类型
        字符串
        列表
        元组
        字典
        集合
    """
    
     可迭代对象
     只有内置有__iter__方法的都叫做可迭代对象
    """
    补充:针对双下线开头双下划线结尾的方法
    推荐读:双下+方法名
    
    基本数据类型中
        是可迭代对象的有
            str list tuple dict set 
            文件对象(执行内置的__iter__之后还是本身 没有任何变化):文件对象本身就是迭代器对象
            
    """
    n = 1
    f = 1.1
    s = 'hello'
    l = [1,2,34,]
    t = (1,2,34)
    s1 = {1,2,3,4}
    d = {'name':'jason'}
    f1 = open('xxx.txt','w',encoding='utf-8')
    
    
     res = s.__iter__()   res = iter(s)
    
     print(s.__len__())   简化成了len(s)
     res1 = l.__iter__()   res1 = iter(l)
     res2 = f1.__iter__()   res2 = iter(f1)
     print(res,res1,res2)
     print(f1)
    
     可迭代对象执行内置的__iter__方法得到就是该对象的迭代器对象
    
    """
    迭代器对象
        1.内置有__iter__方法
        2.内置有__next__方法
        ps:迭代器一定是可迭代对象
        而可迭代对象不一定是迭代器对象
    """
    
    
    
     l = [1,2,3,4]
      生成一个迭代器对象
     iter_l = l.__iter__()
    
      迭代器取值 调用__next__
     print(iter_l.__next__())
     print(iter_l.__next__())
     print(iter_l.__next__())
     print(iter_l.__next__())
     print(iter_l.__next__())   如果取完了 直接报错
    
    
     d = {'name':'jason','password':'123','hobby':'泡m'}
      将可迭代对象d转换成迭代器对象
     iter_d = d.__iter__()
      迭代器对象的取值 必须用__next__
     print(iter_d.__next__())
     print(iter_d.__next__())
     print(iter_d.__next__())
     print(iter_d.__next__())   取完了 报错StopIteration
    
    f1 = open('xxx.txt','r',encoding='utf-8')
     调用f1内置的__iter__方法
     iter_f = f1.__iter__()
     print(iter_f is f1)
    """
    迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身(******)
    """
     print(f1 is f1.__iter__().__iter__().__iter__().__iter__())
    """
    问:__iter__方法就是用来帮我们生成迭代器对象
    而文件对象本身就是迭代器对象,为什么还内置有__iter__方法???
    """
    
    
    
    
    
    d = {'name':'jason','password':'123','hobby':'泡m'}
     iter_d = d.__iter__()
    
    
     print(d.__iter__().__next__())
     print(d.__iter__().__next__())
     print(d.__iter__().__next__())
    
     print(iter_d.__next__())
     print(iter_d.__next__())
     print(iter_d.__next__())
     print(iter_d.__next__())
    
     异常处理
     while True:
         try:
             print(iter_d.__next__())
         except StopIteration:
              print('老母猪生不动了')
             break
    
    
     f = open('xxx.txt','r',encoding='utf-8')
     iter_f = f.__iter__()
     print(iter_f.__next__())
     print(iter_f.__next__())
     print(iter_f.__next__())
    
    
    
    """
    迭代器取值的特点
        1.只能往后依次取 不能后退
    
    """
    d = {'name':'jason','password':'123','hobby':'泡m'}
     for i in d:
         print(i)
     for循环后面的in关键 跟的是一个可迭代对象
    """
    for循环内部的本质
        1.将in后面的对象调用__iter__转换成迭代器对象
        2.调用__next__迭代取值
        3.内部有异常捕获StopIteration,当__next__报这个错 自动结束循环
    """
     for i in 1:
         pass
     iter(1)
    
    
    """
    可迭代对象:内置有__iter__方法的
    迭代器对象:既内置有__iter__也内置有__next__方法
    
    迭代取值:
        优点
            1.不依赖于索引取值
            2.内存中永远只占一份空间,不会导致内存溢出
        
        缺点
            1.不能够获取指定的元素
            2.取完之后会报StopIteration错
    
    """
     l = [1,2,3,4]
     res = map(lambda x:x+1,l)
     print(map(lambda x:x+1,l))
     print(res.__next__())
     print(res.__next__())
     print(res.__next__())
    
    
    l1 = [1,2,3,4,5]
    l2 = ['a','b','c']
    print(zip(l1,l2))
    
    
    
    
    """
    生成器:用户自定义的迭代器,本质就是迭代器
    
    """
     def func():
         print('first')
         yield  666   函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行
         print('second')
         yield  777
         print('third')
         yield  888
         print('forth')
         yield
         yield
      yield后面跟的值就是调用迭代器__next__方法你能得到的值
      yield既可以返回一个值也可以返回多个值 并且多个值也是按照元组的形式返回
     g = func()   生成器初始化:将函数变成迭代器
     print(g)
     print(g.__next__())
     print(g.__next__())
    
    
    
     print(range(1,10))
    
     for i in range(1,10,2):
         print(i)
    
    def my_range(start,end,step=1):
        while start < end:
            yield start
            start += step
    
    
    for j in my_range(1,100,2):
        print(j)
    
    
    
    
    
     yield支持外界为其传参
    def dog(name):
        print('%s 准备开吃'%name)
        while True:
            food = yield
            print('%s 吃了 %s'%(name,food))
     def index():
         pass
    
     当函数内有yield关键字的时候,调用该函数不会执行函数体代码
     而是将函数变成生成器
     g = dog('egon')
     g.__next__()   必须先将代码运行至yield 才能够为其传值
     g.send('狗不理包子')   给yield左边的变量传参  触发了__next__方法
     g.send('饺子')
    
    """
    yield
        1.帮你提供了一种自定义生成器方式
        2.会帮你将函数的运行状态暂停住
        3.可以返回值
    
    与return之间异同点
        相同点:都可以返回值,并且都可以返回多个
        不同点:
            yield可以返回多次值,而return只能返回一次函数立即结束
            yield还可以接受外部传入的值
    """
    
    
    
    
    
     列表生成式
     res = [i for i in range(1,10) if i != 4]
     print(res)
    
     res = (i for i in range(1,100000000) if i != 4)   生成器表达式
     print(res)
     """
     生成器不会主动执行任何一行代码
     必须通过__next__触发代码的运行
     """
     print(res.__next__())
     print(res.__next__())
     print(res.__next__())
     print(res.__next__())
    
    
     一次全部读取整个文件占内存
     f = open('xxx.txt','r',encoding='utf-8')
     data = f.read()
     print(len(data))
     f.close()
    
    
     with open('xxx.txt','r',encoding='utf-8') as f:
          n = 0
          for line in f:
              n += len(line)
          print(n)
         g = (len(line) for line in f)
          print(g.__next__())
          print(g.__next__())
          print(g.__next__())
          print(g.__next__())
         print(sum(g))
    
    
    
    def add(n,i):
        return n+i
    def test():
        for i in range(4):
            yield i
    g=test()
    
    for n in [1,10]:
        g=(add(n,i) for i in g)
         第一次for循环g=(add(n,i) for i in test())
    
         第二次for循环g=(add(n,i) for i in (add(n,i) for i in test()))
    print(n)
    res=list(g)
    
    """
    for i in (add(10,i) for i in test()):  会执行所有的生成器内部的代码
        add(n,i)
    """
    
    
    
    
    A. res=[10,11,12,13]
    B. res=[11,12,13,14]
    C. res=[20,21,22,23]  答案
    D. res=[21,22,23,24]
     print(abs(-11.11))   求绝对值
     l = [0,1,0]
     print(all(l))   只要有一个为False就返回False
     print(any(l))   只要有一个位True就返回True
    def index():
    
        username = '我是局部名称空间里面的username'
         print(locals())   当前语句在哪个位置 就会返回哪个位置所存储的所有的名字
        print(globals())   无论在哪 查看的都是全局名称空间
     index()
     print(bin(10))
     print(oct(10))
     print(hex(10))
     print(int('0b1010',2))
    
     print(bool(1))
     print(bool(0))
    
    
     s = 'hello'
     print(s.encode('utf-8'))
     print(bytes(s,encoding='utf-8'))
    
     可调用的(可以加括号执行相应功能的)
     l = [1,2,3]
     def index():
         pass
     print(callable(l))
     print(callable(index))
    
    
    
    
    
     print(chr(97))   将数字转换成ascii码表对应的字符
     print(ord('a'))   将字符按照ascii表转成对应的数
     dir获取当前对象名称空间里面的名字
     l = [1,2,3]
     print(dir(l))
    
     import test
     print(dir(test))
     print(test.name)
    
     divmod  分页器
    
     print(divmod(101,10))
     total_num,more = divmod(900,11)
     if more:
         total_num += 1
     print('总页数:',total_num)
    
     enumerate 枚举
     l = ['a','b']
     for i,j in enumerate(l,1):
         print(i,j)
    
     eval  exec
    s = """
    print('hello baby~')
    x = 1
    y = 2
    print(x + y)
    
    """
     eval(s)
     exec(s)
    
     eval不支持逻辑代码,只支持一些简单的python代码
    s1 = """
    print(1 + 2)
    for i in range(10):
        print(i)
    """
     eval(s1)
     exec(s1)
    
    
     name = 'jason'
     s2 = """
     name
     """
     print(eval(s2))
    
     format 三种玩法
     {}占位
     {index} 索引
     {name} 指名道姓
    
     print(globals())
    def login():
        """
        一起嗨皮
        :return:
        """
     print(help(login))
    
     isinstance 后面统一改方法判断对象是否属于某个数据类型
     n = 1
     print(type(n))
     print(isinstance(n,list))   判断对象是否属于某个数据类型
    
     print(pow(2,3))
    
    
     print(round(3.4))
    
    
    """
    面向过程编程:就类似于设计一条流水线
        好处:
            将复杂的问题流程化 从而简单化
        坏处:
            可扩展性较差   一旦需要修改 整体都会受到影响
    """
    

      迭代器示例

    import sys
     
    def fibonacci(n): # 生成器函数 - 斐波那契
        a, b, counter = 0, 1, 0
        while True:
            if (counter > n): 
                return
            yield a
            a, b = b, a + b
            counter += 1
    f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
     
    while True:
        try:
            print (next(f), end=" ")
        except StopIteration:
            sys.exit()
    

      

    class MyNumbers:
      def __iter__(self):
        self.a = 1
        return self
     
      def __next__(self):
        if self.a <= 20:
          x = self.a
          self.a += 1
          return x
        else:
          raise StopIteration
     
    myclass = MyNumbers()
    myiter = iter(myclass)
     
    for x in myiter:
      print(x)
    

      总结 :

    迭代器 和生成器 其实都是一种类型,既都可以理解为 一个 按钮,你按一下 出一次结果,以此来达到节省内存的效果,注意的是 ,当 yeild被赋值时,需要考虑形参的传递,函数如果含有yeild 那么 函数名()并不会直接运行函数,而是生成器的初始化,然后我们可以 不断的用函数名__next__()的方法 获取yeild右边的返回值,随后yeild的左边的值会被传入下一次的函数运行中. 

  • 相关阅读:
    事件委托
    a标签深入研究
    windows查看端口号
    什么是WCM
    map key循环
    用Myeclipse打war包
    myeclipse 8.510.0 安装 svn 方法
    SVN使用&CVS使用
    MyEclipse 字体大小 字体颜色
    什么是Quickr
  • 原文地址:https://www.cnblogs.com/Sunbreaker/p/11189600.html
Copyright © 2011-2022 走看看