迭代器、生成器、装饰器
一、装饰器
1、函数对象:可以把函数名(不带括号)当成变量去用,关联的值是该函数的内存地址
2、闭包函数=作用域+函数嵌套+函数对象
核心点:内部函数传参的关系查找是以定义阶段为准
3、什么是闭包函数?
闭包是一个嵌套函数,内层函数调用了外层函数作用域的变量,外层函数返回值为内层函数名。
实质:为函数wrapper传参的一种方式
“闭”函数指的是该函数是内嵌函数
“包”函数指的是该函数包含对其外层函数作用域名字的引用
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形参传入,即成了有参装饰器。
def decorator(x):
def outer(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
print(x)
return res
return wrapper
return outer
二、迭代器
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提供的一种统一的、不依赖于索引的迭代取值方式,只要存在多个“值”,无论序列类型还是非序列类型都可以按照迭代器的方式取值。
4、迭代器对象:内置有__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的异常,代表无值可取,迭代结束
三、生成器
1、什么是生成器/生成器对象?
生成器函数(含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
2、什么是生成器函数:
- 含有yield语句的函数
- 调用生成器函数将返回一个生成器对象,不执行函数体
- yield翻译为”产生”或”生成”,返回多个对象用yield(迭代),返回一个对象用return
(1) 调用生成器函数会自动创建迭代器对象。
(2) 调用迭代器对象的__next__()方法时才执行生成器函数。
(3) 每次执行到yield语句时返回数据,暂时离开。
(4) 待下次调用__next__()方法时继续从离开处继续执行。
3、作用:在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。
4、生成器表达式
创建一个生成器对象有两种方式,一种是调用带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
四、lambda表达式及内置高阶函数
1、lambda表达式
- 定义:是一种匿名函数(方法)。
- 作用:作为参数(实参)传递时语法简洁,优雅,代码可读性强。随时创建和销毁,减少程序耦合度。
- 语法
1.定义:
变量 = lambda 形参: 方法体
2.调用:
变量(实参)
- 说明:
-- 形参没有可以不填
-- 方法体只能有一条语句,且不支持赋值语句。
2、内置生成器函数
- enumerate(可迭代对象):遍历可迭代对象时,可以将索引与元素组合为一个元组。
- zip(可迭代对象1, 可迭代对象2….):将多个可迭代对象中对应的元素组合成一个个元组,生成的元组个数由最小的可迭代对象决定。
- map(函数,可迭代对象):映射,使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象(生成器对象)。
- filter(函数,可迭代对象):过滤,根据条件筛选可迭代对象中的元素,返回值为新可迭代对象(生成器对象)。
>>:a=[1,2,3] >>:b=[4,5,6] >>:ge=enumerate(a) #返回一个生成器,每个元素为一个元组(index,value) >>:ge <enumerate object at 0x000000000357C240> >>:list(ge) [(0, 1), (1, 2), (2, 3)] >>:next(ge) Traceback (most recent call last): File "<input>", line 1, in <module> StopIteration >>:ge=zip(a,b) #返回一个生成器,每个元素为一个元组(a[index],b[index]) >>:ge <zip object at 0x0000000003435308> >>:next(ge) (1, 4) >>:list(ge) [(2, 5), (3, 6)]
>>:ge=map(lambda x : x**2 , a) #让a中每个元素平方,返回一个生成器 >>:ge <map object at 0x000000000356AC50> >>:next(ge) 1 >>:next(ge) 4 >>:next(ge) 9 >>:next(ge) Traceback (most recent call last): File "<input>", line 1, in <module> StopIteration >>:ge=filter(lambda x :x%2==0,b) #筛选b中满足条件的元素,返回一个生成器 >>:ge >>:<filter object at 0x000000000356A828> >>:list(ge) [4, 6]