zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Recommended Books for Algo Trading in 2020
    Market Making is simpler than you think!
    Top Crypto Market Makers of 2020
    Top Crypto Market Makers, Rated and Reviewed
    爬取伯乐在线文章(五)itemloader
    爬取伯乐在线文章(四)将爬取结果保存到MySQL
    爬取伯乐在线文章(三)爬取所有页面的文章
    爬取伯乐在线文章(二)通过xpath提取源文件中需要的内容
    爬取伯乐在线文章(一)
    爬虫去重策略
  • 原文地址:https://www.cnblogs.com/foxshu/p/12039646.html
Copyright © 2011-2022 走看看