可迭代对象
1.迭代的概念
使用for循环遍历取值的过程叫做迭代,比如:使用for循环遍历列表获取值的过程
for value in [2, 3, 4]:
print(value)
2.可迭代对象
使用for循环遍历取值的对象叫做可迭代对象, 比如:列表、元组、字典、集合、range、字符串
而这个数据类型里的东西可以使用for被一个一个的取出来,那我们就必须满足for的要求。这个要求就叫做“协议”。
可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了iter方法。
3. 自定义可迭代对象
自定义可迭代对象: 在类里面定义__iter__方法创建的对象就是可迭代对象
from collections import Iterable
# 自定义可迭代对象: 在类里面定义__iter__方法创建的对象就是可迭代对象
class MyList(object):
def __init__(self):
self.my_list = list()
# 添加指定元素
def append_item(self, item):
self.my_list.append(item)
def __iter__(self):
# 可迭代对象的本质:遍历可迭代对象的时候其实获取的是可迭代对象的迭代器, 然后通过迭代器获取对象中的数据
pass
my_list = MyList()
my_list.append_item(1)
my_list.append_item(2)
result = isinstance(my_list, Iterable)
print(result)
for value in my_list:
print(value)
执行结果:
Traceback (most recent call last):
True
File "/Users/hbin/Desktop/untitled/aa.py", line 24, in <module>
for value in my_list:
TypeError: iter() returned non-iterator of type 'NoneType'
迭代器
**1.**迭代器是什么
迭代器只不过是一个实现迭代器协议的容器对象。它基于两个方法:
(1). iter函数: 获取可迭代对象的迭代器,会调用可迭代对象身上的__iter__方法
(2). next函数: 获取迭代器中下一个值,会调用迭代器对象身上的__next__方法
举个例子来看一下,例如数学中有个著名的斐波拉契数列
class Fibonacci(object):
def __init__(self, num):
# num:表示生成多少fibonacci数字
self.num = num
# 记录fibonacci前两个值
self.a = 0
self.b = 1
# 记录当前生成数字的索引
self.current_index = 0
# 在类里面定义__iter__方法创建的对象就是可迭代对象
def __iter__(self):
return self
# 获取迭代器中下一个值
def __next__(self):
if self.current_index < self.num:
result = self.a
self.a, self.b = self.b, self.a + self.b
self.current_index += 1
return result
else:
raise StopIteration
fib = Fibonacci(5)
# value = next(fib)
# print(value)
for value in fib:
print(value)
执行结果:
0
1
1
2
3
2.为什么使用迭代器
“流式”数据处理方式*少内存消耗
例如: 当处理文件时,把所有数据全部取出来放到内存里面进行处理会导致程序消耗大量内存
一般我们会一部分一部分的对文件内容进行处理:
for text_line in open("xx.txt"):
print text_line
open("xx.txt")返回的是可迭代的对象,所以,可以渐进式地对文件的内容进行处理,即按行来读取文件,并进行处理,而不是,
直接把全部文件一下加载到内存中。
3.迭代器的内部
包含有next方法的实现,在正确范围内返回期待的数据以及超出范围后能够抛出StopIteration的错误停止迭代。
迭代器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator
把list、dict、str等Iterable变成Iterator可以使用iter()函数:
4.迭代器的优点
很方便使用,且只能取所有的数据取一次
节省内存空间
生成器
生成器是一类特殊的迭代器,它不需要再像上面的类一样写__iter__()和__next__()方法了, 使用更加方便,它依然可以使用next函数和for循环取值
**1.**创建生成器的两种方法:
my_list = [i * 2 for i in range(5)]
print(my_list)
# 创建生成器
my_generator = (i * 2 for i in range(5))
print(my_generator)
# next获取生成器下一个值
# value = next(my_generator)
#
# print(value)
for value in my_generator:
print(value)
def fibonacci(num):
a = 0
b = 1
# 记录生成fibonacci数字的下标
current_index = 0
print("--11---")
while current_index < num:
result = a
a, b = b, a + b
current_index += 1
print("--22---")
# 代码执行到yield会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行
yield result
print("--33---")
fib = fibonacci(5)
value = next(fib)
print(value)
value = next(fib)
print(value)
value = next(fib)
print(value)
# for value in fib:
# print(value)
#简单来说:只要在def中有yield关键字的 就称为 生成器
**2.**生成器中yield和return的对比
使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
代码执行到yield会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行
每次启动生成器都会返回一个值,多次启动可以返回多个值,也就是yield可以返回多个值
return只能返回一次值,代码执行到return语句就停止迭代,抛出停止迭代异常