可迭代对象
如何判断一个对象是不是可迭代对象:
方法一:isinstance(obj, Iterable)
方法二:看有没有__iter__方法
迭代器
如何判断某个对象是不是迭代器:
方法一:ininstance(obj, Iterator)
方法二:看对象有没有__iter__属性和__next__属性。
迭代器协议:
- 迭代器类型必须实现__iter__和__next__(python 2是next)
- __iter__方法必须返回self
- __next__必须返回下一个值,如果没有下一个则抛出StopIterator异常
- 对迭代器进行for操作时,每次操作都会执行__next__方法
- 只能迭代一遍。
- for语句的迭代,会忽略StopIteration异常。
from typing import Iterator
obj = range(1,2)
obj1 = iter(range(1,2)) #把range(1,2)转化为Iterator类型
for attr in dir(obj1):
print(attr) #包含__iter__属性和__next__属性
print(isinstance(obj,Iterator)) # False
print(isinstance(obj1,Iterator)) #True
自己动手实现一个迭代器
# range(1,5) 1,2,3,4,5
# next(5) 1,2,3,4
class Next(object):
def __init__(self, stop, start=0):
self.start = 0
self.stop = stop
def __next__(self):
"""如果有下一个数则返回下一个参数,如果没有下一个则抛出StopIteration异常"""
if self.start >= self.stop -1:
raise StopIteration
self.start +=1
return self.start
def __iter__(self):
return self
if __name__=='__main__':
obj = Next(5)
for i,value in enumerate(obj): # 将索引和值都迭代出来
print(i, value)
for i in obj:
print(i)
# print(obj.__next__())
# print(obj.__next__())
# print(obj.__next__())
# print(obj.__next__())
# print(obj.__next__())
迭代器的应用场景
- list存1~10000的数据,占10000个整数的内存,而迭代器,占用几个整数的内存。
- 用Python批量下载图片的爬虫,把所有图片都放到list中,占用内存;每获得一个图片,保存一个图片。
类似装水,要把一桶水用杯子转移到另一个水桶中,
list:50个杯子一次装50杯倒进另一个水桶里。
迭代器:一个杯子,装50次依次倒入另一个水桶。
生成器
生成器的意义:为了快速方便地创建一个迭代器。
yield关键字,实现快速创建迭代器
yield在函数中用
如果一个函数中有yield关键字,调用函数的时候不会执行函数的内容,会返回一个对象,这个对象的类型是生成器类。
生成器一定是一个迭代器。
生成器是如何执行的?
yield和return的区别?
共同点:都是Python关键字
不同点:return是结束函数并返回值,yield是暂时离开函数,遇到__next__以后还会回到函数。
当要访问生成器的__next__方法时,函数会变成running状态,当执行完yield时会暂时离开函数,函数变成非running(挂起)。只有再次执行生成器__next__方法时,函数才会被唤醒。
什么时候会执行生成器对象的__next__方法呢?获取生成器下一个值的时候。
自己动手实现生成器
# 手动实现平方,传参(1,3),返回1,4,9
# 常规方法
result = []
for i in [1,2,3]:
result.append(i*i)
print(result)
# 迭代器实现
class Squares(object):
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __iter__(self):
return self
def __next__(self):
if self.start >=self.stop+1:
raise StopIteration
current = self.start * self.start
self.start +=1
return current
# 生成器实现
def squares(start, stop):
for i in range(start, stop + 1):
yield i * i
# 生成器表达式实现:⽣生成器表达式和列表推导式的语法基本上是⼀样的. 只是把[]替换成()
squares2 = (i * i for i in range(1, 4))
if __name__ == '__main__':
# iterator = Squares(1,3)
iterator = squares(1,3)
for i, value in enumerate(iterator):
print(i, value)