精析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方法使用的少。

 

posted @ 2018-09-01 13:50  Sakura_L  阅读(314)  评论(0编辑  收藏  举报