装饰器的类型和常用装饰器

什么是装饰器

装饰器顾名思义就是用来装饰对象的一种特殊语法,装饰的对象会获取装饰器提供的额外功能装饰器的本质是一个函数,用来装饰类或函数,通过这种方法置入通用功能代码降低程序的复杂度,并且可以通过给被装饰对象添加不同的装饰器来增加不同的额外功能。装饰器可以一般用来做权限验证,比如时间范围检查,或者做登录权限验证。

装饰器的使用

因为装饰器的本质是函数,所以一个函数或者类添加了装饰器,就相当于将被装饰的对象作为参数传进装饰器中,如果装饰器是有参数的,那么就相当于先执行装饰器函数,执行结果作为真正的装饰器去装饰对象。

1. 不带参数的单个装饰器
@deco
def func(): pass
等价于:deco(func)

2. 带参数的单个装饰器
@deco(arg)
def func(): pass  
等价于: deco(arg)(func)  
# 这里先声明deco(arg)返回一个对象,该对象才是以func为参数的装饰器

3. 多个装饰器,并且带参数
@deco1(arg)
@deco2
def func(): pass
等价于:deco1(arg)(deco2(func))  
# 这里先声明deco1(arg),再deco2(func),然后前者作为后者的参数传递,这里涉及到多个装饰器的执行顺序问题,下面再讲。

functools.wraps

上面了解到装饰器将被装饰的函数作为参数,那么在装饰器中返回的函数名其实已经变成了装饰器外层函数返回函数名。

from functools import wraps

def deco(func):
	def inner():
		print('func name:', func.__name__, 1)
		return func()
	return inner

@deco
def func():
	print('func name:', func.__name__, 2)

func()
# 输出
func name: func, 1
func name: inner, 2

如果想被装饰函数保持原来的属性,可以使用functools.wraps装饰器

from functools import wraps

def deco(func):
     @wraps(func)
     def inner():
         print('func name:', func.__name__, 1)
         return func()
     return inner

@deco
def func():
    print('func name:', func.__name__, 2)

func()
# 输出
func name: func 1
func name: func 2

多个装饰器的执行顺序

def deco1(func):
    print(1111)
    def inner():
        print(2222)
        return func()
    return inner

def deco2(func):
    print(3333)
    def inner():
        print(4444)
        return func()
    return inner

@deco1
@deco2
def func():
    print(5555)

func()
# 输出
3333
1111
2222
4444
5555

从上面的代码中可以看到,代码所走的顺序:
1:内层装饰器的外层函数
2:外层装饰器的外层函数
3:外层装饰器的内层函数
4:内层装饰器的内层函数
5:回到被装饰函数
原因:多个装饰器情况会先执行外层装饰器,再执行内层装饰器
我们知道装饰器本质上是一个函数,函数在python解释器解析时声明,从上面我们可以知道这相当于 func = deco1(deco2(func)) ,因此在声明函数(函数声明从上往下)时先声明deco1,在声明deco2,然后函数声明完毕,我们上面的func实际上已经变成被装饰器装饰后返回的新对象。执行func(),先执行外层装饰器,再执行内部装饰器,最后回到被装饰函数,因此就造成如上的打印顺序。

常用装饰器

1. 输出运行时间

def timeit(fun):
    def wrapper(*args, **kwargs):
        star_time=time.time()	# 记录函数开始运行的时间
        res = fun(*args, **kwargs)
        end_time=time.time()	# 记录函数运行完后的时间
        print('运行时间:%.6f' %(end_time-star_time))	# 打印出函数运行的时间
        return res
    return wrapper

2. 检查是否在允许的时间范围内

 def check_time(func):
     def wrapper(*args, **kwargs):
          if is_work_time():
              return func(*args, **kwargs)
          return ''
      return wrapper

# 判断是否为工作日,工作日返回1,非工作日返回0
def is_work_time():
    day_week = datetime.datetime.now().weekday()
    begin = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + '09:00:00'
    end = datetime.datetime.now().strftime("%Y-%m-%d") + ' ' + '18:00:00'
    begin_seconds = time.time() - time.mktime(time.strptime(begin, '%Y-%m-%d %H:%M:%S'))
    end_seconds = time.time() - time.mktime(time.strptime(end, '%Y-%m-%d %H:%M:%S'))
    if int(day_week) in range(5) and int(begin_seconds) > 0 and int(end_seconds) < 0:
        return 1
    else:
        return 0
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值