迭代器 生成器, 可迭代对象以及应用场景

可迭代对象:

实现了迭代器协议的对象就是可迭代对象(实现方式是,实现iter方法)

迭代器

迭代器对象就是实现了iter() 和 next()方法的对象.其中iter()返回迭代器本身,而next()返回容器的下一个元素,在结尾处引发StopInteration异常.

迭代器有两个方法:

iter() 和 next()

it  = iter(iterable)  # 将一个可迭代对象转换为迭代器
next(it)  # 获取下一个迭代器中的下一个值

`注意`
list dic tuple string 并不是迭代器,它们只是可迭代对象.但是可以通过iter(list)的方法
将它们转换为迭代器.

你可能会问,为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

for x in [1,2,3,4,5]
pass

`完全等价于`

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

自定义迭代器

# encoding:utf-8
__author__ = ‘Fioman‘
__date__ = ‘2018/11/20 20:15‘

from itertools import islice
from collections import Iterator,Iterable
# 自定义一个迭代器,求斐波那契序列
class Fib(object):
    def __init__(self):
        self.prev = 0
        self.curr = 1

    def __iter__(self):
        return self

    def __next__(self):
        value = self.curr
        self.curr += self.prev
        self.prev = value
        return value

# 迭代器对象
f = Fib()
print(isinstance(f,Iterator)) # true
L = list(islice(f,0,10)) # islice对可迭代对象进行切片
print(L)
# [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

class Container:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __iter__(self):
        print("调用了 __iter__(self) 方法")
        return self  # 返回迭代器对象本身

    def __next__(self):

        if self.start < self.end:
            i = self.start
            self.start = self.start + 1
            return i
        else:
            raise StopIteration

Cont = iter(Container(0, 10))

for i in Cont:
    print(i)

总结

  • 所有的iterable都可以通过内置函数iter()转换为iterator
  • 迭代器的优点:省内存.它是一种通过延时创建的方式生成一个序列,只有在需要的时候才被创建.
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问结束,只能往前不能后退
  • 迭代器有两个基本的方法:iter,text方法
  • 内置函数iter(),next(),本质上都是用的对象的iter()和next()方法.

生成器

Python使用生成器对延迟操作提供了支持.所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果.

这也是生成器的主要好处.

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator

创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过generator的next()方法:

Python有两种不同的方式提供生成器:

  • 生成器表达式

类似于列表推导式,是用()代替了原来的[].生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

  • 生成器函数

和常规函数定义一样,但是返回语句return被yield语句代替了.yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行.

  • 使用生成器返回自然数的平方
def gensquares(N):
    for i in range(N):
        yield i ** 2

for item in gensquares(5):
    print(item)
  • 使用普通的函数
# 使用普通的函数

def squares_list(N):
    ret = []
    for i in range(N):
        ret.append(i * i)
    return ret

for item in squares_list(5):
    print(item)

再看生成器

1. 语法上和普通的函数非常相似,都是用def进行定义.唯一的不同是普通的函数是用return返回,而生成器是通过yield语句返回一个值

2.自动实现迭代器协议:对于生成器,Python会自动实现它的可迭代协议,以便用在可以迭代的地方.所以我们可调用它的next方法,获取下一个元素,并且在没有值可以返回的时候,生成器会自动产生StopIteration异常

3.状态挂起:生成器使用yield语句返回一值.yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行.

示例

首先,生成器的好处是延时计算,一次返回一个结果.也就是所它不会一次返回所有的结果,可以节省内存.

sum([i for i in range(1000000000)])
sum((i for i in range(1000000000)))

注意:使用生成器的注意事项

列表生成器,迭代器和生成器的区别?

列表生成器

现在有个需求,看列表[1,2,3,4,5,6,7,8,9],要求你把列表里面的每个值都加1,你怎么实现呢?

方法1: 简单,循环遍历,然后用另外一个列表来实现

# encoding:utf-8
__author__ = ‘Fioman‘
__date__ = ‘2018/12/6 11:26‘

# 现在有一个需求,[1,2,3,4,5,6],要求你将里面的数每个数都加1,你怎么办?

# 方法1: 遍历,然后添加
def func1(num_list):
    # # 使用append
    # b = []
    # for i in num_list:
    #     b.append(num_list[i])
    for index, i in enumerate(num_list):
        num_list[i] += 1

    print(num_list)

# 方法2: 使用map,匿名函数.map的作用,就是前面的参数是一个函数,然后是一个可迭代对象
# 将可迭代对象逐个的带入到前面的函数中,返回一个列表
def func2(num_list):
    a = map(lambda x:x+1,num_list)
    print(a)

# 方法3: 高级,直接使用列表推导式

def func3(num_list):
    a = [x+1 for x in num_list]  # 列表推导式,前面是一个表达式,表示结果,后面跟一个for加一个可迭代的对象,再后面还可以跟
    # 一个if else 语句进行判断
    print(a)

if __name__ == ‘__main__‘:
    num_list = [1, 2, 3, 4, 5, 6]
    func1(num_list)

生成器

什么是生成器

通过列表推导式,我们可以直接创建一个列表,但是如果这个列表的长度很大,就很占用内存,比如我们想要创建一个100万个元素的列表,就会占用很大的内存空间.

如果列表元素可以按照某种算法推算出来,我们可不可以在一边循环的过程中不断的推算出后续的元素呢?这样就不需要一次性分配出一个list所需要的全部的内存空间,答案是肯定的,在Python中我们通过生成器的机制,可以实现一边循环一边分配空间.

生成器是迭代器的一种,Python中有两种方法来实现生成器,一个是生成器表达式,一个是生成器函数.

生成器表达式:

将列表推导式的[] 换成圆括号就是生成器表达式.

sum([i for i in range(1000000000)])
sum((i for i in range(1000000000)))

生成器函数,带yield的函数

生成器是一个特殊的函数,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield代替return返回,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器.

生成器类似于返回值为一个数组的一个函数,这个函数可以接收参数,可以被调用,但是不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,生成器可以被看作是一个函数,但是它本质上也算是一个迭代器.

小结

  • 凡是可以用作for循环的对象都是可迭代对象,都遵循了可迭代协议
  • 凡是可以用next()取出下一个元素,使用iter()返回自身的的迭代器类型
  • 可迭代数据类型如list,dict,str等都是Iteralbe但不是迭代器Iterator,不过可以通过iter(list)函数获取一个迭代器对象

对于yield的总结

  • 通常的for ... in ..循环中,后面的是一个列表或者是字典,或者是字符串.它的缺点是很明显的,就是在迭代的时候一下就分配了全部的内存,这样数据比较大,将会占用很大的内存.
  • 生成器是可以迭代的,但是只可以读取它一次,因为用的时候才生成.生成器表达式和列表推导式的区别就是生成器表达式使用小括号而列表推导式使用[]
  • 生成器(generator)能够迭代的关键是他有next()方法,工作原理是通过重复调用next()方法,直到捕获一个StopIteration异常
  • 带有yield的函数不再是一个普通的函数,而是一个生成器函数.可以用于迭代
  • yield就是return返回的一个值,并且记住这个返回的位置.下一次迭代就从整个位置开始
  • send()和next()的区别就在于send可传递参数给yield表达式,这时候传递的参数就会作为yield表达式的值,而yield的参数是返回给调用者的值,也就是说send可以强行修改上一个yield表达式的值

作者:莫辜负自己的一世韶光
链接:https://www.jianshu.com/p/411352426841
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

原文地址:https://www.cnblogs.com/liurenli/p/10127818.html

时间: 2024-10-13 11:52:07

迭代器 生成器, 可迭代对象以及应用场景的相关文章

迭代器_可迭代对象_生成器

[可迭代对象]保存的是已经生成好的数据,占用大量的空间有__iter__方法 就是可迭代对象(Iterable) [迭代器]保存的是生成数据的方法,占用极小的空间,需要时才返回数据既有__iter__,也有__next__ 就是迭代器(Iterator) [生成器]是一个[特殊]的迭代器,保存生成数据的方法(标志就是def中的[yiled],有了yield的def就不是函数(function) 生成器的send(参数) 可以在唤醒时返回参数(需要变量接收), 可迭代对象(iterable):能用

理解迭代器和可迭代对象

前言: 之前在迭代器.可迭代对象这一部分一直有些混淆,结合一些资料,表达我对这些概念的理解,未必都对,但是适合刚开始入手的朋友们从零开始理解 开门见山首先介绍可迭代对象和迭代器的通俗理解 迭代器就是能被next()调用得到下一次迭代值的对象,迭代器不直接保存迭代的序列值,而保存得到下一次迭代值的算法 可迭代对象就是能被iter()方法调用得到迭代对象的对象,只有可迭代对象才可用于for循环 for循环的底层实现原理: 以下是一个for循环的格式 for i in 可迭代对象: 循环体 实质是调用

学习7: 列表生成式,生成器,迭代器,可迭代对象

1) 列表生成式,即创建列表的方式 列表生成式,这里是中括号[] >>> [x*x for x in range(0,10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> [x * x for x in range(1, 11) if x % 2 == 0] [4, 16, 36, 64, 100] >>> [m + n for m in 'ABC' for n in 'XYZ'] ['AX', 'AY', 'AZ

Python生成器、迭代器、可迭代对象

把一个列表[]改成()就创建了一个生成器:generator,generator保存的是算法. 可以用于for循环的数据类型:1.集合类型:list tuple dict set str2.generator 可以直接作用于for循环的对象统称为:可迭代对象(Iterable) from collections import Iterable print(isinstance([],Iterable)) print(isinstance({},Iterable)) print(isinstanc

python的生成器与迭代器和可迭代对象

来简单的说下python中的生成器和可迭代对象以及迭代器的问题.只是简单地记录一下并不涉及太深入的内容. 首先来说一下什么是生成器,先看下面的代码: 1 #_*_ coding:utf-8 _*_ 2 3 result = (x for x in range(10)) 4 5 ''' 6 下面print的打印结果 7 <generator object <genexpr> at 0x0000026FA092B360> 8 ''' 9 print(result)  上面的这种代码其实

Python全栈开发之---迭代器、可迭代对象、生成器

1.什么叫迭代 现在,我们已经获得了一个新线索,有一个叫做"可迭代的"概念. 首先,我们从报错来分析,好像之所以1234不可以for循环,是因为它不可迭代.那么如果"可迭代",就应该可以被for循环了. 这个我们知道呀,字符串.列表.元组.字典.集合都可以被for循环,说明他们都是可迭代的. 我们怎么来证明这一点呢? 1 from collections import Iterable 2 3 l = [1,2,3,4] 4 t = (1,2,3,4) 5 d =

迭代器、可迭代对象、迭代器对象、生成器、生成器表达式和相关的面试题

迭代器: 迭代的工具.迭代是更新换代,如你爷爷生了你爹,你爹生了你,迭代也可以说成是重复,并且但每一次的重复都是基于上一次的结果来的.如计算机中的迭代开发,就是基于软件的上一个版本更新.以下代码就不是迭代,它只是单纯的重复 可迭代对象 python中一切皆对象,对于这一切的对象中,但凡有__iter__方法的对象,都是可迭代对象. 可迭代的对象:Python内置str.list.tuple.dict.set.file都是可迭代对象. 迭代器对象 只有字符串和列表都是依赖索引取值的,而其他的可迭代

迭代器,可迭代对象,迭代器对象和生成器

1  迭代器 迭代的定义:迭代是一个重复的过程,不同于其他纯粹的重复,迭代的每一次结果都是基于上一次迭代的结果产生的. 迭代器就是一个可以进行迭代取值的工具 作用:给我们提供了一种不依赖索引取值的方式 补充:针对双下划线开头,双下滑线结尾的方法 推荐读:双下+方法名 2 可迭代对象 内置有__iter__方法的对象(列表,词典,元组,字符串,集合等) 3 迭代器对象 即内置有__iter__方法也内置有__next__方法的对象(文件,类等) 注意:迭代器对象一定是可迭代对象,但可迭代对象不一定

迭代器 and 可迭代对象

可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器和带yield的generator function. 这些可以直接作用于for循环的对象统称为可迭代对象:Iterable. 而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了. 可以被next()函数调用并不断返回下一个值的对象称为迭代器