一、迭代器
字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。
print(dir([])) #告诉我列表拥有的所有方法
ret = set(dir([]))&set(dir({}))&set(dir(''))&set(dir(range(10)))
print(ret) #iterable
print('__iter__' in dir(int))
print('__iter__' in dir(bool))
print('__iter__' in dir(list))
print('__iter__' in dir(dict))
print('__iter__' in dir(set))
print('__iter__' in dir(tuple))
print('__iter__' in dir(enumerate([])))
print('__iter__' in dir(range(1)))
#输出:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
{'__str__', '__hash__', '__subclasshook__', '__ge__', '__len__', '__reduce_ex__', '__ne__', '__new__', '__getitem__', '__doc__', '__repr__', '__le__', '__reduce__', '__class__', '__delattr__', '__iter__', '__contains__', '__dir__', '__init__', '__eq__', '__init_subclass__', '__format__', '__getattribute__', '__gt__', '__sizeof__', '__lt__', '__setattr__'}
False
False
True
True
True
True
True
True
由以上可以得知:
只要是能被for循环的数据类型 就一定拥有 __iter__ 方法
print([].__iter__())
#输出
<list_iterator object at 0x00C2AE30>
一个列表执行了__iter__()之后的返回值就是一个迭代器
print(dir([]))
print(dir([].__iter__()))
print(set(dir([].__iter__())) - set(dir([])))
链表迭代器方法的集合 - 链表方法的集合 =链表迭代器有的方法而链表没有的
输出:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
{'__next__', '__length_hint__', '__setstate__'}
重点学习:{'__next__', '__length_hint__'}
print([1,'a','bbb'].__iter__().__length_hint__())
输出:3
.__length_hint__() 返回元素个数
l = [1,2,3]
iterator = l.__iter__()
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
输出:
1
2
3
StopIteration :报错的意思,原因是链表中只有3个元素,第四次迭代时已经没元素了,所以报错
总结:
Iterable 可迭代的 -- > __iter__ 只要含有__iter__方法的都是可迭代的
[].__iter__() 迭代器 -- > __next__ 通过next就可以从迭代器中一个一个的取值
只要含有__iter__方法的都是可迭代的 —— 可迭代协议
迭代器协议 : 内部含有__next__和__iter__方法的就是迭代器
可以被for循环的都是可迭代的
# 可迭代的内部都有__iter__方法
# 只要是迭代器 一定可迭代
# 可迭代的.__iter__()方法就可以得到一个迭代器
# 迭代器中的__next__()方法可以一个一个的获取值
for
只有 是可迭代对象的时候 才能用for
当我们遇到一个新的变量,不确定能不能for循环的时候,就判断它是否可迭代
迭代器的好处:
# 从容器类型中一个一个的取值,会把所有的值都取到。
# 节省内存空间
#迭代器并不会在内存中再占用一大块内存,
# 而是随着循环 每次生成一个
# 每次next每次给我一个
二、生成器
1、只要含有yield关键字的函数都是生成器函数 yield不能和return共用且需要写在函数内
def generator():
print(1)
yield 'a'
#生成器函数 : 执行之后会得到一个生成器作为返回值
ret = generator()
print(ret)
print(ret.__next__())
输出:
<generator object generator at 0x00914DF0>
1
a
2、yield会结束本次迭代。并且在一个迭代器中迭代时,下一次迭代是挨着上一次迭代的位置迭代的
栗子:
def generator():
print(1)
yield 'a'
print(2)
yield 'b'
yield 'c'
g = generator()
ret = g.__next__()
print(ret)
输出:
1
a
def generator():
print(1)
yield 'a'
print(2)
yield 'b'
yield 'c'
g = generator()
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)
输出:
1
a
2
b
def generator():
print(1)
yield 'a'
print(2)
yield 'b'
yield 'c'
g = generator()
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)
输出:
1
a
2
b
c
三、监听文件输入的例子
def tail(filename):
f = open(filename,encoding='utf-8')
while True:
line = f.readline()
if line.strip():
yield line.strip()
g = tail('file')
for i in g:
if 'python' in i:
print('***',i)