Python基础之装饰器、迭代器&生成器
一、装饰器
1.定义
本质就是函数,功能 为其它函数添加附加功能
原则:
- 不修改被修饰函数的源代码
- 不修改被修饰函数的调用方式
装饰器的知识储备
装饰器 = 高阶函数+函数嵌套+闭包
这里面要明确高阶函数的定义
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time#导入时间模块儿 def foo(func): # func = test def bar(*args,**kwargs): start_time = time.time() res=func(*args,**kwargs) # 这里就是在运行test() 赋予变量 stop_time = time.time() print("狼来了的时间为%s" %(stop_time-start_time)) return res # 返回test()的值 return bar @foo # @foo 相当于 test=foo(test) 调用foo函数并将test传给func def test(name,age): time.sleep(1) print("名字叫%s年龄为%s的狼来了" %(name,age)) return "村里的羊被吃了" ret = test("灰太狼",age=10) # test()意在运行bar() # 输出res的返回值 print(ret) 装饰器模型
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
先定义一个基本的装饰器:
########## 基本装饰器 ########## def orter(func): #定义装饰器 def inner(): print("This is inner before.") s = func() #调用原传入参数函数执行 print("This is inner after.") return s #return原函数返回值 return inner #将inner函数return给name函数 @orter #调用装饰器(将函数name当参数传入orter装饰器) def name(): print("This is name.") return True #name原函数return True ret = name() print(ret) 输出结果: This is inner before. This is name. This is inner after. True
1.给装饰器传参数:
############ 装饰器传参数 ########### def orter(func): def inner(a,b): #接收传入的2个参数 print("This is inner before.") s = func(a,b) #接收传入的原函数2个参数 print("This is inner after.") return s return inner @orter def name(a,b): #接收传入的2个参数,并name整体函数当参数传入orter装饰器 print("This is name.%s,%s"%(a,b)) return True ret = name('nick','jenny') #传入2个参数 print(ret) 输出结果: This is inner before. This is name.nick,jenny This is inner after. True
给装饰器传万能参数:
########## 万能参数装饰器 ########## def orter(func): def inner(*args,**kwargs): #万能参数接收多个参数 print("This is inner before.") s = func(*args,**kwargs) #万能参数接收多个参数 print("This is inner after.") return s return inner @orter def name(a,b,c,k1='nick'): #接受传入的多个参数 print("This is name.%s,%s"%(a,b)) return True ret = name('nick','jenny','car') print(ret) 输出结果: This is inner before. This is name.nick,jenny This is inner after. True
2.一个函数应用多个装饰器方法:
########### 一个函数应用多个装饰器 ######### def orter(func): def inner(*args,**kwargs): print("This is inner one before.") print("This is inner one before angin.") s = func(*args,**kwargs) print("This is inner one after.") print("This is inner one after angin.") return s return inner
def orter_2(func): def inner(*args,**kwargs): print("This is inner two before.") print("This is inner two before angin.") s = func(*args,**kwargs) print("This is inner two after.") print("This is inner two after angin.") return s return inner
@orter #将以下函数整体当参数传入orter装饰器 @orter_2 #将以下函数当参数传入orter_2装饰器 def name(a,b,c,k1='nick'): print("This is name.%s and %s."%(a,b)) return True ret = name('nick','jenny','car') print(ret) 输出结果: This is inner one before. This is inner one before angin. This is inner two before. This is inner two before angin. This is name.nick and jenny. This is inner two after. This is inner two after angin. This is inner one after. This is inner one after angin. True
3.闭包
1 ''' 2 闭包:在一个作用域里放入定义变量,相当于打了一个包 3 ''' 4 def father(name): 5 def son(): 6 # name='alex' 7 print('我爸爸是 [%s]' %name) 8 def grandson(): 9 # name='wupeiqi' 10 print('我爷爷是 [%s]' %name) 11 grandson() 12 son() 13 father('舒克')
4.综合运用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, {'name':'病毒尖er','passwd':'123'}, ] current_user={'username':None,'login':False} def auth_func(func): # 用户登陆验证 def bar(*args,**kwargs): if current_user["username"] and current_user["login"]: res = func(*args,**kwargs) return res for i in range(3): username = input("请输入用户名:").strip() passwd = input("请输入密码:").strip() for item in user_list: if username == item["name"] and passwd == item["passwd"]: current_user["username"] = username current_user["login"] = True res=func(*args,**kwargs) return res else: print("您输入的用户名或者密码有误") return bar @auth_func # 相当于index=auth_func(index) def index(): print("欢迎来到京东商城" ) @auth_func # 相当于home=auth_func(home) def home(name): print("%s欢迎回家" %name) @auth_func # 相当于shop_car=auth_func() def shop_car(name): print("%s的购物车是空的,赶紧购物咯" %name) index() home(current_user["username"]) shop_car(current_user["username"])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, {'name':'病毒尖er','passwd':'123'}, ] current_user={'username':None,'login':False} def auth(auth_type="file"): def auth_func(func): # 用户登陆验证 def bar(*args,**kwargs): if auth_type == "file": if current_user["username"] and current_user["login"]: res = func(*args,**kwargs) return res for i in range(3): # 给用户三次重复输入的机会 防止进入其它功能进入下一层 username = input("请输入用户名:").strip() passwd = input("请输入密码:").strip() for item in user_list: if username == item["name"] and passwd == item["passwd"]: current_user["username"] = username current_user["login"] = True res=func(*args,**kwargs) return res else: print("您输入的用户名或者密码有误") elif auth_type == "ldap": print("快点告诉你,你用我画的蜡笔") res = func(*args,**kwargs) return res return bar return auth_func @auth(auth_type="file") def index(): print("欢迎来到京东商城" ) @auth(auth_type="ldap") # 传参数 类型对应 def home(name): print("%s欢迎回家" %name) @auth(auth_type="file") def shop_car(name): print("%s的购物车是空的,赶紧购物咯" %name) index() home(current_user["username"]) shop_car(current_user["username"]) 有参装饰器
二、代器 & 生成器
1、迭代器
迭代器只不过是一个实现迭代器协议的容器对象。
迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)
特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
- 便于循环比较大的数据集合,节省内存
>>> a = iter([1,2,3,4,5]) >>> a <list_iterator object at 0x101402630> >>> a.__next__() 1 >>> a.__next__() 2 >>> a.__next__() 3 >>> a.__next__() 4 >>> a.__next__() 5 >>> a.__next__() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration #末尾生成StopIteration异常
2.1、生成器
一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);如果函数中包含yield语法,那这个函数就会变成生成器。
生成器的概念:自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象
def xran(): print("one") yield 1 print("two") yield 2 print("sr") yield 3 ret = xran() #print(ret) #<generator object xran at 0x00000000006ED308> result = ret.__next__() print(result) result = ret.__next__() print(result) result = ret.__next__() print(result) # ret.__next__() #循环完毕抛出StopIteration # # ret.close() #关闭生成器
2.2.生成器表达式
>>>a=[7,8,9] >>>b=[i**2 for i in a] >>>b [49, 64, 81] >>>ib=(i**2 for i in a) >>>ib <generator object <genexpr> at 0x7f72291217e0> >>>next(ib) 49 >>>next(ib) 64 >>>next(ib) 81 >>>next(ib) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
2.4补充1
# 用生成器函数 # yield 相当于return控制的是函数的返回值 # x=yield的另外一个特性,接收send传过来的值,赋值给x def test(): print("开始啦") first = yield # return 1 first = None print("第一次",first) yield 2 print("第二次") t = test() print(test().__next__()) res = t.__next__() # next(t) print(res) res = t.send("函数停留在first那个位置,我就是给first赋值的") print(res) 输出结果 开始啦 None 开始啦 None 第一次 函数停留在first那个位置,我就是给first赋值的 2
2.5补充于总结
1.yield--->自定义函数中只要出现y写了点就说明函数已经是一个Generator。
- yield--->m=yield 5 131 可作为表达式进行赋值,此刻m的值是131,5是def定义的函数返回的值
- yield--->next() 函数被调用后必须经过.__next__()方法执行,直到返回值StopIteration停止
2.send()与next()
- send()与next()作用基本相同,但是send(*)可以产地yield的表达式值进入,而next()不能传递特定的值,只能传递None进去
- 友情提醒:第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值
3.总结
优点:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行
优点一:生成器的好处是延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。
优点二:生成器还能有效提高代码可读性
注意事项:生成器只能遍历一次(母鸡一生只能下一定数量的蛋,下完了就死掉了)
四、python'中 for循环机制
1.首先通过调用.__iter__()方法把他们变成可迭代对象
2.之后for循环调用了__next__方法进行取值
3.for循环会捕捉StopIteration异常,以终止迭代
返回:基础之函数