一. 迭代器
1.如何查看一个数据类型的所有方法?
#dir()可以查看数据类型所有可使用的方法 print(dir([1,2])) print(dir({1,2})) print(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'] ['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update'] ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
2.通过观察我们不难发现,输出的结果里面都含有 __iter__这个方法(可迭代的都必须含有__iter__方法)
print('__iter__' in dir([1,2])) print('__iter__' in dir({1,2})) print('__iter__' in dir('')) #结果: True True True
3.什么是迭代器呢?
请看下面的例子:
r=[].__iter__() print(r) #结果 : <list_iterator object at 0x000001C90B547358>
返回乐意个有‘iterator的单词,这是什么意思呢?通过百度我们明白了它就是一个迭代器,
我们通过调用列表的__iter__方法就得到了一个迭代器。
4.那我们再看看迭代器里面都含有什么方法
r=[].__iter__() print(dir(r)) #['__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__'方法。那它又有什么用处呢?
L=[1,2,3,4] r=L.__iter__() print(r.__next__()) print(r.__next__()) print(r.__next__()) print(r.__next__()) #1 #2 #3 #4
每调用一次__next__方法都返回一个L列表里面的值,当列表里面的值输出完时,再调用__next__方法会报错
5,好了,通过上面的例子我们可以了解到下面知识:
1.迭代器一定可迭代(必须含有__iter__方法)可迭代不一定就是迭代器
2.迭代器必定含有__iter__,__next__方法
二. 生成器
生成器时在迭代器的基础上形成的(生成器必是迭代器)
1.生成器函数
def genteater(): print('a') yield '1' a=genteater() #a只是一个生成器 print(a) #<generator object genteater at 0x0000015792557048> #generator就是生成器
那如何打印函数里面的值呢?
def genteater(): print('a') yield '1' a=genteater() #a只是一个生成器 print(a.__next__()) #调用__next__ 方法 #a #1
如果你懂了上面的例子,那么请看下面
#调用__next__方法,每次只能执行一次yield,再次调用就从上一个yield哪里开始 def genteater(): print('a') yield '1' print('b') yield '2' a=genteater() #a只是一个生成器 print(a.__next__()) #调用__next__ 方法 print(a.__next__()) #a #1 #b #2
#当然我们也可以用for循环的发放循环生成器 def genteater(): print('a') yield '1' print('b') yield '2' a=genteater() #a只是一个生成器 for i in a: print(i) #a #1 #b #2
2.生成器监听文件的例子:
#监听文件 def tail(file): f=open(file) while True: line=f.readline() if line.strip(): yield line.strip() g=tail('xiaowu') for i in g: if 'python' in i: print('****',i)
send方法(可以向yield传值)
def generator(): print('123') content=yield 'a' print('***',content) print('456') yield 'b' g=generator() print( g.__next__() ) # ===print(g.send(None)) print(g.send('hello')) #和next用法大致一样,只是可以在获取下一个值的时候给上一个yield的位置传值 #send不能用在开头
#send实例 def func(a): def inner(*args,**kwargs): ret=a(*args,**kwargs) ret.__next__() return ret return inner @func def avg(): sum=0 count=0 avg=0 while True: num=yield avg sum+=num count+=1 avg=sum/count avg_1=avg() ret=avg_1.send(10) ret=avg_1.send(2) print(ret)
生成器面试题
#面试题1 def a(): for i in range(4): yield i b=a() b1=(i for i in b) b2=(i for i in b1) print(list(b1)) #[0,1,2,3] print(list(b2)) #[] (g1已经空了,b2取不到值)
#面试题2 def add(x,y): return x+y def generator(): for i in range(4): yield i g=generator() for a in [1,10]: g=(add(a,b) for b in g) print(list(g))
#[20,21,23]
#其中
for a in [1,10]:
g=(add(a,b) for b in g)可以被替换成如下:
a=1
g=(add(a,b) for b in g)
a=10
g=(add(a,b) for b in g) # == g=(add(a,b) for b in (add(a,b) for b in generator() ))
即可以用下列代码表示
def add(x,y): return x+y def generator(): for i in range(4): yield i g=generator() a=1 g=(add(a,b) for b in g) a=10 g=(add(a,b) for b in g) # == g=(add(a,b) for b in (add(a,b) for b in generator() )) print(list(g))