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

大城市里の小女人 提交于 2020-02-26 02:33:11

可迭代对象

  • str,tuple,dict,list,set,bytes都为可迭代对象
  • range的结果是一个 range 对象,是一个可迭代对象
  • 可迭代对象的本质:
    • 在迭代一个可迭代对象的时候,实际上就是先获取该对象提供的一个迭代器,然后通过这个迭代器来依次获取对象中的每一个数据。
    • 那么也就是说,一个具备了_ _iter _ _方法的对象,就是一个可迭代对象。

迭代器

  • python中只要实现了__iter____next__方法的对象都可以称之为迭代器,

  • _ _iter _ _() 方法返回一个特殊的迭代器对象,迭代器的 _ _ iter _ _() 返回⾃身, 这个迭代器对象实现了 _ _next _ _() 方法返回下一个值并通过 StopIteration 异常标识迭代的完成。

  • 迭代器是一个带状态的对象,可以记录迭代的位置。

  • str / bytes / list / tuple / dict / set ⾃身不是迭代器,他 们⾃身不具备 _ _next _ _() , 但是具有 _ _iter _ _() , _ _iter _ _() ⽅法 ⽤来把⾃身转换成⼀个迭代器

  • 
    In [1]: s='asdfghh' #字符串为可迭代对象
    
    In [2]: si=s.__iter__() #调用__iter__()方法返回一个迭代器
    
    In [3]: next(si)
    Out[3]: 'a'
    
    
  • _ _next _ _() 方法(Python 2 里是 next())会返回下一个迭代器对象。

  • 执行顺序:

class A:
    def __init__(self):
        self.count=10

    def __iter__(self):
        print('执行 __iter__')
        return self
    def __next__(self):
        print('执行 __next__')
        if self.count>0:
            self.count-=1
            return self.count
        else:
            print('停止迭代')
            raise StopIteration
for i in A():
    print('i=',i)
    
#################################打印的结果
'''
执行 __iter__   #先执行__iter__,返回一个可迭代对象
执行 __next__
i= 9
.
.
.
执行 __next__
i= 1
执行 __next__
i= 0
执行 __next__
停止迭代


'''

  • 练习:用迭代器实现斐波那契数列
class FibonaccIterator(object):
    def __init__(self,n):
        self.n=n
        self.current=0
        self.num1=1
        self.num2=1

    def __iter__(self):
        return self
    def __next__(self):
        if self.current < self.n:
            x=self.num1
            self.num1,self.num2=self.num2,self.num1+self.num2
            self.current +=1
            return x
        else:
            raise StopIteration

生成器

  • generator: ⽣成器是⼀种特殊的迭代器, 不需要⾃定义 _ _iter _ _ 和 _ _next _ _

  • 对一个函数使用yield关键字进行值得返回

  • 生成器能自己记录当前的运行状态,下次启动时会从上次的位置继续执行

  • yield 语句执行时,生成器对象会让出解释器的控制权,生成器自身会挂起

def foo():
    print(111)
    yield 222   #yield会让出解释器的控制权,挂起
    print(333)
    yield 444
    print(555)

n=foo() #含有yield就是一个特殊的函数,仅仅是在封装一个生成器对象
#并不会执行任何结果

next(n)#只有next调用才会有结果
x = next(n)  # 打印 111,返回 222
y = next(n)  # 打印 333,返回 444
z = next(n)  # 打印 555,抛出 异常

  • 除了使用yield实现生成器外,还有另外一种方法实现生成器

    • 
      In [1]: x=(i for i in range(10))
      
      In [2]: type(x)
      Out[2]: generator
      
  • 练习:使用生成器实现斐波那契数列

def gen_fib(n):
    num1=num2=1
    current=0
    while current < n:
        yield num1
        num1,num2=num2,num1+num2
        current+=1
F=gen_fib(12)
for i in F:
    print(i)

手写一个range

class Range:
    def __init__(self, start, end=None, step=1):
        if end is None:
            self.start = 0
            self.end = start
        else:
            self.start = start
            self.end = end
        self.step = step

    def __iter__(self):
        return self

    def __next__(self):
        if self.start < self.end:
            current = self.start
            self.start += self.step
            return current
        else:
            raise StopIteration


for i in Range(5):
    print(i)

for i in Range(5, 10):
    print(i)

for i in Range(10, 20, 3):
    print(i)

使用迭代器,生成器的好处

  • 节省内存
    • 可使用 sys标准库中的getsizeof方法查看使用内存的大小

In [4]: x=range(10000)

In [5]: y=[i for i in range(10000)] #列表推导式

In [6]: import sys

In [7]: sys.getsizeof(x)
Out[7]: 48

In [8]: sys.getsizeof(y)
Out[8]: 87624
  • 惰性求值 (惰性求值思想来⾃于 Lisp 语⾔)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!