迭代器、生成器、装饰器python
1、装饰器算法
1、函数对象:能够把函数名(不带括号)当成变量去用,关联的值是该函数的内存地址闭包
2、闭包函数=做用域+函数嵌套+函数对象app
核心点:内部函数传参的关系查找是以定义阶段为准函数
3、什么是闭包函数?工具
闭包是一个嵌套函数,内层函数调用了外层函数做用域的变量,外层函数返回值为内层函数名。spa
实质:为函数wrapper传参的一种方式翻译
“闭”函数指的是该函数是内嵌函数code
“包”函数指的是该函数包含对其外层函数做用域名字的引用orm
def outer(): x=1 def wrapper(): print(x) return wrapper f=outer() #为何要返回函数名wrapper:打破内嵌函数wapper只能在outer函数内部调用的规则,使得重回全局调用 f()
4、闭包函数解决的痛点:当wrapper函数体须要传参,又不能直接经过形参传入时,闭包就能够解决此问题
5、什么是装饰器?
定义一个函数(类),在不改变被装饰函数源代码及调用方式的状况下为其增长功能。
import time
def target(x,y): time.sleep(3) print("my name is {} ,age is {}".format(x,y)) return "ok"
#需求:不改变target函数源代码和调用方式的状况下统计target函数的运行时间 import time
def outer(func): #func体现闭包的功能,给wrapper函数体传入须要的参数func,为了避免改变target源码 def wrapper(*args,**kwargs): #*args,**kwargs被装饰函数须要的参数 start=time.time() res=func(*args,**kwargs) end=time.time() print(end-start) return res return wrapper #target=outer(target) #为了避免改变target调用方式 #偷梁换柱:将target函数名指向的内存地址换成了wrapper @outer def target(x,y): time.sleep(3) print("my name is {} ,age is {}".format(x,y)) return "ok" target("lennie",28)#没动源码,也没改变调用方式
6、无参装饰器模板
def outer(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper
7、有参装饰器
在outer函数外再套一层函数outer2,将outer函数体须要的参数,经过outer2形参传入,即成了有参装饰器。
2、迭代器
1、迭代:每一次对过程的重复称为一次“迭代”,而与单纯的重复不一样,每一次迭代获得的结果会做为下一次迭代的初始值。
#重复 while True: msg = input('>>: ').strip() print(msg) #迭代 goods=['mac','lenovo','acer','dell','sony'] index=0 while index < len(goods): print(goods[index]) index+=1
2、可迭代对象:内置有__iter__()方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象,能够直接被for循环遍历。经过obj.__iter__()或者iter(obj)能够返回一个迭代器对象iterator。
3、迭代器:迭代器即用来迭代取值的工具。是Python提供的一种统一的、不依赖于索引的迭代取值方式,只要存在多个“值”,不管序列类型仍是非序列类型均可以按照迭代器的方式取值。
四、迭代器对象:内置有__next__()方法的对象,能够经过iterator.__next__()或者next(iterator)取出出迭代器中的下一个值,能够直接被for循环遍历。
>>> s={1,2,3} # 可迭代对象s >>> i=iter(s) # 本质就是在调用s.__iter__(),返回s的迭代器对象i, >>> next(i) # 本质就是在调用i.__next__() 1 >>> next(i) 2 >>> next(i) 3 >>> next(i) #抛出StopIteration的异常,表明无值可取,迭代结束
2、生成器
一、什么是生成器/生成器对象?
生成器函数(含yield关键字)的返回值为生成器对象,内置有__iter__()和__next__()方法,因此生成器自己就是一个迭代器,能够直接被for循环遍历。
>>> def my_range(start,stop,step=1): ... print('start...') ... while start < stop: ... yield start ... start+=step ... print('end...') ... >>> g=my_range(0,3) >>> g <generator object my_range at 0x104105678> #直接调用不执行函数体 >>> g.__iter__ <method-wrapper '__iter__' of generator object at 0x1037d2af0> >>> g.__next__ <method-wrapper '__next__' of generator object at 0x1037d2af0> >>> next(g) # 触发函数执行直到遇到yield则中止,将yield后的值返回,并在当前位置挂起函数 start... 0 >>> next(g) # 再次调用next(g),函数从上次暂停的位置继续执行,直到从新遇到yield... 1 >>> next(g) # 周而复始... 2 >>> next(g) # 触发函数执行没有遇到yield则无值返回,即取值完毕抛出异常结束迭代 end... Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
二、什么是生成器函数:
(1) 调用生成器函数会自动建立迭代器对象。
(2) 调用迭代器对象的__next__()方法时才执行生成器函数。
(3) 每次执行到yield语句时返回数据,暂时离开。
(4) 待下次调用__next__()方法时继续从离开处继续执行。
三、做用:在循环过程当中,按照某种算法推算数据,没必要建立容器存储完整的结果,从而节省内存空间。数据量越大,优点越明显。
四、生成器表达式
建立一个生成器对象有两种方式,一种是调用带yield关键字的函数,另外一种就是生成器表达式,与列表生成式的语法格式相同,只须要将[]换成(),即:
>>> [x*x for x in range(3)] [0, 1, 4] >>> g=(x*x for x in range(3)) >>> g <generator object <genexpr> at 0x101be0ba0> >>> next(g) #对比列表生成式,生成器表达式的优势天然是节省内存(一次只产生一个值在内存中) 0 >>> next(g) 1 >>> next(g) 4 >>> next(g) #抛出异常StopIteration