10分钟理解迭代器,生成器,可迭代对象

158 阅读3分钟

迭代器 iterable

1.定义

  • 当类中定义了__iter__和__next__两个方法
  • __iter__方法需要返回对象本身,即self
  • __next__方法,返回下一个数据,如果没有数据,则需要抛出一个StopIteration异常。

官方文档:docs.python.org/3/library/s…

2.创建迭代器类型

class IteratorObject(object):
    def __init__(self):
        self.counter = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter > 3:
            raise StopIteration("没有next了")
        return self.counter

3.实例化创建迭代器对象

迭代器可以通过obj.__next__()获取next数据,或者通过python内置函数next(obj)方法获取效果是一样的,当没有下一个next数据时会抛出异常StopIteration

迭代器可以使用for循环,for循环首先会执行__iter__方法获取返回值,并对返回值一直反复执行next,将next数据作为当前循环值,若无next数据则退出循环不会报错。生成器,可迭代对象使用for循环也是同样的原理

obj1 = IteratorObject()  # 创建示例

print(obj1.__next__())  # 访问next
print(next(obj1))  # 简洁的访问方式,效果一致

# 迭代器也能通过循环访问
for item in obj1:
    print(item)

try:
    # 若超出
    print(next(obj1))
except StopIteration as e:
    print("出错:", e)
for item in obj1:
    print(item)

生成器

1.定义

一个函数只要包含yield那这个函数就是生成器函数,实例化生成器函数得到的对象就是生成器对象,生成器对象内部是根据生成器类Generator创建的,而Generator内部也声明了__iter__和__next__,所以生成器是一种特殊的迭代器。

# 创建生成器函数
def func():
    yield 1
    yield 2


# 创建生成器对象
obj1 = func()

print(next(obj1))
for i in obj1:
    print(i)
try:
    print(next(obj1))
except StopIteration as e:
    print("StopIteration")

2.生成器的好处

生成器能大大降低内存和提高运行速度,下面代码表示新建函数用来创建储存相同数据的对象create_list方法用list类型来创建对象,creat_generator函数用生成器来创建对象,分别运行观察内存消耗和运行时间。

def create_list():
    start_time = time.time()
    print(f'list 内存前:{mem.memory_usage()}')
    a = [i * 4 for i in range(10000000)]
    print(f'list 内存后:{mem.memory_usage()}')
    print(f'list 运行时间:{time.time() - start_time}')


def create_generator():
    start_time = time.time()
    print(f'generator 内存前:{mem.memory_usage()}')
    # 生成器推导式 不是列表也不是元组
    a = (i * 4 for i in range(10000000))
    print(f'generator 内存后:{mem.memory_usage()}')
    print(f'generator 运行时间:{time.time() - start_time}')
list 内存前:[18.30859375]
list 内存后:[404.8359375]
list 运行时间:0.8840179443359375
generator 内存前:[18.73046875]
generator 内存后:[18.73046875]
generator 运行时间:0.21883869171142578

对比执行结果可明显看出利用生成器来获取对象内存消耗少,运行时间快。这是因为假如对象里包含的所有元素就是一个苹果,现在需要100个苹果,用列表的方式就是把这100个苹果一起生产出来放到房间里;但用生成器的方式就是制造了一个生产苹果的机器,这个机器能生产100个苹果,你需要一个它就生产一个,所以占用内存少速度快。

可迭代对象

1.定义

如果一个类中有__iter__方法且返回一个迭代器对象,则这个类是可迭代对象类。通过这个类创建的对象为可迭代对象。

class Foo(object):
    def __iter__(self):
        return 迭代器对象/生成器对象