可迭代类型
1. 可迭代对象与迭代器对象
collections包下的abc模块中,有一个Iterable,表示可迭代类型。可迭代类型即可以依次获取到每一个元素,可以使用for-in遍历。
from collections.abc import Iterable
print(isinstance(10, Iterable)) # False
print(isinstance('abc', Iterable)) # True
print(isinstance([], Iterable)) # True
print(isinstance(map(str, [10, 20, 30]), Iterable)) # True
在遍历可迭代类型的时候,有些是使用别的序列在记录遍历位置,有些则是自己在记录遍历位置。那么,记录着迭代位置的对象,就是一个“迭代器”。
from collections.abc import Iterator
print(isinstance(10, Iterator)) # False
print(isinstance('abc', Iterator)) # False
print(isinstance([], Iterator)) # False
print(isinstance(map(str, [10, 20, 30]), Iterator)) # True
'''
迭代器序列的数据的特点:
取值只能向前 不能向后 取出之后 迭代器中就没有这个数据了
除了可以使用for-in进行遍历之外 还可以使用next(序列)获取序列中的元素
'''
s = 'hello'
for ch in s:
print(ch)
print('===')
for ch in s:
print(ch)
print('===')
'''
可迭代类型 非迭代器序列类型的数据 在遍历的时候 先创建一个迭代器对象 用它来记录位置 逐个获取元素
'''
# 迭代器序列类型的数据 先把自身设置迭代器【记录自身位置】 然后逐个取值
seq = map(str, [10, 20, 30])
for ele in seq:
print(ele)
print('====')
for ele in seq:
print(ele)
2. 自定义迭代器
在一个类中定义了 _iter_ 魔术方法的,就可以称为是可迭代对象了。这个方法需要返回一个迭代器对象,可以是自己,也可以是其他对象。
在一个类中同时定义了 _iter_ 和 __next__ 魔术方法的,就可以称为是迭代器对象了。
在使用for-in遍历可迭代对象的时候,其实是先获取到迭代器对象,然后每一次循环都调用__next__方法,获取到下一个元素。
class Fibonacci:
def __init__(self, bound):
self.bound = bound # 记录边界
# 记录从几开始遍历
self.current = 1
# 记录前两位的数字
self.number_1 = 1
self.number_2 = 1
# 记录当前的数字
self.current_number = 1
def __iter__(self):
return self
def __next__(self):
if self.current <= self.bound:
if self.current > 2:
self.current_number = self.number_1 + self.number_2
# 为下一位做准备
self.number_1 = self.number_2
self.number_2 = self.current_number
# 位数+1
self.current += 1
return self.current_number
else:
# raise ValueError("后面没有了")
raise StopIteration
fib = Fibonacci(10)
for ele in fib:
print(ele)
for ele in fib:
print(ele)
print(isinstance(fib, Iterable))
print(isinstance(fib, Iterator))
自定义迭代器遍历其他序列
class MySequenceIterator:
def __init__(self, seq):
self.seq = seq # 记录需要遍历的序列
self.current = 0 # 记录当前遍历到的位置
def __iter__(self):
return self # 以自己作为迭代器
def __next__(self):
if self.current < len(self.seq):
# 获取到指定位的元素
value = self.seq[self.current]
# 迭代位置自增
self.current += 1
# 返回处理之后的数据
return str(value).title()
else:
raise StopIteration
# 创建一个序列
l = ["hello world", "python language", "hadoop distributed file system", "mysql database"]
for e in MySequenceIterator(l):
print(e)
3. 生成器
生成器是一种特殊的迭代器,支持迭代器的所有的操作。使用生成器主要用来生成一个序列的。
生成器分为两种:
- 简单表达式:类似于列表推导式
- 函数生成器:定义一个函数,用来生成一系列的数据,将return换成yield即可
简单表达式
# 列表推导式,直接生成一个列表
l1 = [f"{x:03d}" for x in range(1, 200) if x % 7 == 0 and x % 3 == 0]
print(l1)
# 简单表达式生成器,获取到一个生成器对象
l2 = (f"{x:03d}" for x in range(1, 200) if x % 7 == 0 and x % 3 == 0)
print(l2) # <generator object <genexpr> at 0x10474b780>
print(next(l2)) # 021
print(next(l2)) # 042
函数生成器
def get_generator():
for i in range(5, 10000, 5):
if i % 3 == 0:
yield i
"""
return: 结束函数,并把结果返回到调用的位置
yield: 根据逻辑,将数据产出并暂停生产。当下一次获取数据的时候,继续生产数据
"""
gen = get_generator()
print(next(gen))
print(next(gen))
生成器特点
生成器并不直接生成全部的数据,而是根据数据生成的逻辑,每次调用next的时候,才会生成一个元素
因此,生成器常用于在程序中使用大量的数据的时候,此时会有明显的内存占用的效果