python_可迭代对象,迭代器,生成器
一。可迭代对象
概念:可以用for操作的对象都是可迭代对象
举例:list tuple str set dict 都是可迭代对象
如何判断是否是可迭代对象:
方法一:isinstance(obj,Iterable) ,需要先导入Iterable(from typing import Iterable)
方法二:有__iter__属性就是可迭代对象
print(hasattr(list, "__iter__"))
print(hasattr(tuple, "__iter__"))
print(hasattr(str, "__iter__"))
print(hasattr(set, "__iter__"))
print(hasattr(dict, "__iter__"))
#不可迭代对象
for i in int(1): #会报错:TypeError: 'int' object is not iterable
print(i)
可迭代对象range()的实现方法:
def my_range(stop):
"""模拟了python2中的range"""
value = 1
result = []
while value < stop:
result.append(value)
value += 1
return result
# python2 中有xrange这个函数
# python3 中把python2的 range和xrange 整合为 "range"
if __name__ == '__main__':
# print(my_range(10))
print(isinstance(my_range(10), Iterable))
# 如果输入的数字过大就会很慢
# print(my_range(999999999999999999))
二。迭代器
#如何判断某个对象是不是迭代器
#方法一:isinstance(obj,Iterator) ,需要先导入Iterator
#方法二:看对象有没有__iter__属性和__next__属性
#迭代器协议:
#1。迭代器类型必须实现 __iter__ 和 __next__ (__next__在python2中是next,没有下滑线)
#2。__iter__ 方法必须返回self
#3。__next__必须返回下一个值,如果没有下一个抛出StopIteration异常
from typing import Iterator
obj = range(1,2)
obj1= iter(range(1,2))
#方法一:
print(isinstance(obj,Iterator)) #False
print(isinstance(obj1,Iterator)) #True
print(isinstance([1,2,3],Iterator)) #False
#方法二:
for attr in dir(list):
print(attr) #只有:__iter__属性
for attr in dir(obj1):
print(attr) #有:"__iter__" 和 "__next__" 属性
三。生成器
#生成器的意义:为了快速创建一个迭代器
# yield的关键字,来实现快速创建迭代器,生成器一定是一个迭代器
#yield用法:在函数中使用
#如果一个函数中有yield关键字,调用函数的时候不会执行函数的内容,会返回一个对象(这个对象类型是生成器类)
四:自己实现一个生成器
# 手动实现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:
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))
#第二种方法和第三种方法对比:都是一样的类型 ,返回的都是:<class 'generator'>
print(type(squares(1,4)))
print(type(squares2))
if __name__ == '__main__':
#迭代器实现
# iterator = Squares(1, 3)
# for i in result:
# print(i)
#生成器实现
iterator = squares(1, 3)
for i in result:
print(i)
五:生成器的执行过程
def f():
print("开始执行")
yield 1
print("~~~~~~~~~~")
yield 2
def f2():
result = []
result.append(1)
result.append(2)
return result
#当要访问生成器的__next__方法时,函数会变成 running 状态,当执行完成yield时,函数变成非running状态(即挂起),
# 只有再次执行生成器的__next__方法时函数才会唤醒
#疑问:什么情况下会执行生成器对象的__next__方法那?
# (获取生成器下一个值的时候【参考f()与f2(),这两个方法最终结果是一样的,在执行f()时第二次 yield 2 就是获取下一个值,也就是执行__next__】)
if __name__ == '__main__':
obj = f()
#如果有yield返回的是 generator 对象,如果没有yield 返回的是"开始执行"
print(obj)
print(type(obj))
print(obj.__next__())
print(obj.__next__())
#yield 与 return区别
#共同点:都是python的关键字
#不同点:return 是结束函数并返回值,yield是暂时离开函数
#方法一:isinstance(obj,Iterable) ,需要先导入Iterable
爱折腾的小测试