一、反射
反射就是通过 内置函数getattr() 以字符串的形式导入模块,以字符串的形式调用模块/对象里方法
l=['add','del','set','find'] for i in l: print(i) choice=input("请输入您需要的操作:".strip()) mode=__import__(choice) #相当于 import 模块 getattr(mode,choice[0])() #获取 模块里定义的方法(函数)并且执行;
二、迭代器
Python的数据类型分为
不可迭代类型(数字、布尔值)
可迭代类型(字符串、列表、元组、集合、字典、文件句柄、range、枚举....),
这些可迭代对象有一个共同的特征就是可以被for循环,而不能被for循环的都是不可迭代对象;
那么他们为什么可以被for循环呢?
Python种一切皆对象体现在+/-....语法都可以被Python解释隐藏调用一些双下(__add__。。。。)方法也就是已经被C语言实现好了的方法,当解释器遇到语法就会调用其对应的双下方法,进而返回结果;
顺腾摸瓜我们就来看一下这些可迭代对象中都隐藏了什么__共同的双下___方法;
ret=set(dir({})) & set(dir([])) & set(dir(())) print(ret) {
'__reduce__', '__eq__', '__reduce_ex__', '__getitem__', '__len__', '__sizeof__', '__getattribute__',
'__format__', '__subclasshook__', '__delattr__', '__gt__', '__setattr__', '__hash__', '__contains__',
'__class__', '__iter__', '__doc__', '__le__', '__new__', '__init_subclass__', '__repr__', '__ge__',
'__lt__', '__ne__', '__dir__', '__str__', '__init__'
}
print('__iter__' in set(dir({}))) #可迭代对象拥有__iter__双下方法 print('__iter__' in set(dir(True))) #不可迭代对象没有__iter__双下方法
得知所有的可迭代对象内部都有1个__inter__()双下方法,这就是Python中规定的可迭代协议;
所以在for循环执行之前会去寻找循环对象的__inter__方法,如果没有__inter__方法,循环会直接报错,这是不可以迭代的对象;
l1=[1,2,3,4] print(l1.__iter__())
所有可迭代对象执行__iter__双下方法之后都会返回1个迭代器
l1=[1,2,3,4] print(set(dir(l1.__iter__())) - set(dir({}))) #{'__setstate__', '__next__', '__length_hint__'}
迭代器比可迭代对象多了3个双下方法分别是:__setstate__, __next__, __length_hint__
class A(): def __iter__():pass def __next__():pass a=A() from collections import Iterable from collections import Iterator print(isinstance(a,Iterable))#可迭代对象 print(isinstance(a,Iterator))#迭代器
迭代器协议:实现了__iter__ + __next__方法就是一个迭代器;
迭代器的作用:
1.由于可迭代对象生成数据是不会一下生成全部的数据,而是生成一个迭代器,然后1个1个得吐给你,所以就避免可生成大数据导致内存撑爆;
generater=range(10000000000000000000000000) #迭代器把数字1个1个得吐出来,不会占用1大块内存,而是随着for循环/__next__()1个1个得生成; for n in generater: #随着for循环1个1个得取处迭代器中值 print(n) #big_data=list(range(10000000000000000000000000)) #会把数据1次生成,如果数据量过大,容易沾满内存
2.for循环是 对可迭代协议的实现
为啥列表/字典这些可迭代对象,没有__next__方法,容器中的元素也可以被 for循环出来呢?
因为for循环先执行了 [].__iter()__()把可迭代对象中__iter__()方法returen的结果组成 1个迭代器
然后1次1次得执行 [].__iter()__()__next__()把元素1个1个得获取出来。
#Python中for 循环的原理 list1=['1','2','3','4','5'] g=list1.__iter__() #第1步:可迭代对象执行__iter__()得到1个生成器g print(g.__next__()) #第2步:生成器g.__next__()遍历数据 print(g.__next__()) print(g.__next__()) print(g.__next__())
迭代器的应用场景
在平时写代码的过程中,需要产生大量的数据,但1次性全部生成又会导致内存占用量大,就可以使用迭代器协议,先生成迭代器,然后1个1个得吐出数据;
三、生成器
生成器的本质还是迭代器,可不过这个迭代器是程序员自己实现的;
实现生成器有2种方式:
方式1:yield写生成器函数
def func(): #普通函数 return 'zhanggen' ret=func() print(ret) ------------------------------------------------------------------ def generator(): #0.生成器函数:函数内部包含yield关键字,就是生成器函数 yield 'zhang' yield 'gen' g= generator() #1.生成器函数被调用后,得到1个生成器也就是迭代器作为返回值。 print(g.__next__()) #2.使用__next__()从里面取值 print(g.__next__())
使用生成器生成1000000个哇哈哈哈,只获取前50个
def wahaha(): for i in range(1000000): yield "wahaha%s" %i g=wahaha() print (g.__next__())#wahaha0 count=0 #获取前50个 for i in g: count+=1 if count<=50: print('for循环....%s'%i)
监听文件的输入,然后过滤用户输入的关键字
方式2:生成器表达式
g=(i for i in range(1,100)) print(g.__next__())
四、生成器进阶
send语法
send的作用和next类似,不同的是send可以在获取生成器函数里面 下1个yield 值的同时,还可以在上1个yield 值的右边send1个值到生成器函数里面。
def generator(): print(123) num=yield 1 #Python解释器当遇到1个等号时 先执行右边的yield 1,然后赋值num=yield 1 print('send传入的值',num) print(456) num1=yield 2 print(num1) yield 3 g=generator() print(g.__next__()) #第一次调用生成器时不能使用 send print(g.send('hello'))#send的效果和__next__效果一样 print(g.send('hello1'))#send的效果和__next__效果一样 print(g.__next__())#最后1次调用生成器不使用 send
使用send的注意事项:
综上所述send的功能,send不可以 第1次和最后1次调用生成器时使用。
如何让1个生成器,无限的yield值 ,不会遇到 StopIteration异常。
def average(): print('start') num=0 while True:#下次调用 __next__依然在while循环里面 num+=4 yield num #4 8 12 16... g=average() print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__())
使用sen不断求平均值
#不断得计算平均值 def average(): sum_=0 count_=0 avg_=0 while True: num_=yield avg_ sum_+=num_ count_+=1 print(sum_,num_,count_) avg_=sum_/count_ avg_g=average() avg_g.__next__() print(avg_g.send(10)) print(avg_g.send(12)) print(avg_g.send(15)) print(avg_g.send(16))
yield from 语法
yield from 帮助我们从序列数据类型里1个1个得yield 出每1个元素,而不是使用 for 循环
def generator(): a='abcde' b='12345' yield a yield b ''' abcde 12345 ''' g=generator() for i in g: print(i) def generator(): a='abcde' b='12345' yield from a #帮助我们从序列数据类型里,1个1个yield 出每个元素,而不是使用 for 循环。 yield from b g=generator() for i in g: print(i) ''' a b c d e 1 2 3 4 5 '''
chain多个生成器
def coroutine1(n): print('我这coroutine1里面') yield '1' yield '2' def coroutine2(n): print('我这coroutine2里面') yield '3' yield '4'
def func(n): print('我在func里面') yield from coroutine1(n) #yield from 相当于1个中间件,可以在1个函数里面 直接 把其他生成器里所有yield的值获取到 yield from coroutine2(n) g=func(2) print(next(g)) print(next(g)) print(next(g)) print(next(g)) ''' 我这coroutine1里面 1 2 我这coroutine2里面 3 4 '''