精析python中的装饰器、生成器
装饰器:
wahaha()
jiaduobao()
此处调用原函数时,可以发现函数的功能是可以正常执行的,符合了编程开放-封闭的规则,而设置了一个可以控制的变量FLAGE,通过改变FLAGE的值,控制装饰器的开关。
分析:@time_out(FLAGE) 可以把@和time_out(FLAGE)分开来看,在python中程序都是从右向左执行的,所以先执行time_out(FLAGE)这层函数,将timer的内存地址给返回给@,而@就等于wahaha = timer(wahaha),再将inner的内存地址返回出来,在调用wahaha()时,其本质就是在调用inner,而在inner的内部做到了FLAGE控制装饰器的功能,这里用到了闭包这个概念。
闭包:在内层函数可以引用外层函数的变量,在使用装饰器时,就是利用了闭包这个原理,在执行完外层函数后,并没有把变量立即释放掉,而是封装在函数的内部。
生成器:
生成器的本质就是迭代器,那么什么是迭代器呢?这涉及到什么是可迭代的对象。
可迭代的对象:含有__iter__方法的对象,可以通过.__dict__查看名称空间判断,可迭代的对象一定可以被for循环,例如str、list、dir、set、range等等
而迭代器就是同时拥有__iter__和__next__方法的可迭代对象。而可迭代对象可以通过调用__iter__方法成为一个迭代器。
言归正传,生成器就是迭代器的一种,生成器有两种表现形式,第一种是生成器函数,第二种是生成器表达式。
生成器函数就是含有yield关键字的函数
生成器函数特点:调用函数之后函数不会执行,而是返回一个生成器,每次调动next()方法时才会去取出一个值。直到取到了最后一个值,再执行一次next(),那么程序就会报错。
生成器表达式:g=(i for i in range(10))
此时的g就是一个生成器了,比函数更方便。
从生成器中取值的几个方法:
1.next 2.for 3.数据类型的强制转换 例如:list(g) g代表一个生成器
强制转换存在一个缺点就是会瞬间占用内存,如果生成器中存储的数据较多,那么有撑爆内存的风险,造成电脑死机。而for循环和next都是一个一个去取的,即拿即用,所以不存在这个风险。
分析生成器:
此例中g=test()时并没有去执行任何操作,只是把生成器返回给了g,在遇到for循环生成器嵌套问题时,需要把问题拆分。
n=1时,g=(add(i,n) for i in test()) #此时的g就是test()
n=10,g=(add(i,n) for i in g=(add(i,n) for i in test()))#此时的g是上面的g,g被重新赋值了一次。
n=5,g=(add(i,n) for i in (add(i,n) for i in g=(add(i,n) for i in test())),此时g又被赋值了一次,现在可以将n=5代入计算了,test()取到的就是0,1,2,3
生成器中还有一个send()的方法
send()的效果与next基本一致,只是在获取下一个值的时候,给上一个yield传递一个数据(信号)。
send()使用时的注意事项,第一次使用生成器的时候,是用next获取下一个值的,最后一个yield也不能接受外部的值。
例:
来分析一下程序执行的过程,首先g=test(),那么g就是一个生成器,随后a=g.__next__(),使生成器执行一次并yield1,此时count=这个赋值语句还没来得及执行就被yield打断了,先返回了1,所以print(a)能得到123,1
然后调用了send('hello'),此时count=赋值语句执行,将hello赋值给了count,打印出======hello,然后再打印456,yield2,程序再次终止。
相对于next来说send方法使用的少。