python函数带装饰器_Python函数——装饰器

前言

给下面的函数加上运行时间

deffib(n):

a, b= 0, 1

for i inrange(n):print(b)

a, b= b, a+breturnb

a= fib(50)

修改一:改动函数

importtimedeffib(n):

start=time.time()

a, b= 0, 1

for i inrange(n):print(b)

a, b= b, a+bprint(time.time() -start)returnb

a= fib(50)

修改二:不改动函数

deffib(n):

a, b= 0, 1

for i inrange(n):print(b)

a, b= b, a+breturnbimporttimedefwrapper(func):def inner(*args, **kwargs):

start=time.time()

a= func(*args, **kwargs)print(time.time() -start)returnareturn inner #返回函数名

fib=wrapper(fib)

fib(50)

忙活了这么半天,终于初具规模了!现在已经基本上完美了,唯一碍眼的那句话就是还要在做一次赋值调用。。。

装饰器

装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展

装饰器的本质:就是一个闭包函数

满足开放封闭原则

1.对扩展是开放的

2.对修改是封闭的

通过使用装饰器语法糖来解决这个问题!

importtimedefwrapper(func):def inner(*args, **kwargs):

start=time.time()

a= func(*args, **kwargs)print(time.time() -start)returnareturn inner #返回函数名

@wrapper#fib = wrapper(fib)

deffib(n):

a, b= 0, 1

for i inrange(n):print(b)

a, b= b, a+breturnb

fib(100)

上面的装饰器已经非常完美了,但是正常我们情况下查看函数的一些信息的方法在此处都会失效

importtimedefwrapper(func):def inner(*args, **kwargs):

start=time.time()

a= func(*args, **kwargs)print(time.time() -start)returnareturn inner #返回函数名

@wrapper#fib = wrapper(fib)

deffib(n):

a, b= 0, 1

for i inrange(n):print(b)

a, b= b, a+breturnb

fib(100)print(fib.__doc__)print(fib.__name__) #返回 inner

# 为了不让他们失效,我们还要在装饰器上加上一点来完善它:importtimefrom functools importwrapsdefwrapper(func):

@wraps(func)#加在最内层函数正上方

def inner(*args, **kwargs):

start=time.time()

a= func(*args, **kwargs)print(time.time() -start)returnareturn inner #返回函数名

@wrapper#fib = wrapper(fib)

deffib(n):

a, b= 0, 1

for i inrange(n):print(b)

a, b= b, a+breturnb

fib(100)print(fib.__doc__)print(fib.__name__) #返回 fib

带参数的装饰器

带参数的装饰器:就是给装饰器传参

用处:就是当加了很多装饰器的时候,现在忽然又不想加装饰器了,想把装饰器给去掉了,但是那么多的代码,一个一个的去闲的麻烦,

那么,我们可以利用带参数的装饰器去装饰它,这就他就像一个开关一样,要的时候就调用了,不用的时候就去掉了。给装饰器里面传个参数,

那么那个语法糖也要带个括号。在语法糖的括号内传参。在这里,我们可以用三层嵌套,弄一个标识 为去标识。如下面的代码示例

importtimefrom functools importwraps

flag=Falsedefouter(flag):defwrapper(func):

@wraps(func)#加在最内层函数正上方

def inner(*args, **kwargs):

start=time.time()ifflag:print('执行fib')

a= func(*args, **kwargs)else:print('不执行fib')

a= ''

print(time.time() -start)returnareturn inner #返回函数名

returnwrapper"""带参数的装饰器执行过程

fib = outer(False) (fib)

--分解

fib_decorator = outer(False)

fib = fib_decorator(fib)

--分解

fib_decorator = outer(False)

@fib_decorator

def fib(n)

所以,带参数的outer函数首先返回一个decorator函数,

再让这个decorator函数接收fib并返回新函数:"""@outer(True)deffib(n):

a, b= 0, 1

for i inrange(n):print(b)

a, b= b, a+breturnb

fib(100)print(fib.__doc__)print(fib.__name__) #返回 fib

多个装饰器叠加使用

defdecorator_a(func):print('Get in decorator_a')def inner_a(*args, **kwargs):print('Get in inner_a')return func(*args, **kwargs)returninner_adefdecorator_b(func):print('Get in decorator_b')def inner_b(*args, **kwargs):print('Get in inner_b')return func(*args, **kwargs)returninner_b

@decorator_b

@decorator_adeff(x):print('Get in f')return x * 2

print(f(1))

输出结果分析

"""装饰器执行顺序自下而上,内部函数调用顺序自上而下

所以输出

Get in decorator_a

Get in decorator_b

Get in inner_b

Get in inner_a

Get in f

2

分析

当解释器执行下面这段代码时,实际上按照从下到上的顺序已经依次调用了 decorator_a 和 decorator_b ,

这是会输出对应的 Get in decorator_a 和 Get in decorator_b 。

这时候 f 已经相当于 decorator_b 里的 inner_b 。但因为 f 并没有被调用,

所以 inner_b 并没有调用,依次类推 inner_b 内部的 inner_a 也没有调用,

所以 Get in inner_a 和 Get in inner_b 也不会被输出。

然后最后一行当我们对 f 传入参数1进行调用时, inner_b 被调用了,

它会先打印 Get in inner_b ,然后在 inner_b 内部调用了 inner_a

所以会再打印 Get in inner_a, 然后再 inner_a 内部调用的原来的 f,

并且将结果作为最终的返回。这时候你该知道为什么输出结果会是那样,

以及对装饰器执行顺序实际发生了什么有一定了解了吧。"""

装饰器使用举例

#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 2018/4/4 22:38#@Author : hyang#@Site :#@File : 装饰器练习.py#@Software: PyCharm

"""三:编写装饰器,为函数加上认证的功能,即要求认证成功后才能执行函数

四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),

要求登录成功一次,后续的函数都无需再输入用户名和密码

提示:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式"""user_data={'user': None,'is_authenticated': False

}deflogin_required(func):#用户认证装饰器

def inner(*args, **kwargs):if args[0].get('is_authenticated'):print('User is authenticated')

ret= func(*args, **kwargs)else:

exit("User is not authenticated !!!")returnretreturninnerdefget_acct_info():"""get acct_info from USER.TXT

:return:"""with open(r'USER.TXT', 'r') as f:for line inf:

user_dict=eval(line)

USER_INFO_LI.append(user_dict)defauth_user():"""认证用户

:return:"""count=0while count < 3:

user= input('user >>>').strip()

pwd= input('pwd >>>').strip()#print(USER_INFO_LI)

user_flag =False

pwd_flag=Falsefor item inUSER_INFO_LI:if user == item['name']:

user_flag=Trueifuser_flag:if pwd == item['password']:

pwd_flag=Trueif user_flag andpwd_flag:#用户认证成功

user_data['user'] =user

user_data['is_authenticated'] =Trueprint('account login success')returnuser_dataelifuser_flag:#密码不对

print('pwd is error')else:#用户名不存在

print('user is not exists')

count+= 1

else:print("account [%s] too many login attempts" %user)

exit()

@login_requireddefprint_info(p_data):print(p_data)

@login_requireddefenter_x(p_data):print('enter_x', p_data['user'])

@login_requireddefenter_y(p_data):print('enter_x', p_data['user'])deflogout(p_data):print('logout', p_data['user'])

p_data['is_authenticated'] =Falsedefinteractive(p_data):"""interact with user

:return:"""menu= """------- menu ---------

1. 账户信息(功能已实现)

2. 进入x(功能已实现)

3. 进入y(功能已实现)

4. 退出程序"""

print(menu)

menu_dic={'1': print_info,'2': enter_x,'3': enter_y,'4': logout

}

exit_flag=Falsewhile notexit_flag:

user_option= input(">>:").strip()if user_option inmenu_dic:

menu_dic[user_option](p_data)else:print("Option does not exist!")if __name__ == '__main__':

USER_INFO_LI=[]

get_acct_info()

acc_data=auth_user()

interactive(acc_data)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值