12-[函数进阶]-装饰器
1.引入装饰器
(1)函数版本
(2)添加登录模块
user_status = False def login(): _username = "alex" #假装这是DB里存的用户信息 _password = "123" #假装这是DB里存的用户信息 global user_status if user_status == False: username = input("user:") password = input("pasword:") if username == _username and password == _password: print("welcome login....") user_status = True else: print("wrong username or password!") else: print("用户已登录,验证通过...") def home(): print("---首页----") def japan(): print("----日韩专区----") def henan(): login() print("----河南专区----") japan() henan()
我现在有很多模块需要加认证模块,你的代码虽然实现了功能,但是需要更改需要加认证的各个模块的代码,这直接违反了软件开发中的一个原则“开放-封闭”原则,
简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
- 封闭:已实现的功能代码块不应该被修改
- 开放:对现有功能的扩展开放
(3)登录函数中调用japan函数
(4)装饰器原理
2.语法糖:装饰器
python解释器就会从上到下解释代码,步骤如下:
- def login(func): ==>将login函数加载到内存
- @login
没错, 从表面上看解释器仅仅会解释这两句代码,因为函数在 没有被调用之前其内部代码不会被执行。
从表面上看解释器着实会执行这两句,但是 @login 这一句代码里却有大文章, @函数名 是python的一种语法糖。
3.通用装饰器
user_status = False def login(fun): def inner(*args,**kwargs): # 可变参数 _username = "alex" _password = "123" global user_status if user_status == False: username = input("user:") password = input("pasword:") if username == _username and password == _password: print("welcome login....") user_status = True else: print("wrong username or password!") if user_status == True: fun(*args,**kwargs) # 可变参数 return inner
4.两个装饰器
def w1(func): print('---正在装饰--') def inner(): print('---正在验证权限1--') func() return inner def w2(func): print('---正在装饰2--') def inner(): print('---正在验证权限2--') func() return inner # 只要python解释器执行到了这个代码,那么就会自动的进行装饰,而不是等到调用的时候才装饰的 @w2 @w1 def f1(): print('---f1') f1()
5.带参数装饰器
- 在原有装饰器的基础上,设置外部变量,执行一次函数,获取它的返回值而已
def func_arg(arg): def func(functionName): def func_in(): print("---记录日志-%s-"%arg) functionName() return func_in return func #1.先执行func_arg("heihei")函数,这个函数return 的结果是func这个函数的引用 #2.@func #3.使用@func对test进行装饰 @func_arg('heihei') def test1(): print('---testt') test1()
---记录日志-heihei- ---testt
有什么用?
# 认证函数 def auth(request,kargs): print("认证成功!") # 日志函数 def log(request,kargs): print("日志添加成功") # 装饰器函数。接收两个参数,这两个参数应该是某个函数的名字。 def Filter(auth_func,log_func): # 第一层封装,f1函数实际上被传递给了main_fuc这个参数 def outer(main_func): # 第二层封装,auth和log函数的参数值被传递到了这里 def wrapper(request,kargs): # 下面代码的判断逻辑不重要,重要的是参数的引用和返回值 before_result = auth(request,kargs) if(before_result != None): return before_result; main_result = main_func(request,kargs) if(main_result != None): return main_result; after_result = log(request,kargs) if(after_result != None): return after_result; return wrapper return outer # 注意了,这里的装饰器函数有参数哦,它的意思是先执行filter函数 # 然后将filter函数的返回值作为装饰器函数的名字返回到这里,所以, # 其实这里,Filter(auth,log) = outer , @Filter(auth,log) = @outer @Filter(auth,log) def f1(name,age): print("%s 正在连接业务部门1数据接口......"%name) # 调用方法 f1("jack",18)
#----------------------------------------------- 运行结果: 认证成功! jack 正在连接业务部门1数据接口...... 日志添加成功
user_status = False #用户登录了就把这个改成True def login(auth_type): #把要执行的模块从这里传进来 def auth(func): def inner(*args,**kwargs):#再定义一层函数 if auth_type == "qq": _username = "alex" #假装这是DB里存的用户信息 _password = "123" #假装这是DB里存的用户信息 global user_status if user_status == False: username = input("user:") password = input("pasword:") if username == _username and password == _password: print("welcome login....") user_status = True else: print("wrong username or password!") if user_status == True: return func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能 else: print("only support qq ") return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数 return auth def home(): print("---首页----") @login('qq') def america(): #login() #执行前加上验证 print("----欧美专区----") def japan(): print("----日韩专区----") @login('weibo') def henan(style): ''' :param style: 喜欢看什么类型的,就传进来 :return: ''' #login() #执行前加上验证 print("----河南专区----") home() # america = login(america) #你在这里相当于把america这个函数替换了 #henan = login(henan) # #那用户调用时依然写 america() henan("3p")
---首页---- user:alex pasword:123 welcome login.... ----欧美专区---- only support qq