迭代器与生成器
大约 3 分钟
iterator(迭代器)
# python的迭代协议
# 迭代器是访问容器内元素的一种方式,通常通过for循环遍历容器内元素
# 迭代器是不能通过下标访问的,但它提供了一种延迟访问数据的方式
# Iterable 是可迭代对象
# Iterator 是迭代器
# str、list、tuple、dict、set等容器实现的都是 Iterable ,但它们并不是 Iterator 迭代器
from collections.abc import Iterable, Iterator
print(isinstance("abc", Iterable)) # True
# 因为容器都实现了 __iter__ 方法,因此可以判断一个对象是否是 Iterator
iter_str = iter("abc")
print(isinstance("abc", Iterator)) # False
print(isinstance(iter_str, Iterator)) # True
print(isinstance([1, 2, 3], Iterable)) # True
print(isinstance([1, 2, 3], Iterator)) # False
print(isinstance({1, 2, 3}, Iterable)) # True
print(isinstance({1, 2, 3}, Iterator)) # False
print(isinstance((1, 2, 3), Iterable)) # True
print(isinstance((1, 2, 3), Iterator)) # False
print(isinstance({"name": 'lixingyun', "age": 18}, Iterable)) # True
print(isinstance({"name": 'lixingyun', "age": 18}, Iterator)) # False
# 自定义迭代器
import copy
class MyIterator:
def __init__(self, start, end):
self.start = start
self.end = end
# 内部需要维护一个索引值
self.index = start
# 自定义迭代器必须实现__iter__
def __iter__(self):
return self
# 自定义迭代器必须实现__next__,它会在每次循环时自动执行
def __next__(self):
if self.index < self.end:
current = self.index
self.index += 1
return current
else:
raise StopIteration()
myiter1 = MyIterator(0, 5)
# 如果没有定义 __iter__,那么会再找有没有 __getitem__ 方法,如果也没有,就先创建一个默认的 __iter__
iter_myiter = iter(myiter1)
print(isinstance(iter_myiter, Iterator)) # True
for i in iter_myiter:
print(i, end=" - ") # 0 - 1 - 2 - 3 - 4 -
for i in myiter1:
print(i, end=" + ") # 无输出
print()
# 第二次再执行不会有任何输出,因为迭代器具有`一次性`特征
for i in myiter1:
print(i, end=" / ") # 无输出
print()
# 可以重新创建对象进行迭代
myiter2 = MyIterator(0, 5)
for i in myiter2:
print(i, end=" | ") # 0 | 1 | 2 | 3 | 4 |
print()
# 使用对象拷贝的方式也不会有输出
# 使用浅拷贝
myiter_copy = copy.copy(myiter1)
for i in myiter_copy:
print(i, end=" * ") # 无输出
print()
# 使用深拷贝也不行
myiter_deepcopy = copy.deepcopy(myiter1)
for i in myiter_deepcopy:
print(i, end=" & ") # 无输出
generator(生成器)
Python中的Generator(生成器)
类似于Go语言中的iota
,可以是实时动态生成有序数值,节约内存资源。
# 生成器函数:函数里面只要有 yield 关键字,那么这个函数就是一个生成器函数
def genfunc():
# yield 和它后面的数值没有关系,有几个yield就执行几次
yield 1
# 还可以继续调用 yield
yield 3
# 可以不停地调用 yield
yield 2
# ......
def func():
return 1
# 对比普通函数和生成器函数的区别
# 生成器对象也实现了迭代协议,而且是延迟计算
# 返回生成器对象,在python编译字节码的时候产生
gen = genfunc()
res = func()
print(type(gen)) # <class 'generator'>
print(gen) # <generator object genfunc at 0x7fb8400cf660>
print(next(gen)) # 1
print(next(gen)) # 3
print(next(gen)) # 2
print(type(res)) # <class 'int'>
print(res) # 1
# 实现斐波那契数列
def fib1(max):
flist = []
n, a, b = 0, 0, 1
while n < max:
flist.append(b)
a, b = b, a + b
n += 1
return flist
# 用生成器实现斐波那契数列,由于延迟计算,它在计算时才会占用
def fib2(max):
n, a, b = 0, 0, 1
while n < max:
# 接着上一次返回的位置继续执行
yield b
a, b = b, a + b
n += 1
print(fib1(10)) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
for i in fib2(10):
print(i, end='\t') # 1 1 2 3 5 8 13 21 34 55
print()
def generate(max):
n = 0
while n <= max:
n += 1
yield n
gen = generate(10)
print(next(gen)) # 1
print(next(gen)) # 2
# 生成器的特性之一:已经生成过的数字不会再出现
for i in gen:
print(i) # 3 4 5 6 7 8 9 10 11
# 推导式也是生成器
x = (i for i in range(10))
print(type(x)) # <class 'generator'>
print(next(x)) # 0
print(next(x)) # 1
感谢支持
更多内容,请移步《超级个体》。