您的位置:首页 > 编程语言 > Python开发

Python04-装饰器与迭代器

2020-07-16 04:36 260 查看

装饰器

定义:本质是函数,也是使用def关键字定义,(装饰其他函数)为其他函数添加附加功能。
原则:1,不能修改被装饰的函数的源代码。
2,不能修改被装饰的函数的调用方式。

函数即“变量”:定义函数时即是将函数体赋值给了变量名为函数名的变量
高阶函数:单独使用高阶函数也能给原函数添加新功能,只是会改变调用方式,或添加不了新功能;原函数必须在新函数调用时才执行。
嵌套函数
高阶函数+嵌套函数=》装饰器 :使用高阶函数时为了不修改原函数func(源代码), 将原函数func传递进去,然后使用嵌套函数,在内部定义嵌套函数(只是定义,并没有调用执行),外层的高阶函数将嵌套 函数返回。然后在调用高阶函数时,只是会定义内部的嵌套函数,然后将嵌套函数返回传递给原函数变量func,再次调用func(),便是执行了嵌套的函数。嵌套函数内部可
以添加自己的功能。原函数func的参数传递给嵌套函数的形参。若原函数有返回值,则使用装饰器调用后,最终返回的是嵌套函数的返回值。

python解释器回收垃圾(变量,函数),回收的依据是是否还存在引用;引用计数为0时代表对象可以被回收;使用del 删除对象时并没有删除对象本身,只是将引用计数减1了;

定义函数的函数体在内存中是可以看成一堆字符串,定义函数就是将存储这一串字符串的地址赋值函数名这个"变量”(函数即“变量”)。
函数在调用前一定要定义,多个函数的定义顺序是可以打乱的;

生成器

生成器:生成器在调用时才会生成相应的数据。它只能一个一个接着去生成和访问;而且生成器只能记住当前的位置的元素,并不能向前访问数据或是向后跳跃式的访问数据。
python2.X访问生成器的下一个元素的方法是next(), Python3.X是__next__()方法或者next(g), g代表生成器对象
next()取结束时,会报异常,而使用for循环就不会报异常。当然了,发生异常,也是可以捕获的。如下:

while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break

当生成器的元素的生成规则很复杂时,可以使用函数,然后在函数内部,使用yied来修饰生成器的元素。函数结束也可以return;如下:

def fib(max):
n,a,b = 0,0,1
while n < max:
#print(b)

yield b # 使用yield修饰,表示它不再是普通函数,而是生成器,该生成器遇到yield语句便会返回b然后中断,再次遇到next()就会接着上次中断的地方继续执行

a,b = b,a+b # 等价于t=(b,a+b),此时t的元素已经确定,然后a=t[0], b=t[1]
n += 1

return ‘done’ # 这里的return语句不再是函数结束的标志,而是生成器内元素取完时,抛出异常返回的信息,表示元素取完。
函数调用时执行,执行结束或者遇到return时就结束;而生成器不同,遇到next(g)时执行,遇到关键字yield语句就返回,再次执行会从yield中断的地方继续执行,上面代码时从小往大的方向,如果从大往小的方向,就适合使用递归。

yield后可为空,然后将yield赋值给变量A,在使用生成器的send(variable)方法传值给yield,并将值赋给A,同时会唤醒yield的中断处,使生成器接着往下执行,知道再次中断或者结束。如下:

import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

def producer():
c = consumer('A')
c.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做的第%d个包子!"%(i+1))
c.send(i+1)
producer()

上面的单线程跑出了多线程的效果,称之为协程

迭代器与可迭代对象
我们已经知道,可以直接作用于for循环的数据类型有以下几种:
1,是集合数据类型,如list、tuple、dict、set、str等;
2,是generator,包括生成器和带yield的generator function。
上面可以直接作用于for循环的对象统称为可迭代对象:Iterable,可以使用isinstance()判断一个对象是否是Iterable对象;
生成器可以作用于for循环,还可以被next()函数返回下一个值,直到最后抛出StopIteration异常表示无法继续返回下一个值;
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator,可以使用isinstance()判断一个对象是否是Iterator对象:
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator;把list、dict、str等可迭代对象Iterable变成Iterator可以使用iter()函数,产生一个迭代对象。
使用dir(object),便可以查看对象的所有方法。
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。
可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性
的,只有在需要返回下一个数据时它才会计算。Iterator甚至可以表示一个无限大的数据流,例如全体自然数,而list是无法存储全体自然数的
在Python3.Xx中,range(10)本身就是一个迭代器,而在Python2.Xx中却不是。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: