装饰器整理

什么是装饰器

装饰器(Decorators) 可能是Python中最难掌握的概念之一了,在解释是什么是装饰器之前,我们需要知道,python是一门面向对象的语言,python基本思想就是一切皆对象,数据类型是对象,类是对象,类实例也是对象,所以对于装饰器而言,重要的是函数也是对象!既然对象,就可以进行赋值操作

def func():
    print('执行功能ing')

if __name__ == '__main__':
    func1 = func
    func1()

原来我们定义的函数名是func,但是我们把函数赋值给func1后,也可以通过func1()来调用func函数。
我们也可以把函数当作参数传递给其他函数:

def do_something():
	print('正在完成功能')
def func(f):
	f()
if __name__ == '__main__':
	func(do_somethong)

因为python中函数既可以赋值给其他变量,也可以当作参数传递给其他函数,但是函数也不同于其他变量,函数也有自己的特性,函数内部可以定义函数,可以有返回值:

def func():
	def inner_func():
		print('我是内部函数')
	return inner_fun
if __name__ == '__main__':
	func1 = func()
	func1()

综上所述,发现有几个特性:
1.可以赋值给其他变量;
2.可以作为参数传递给其他函数;
3.可以在内部定义一个函数;
4.可以当作返回值;

从本质上说,装饰器就是一个函数,它也具有我们上面说的几个特性,并且充分利用了这几个特性。装饰器接受一个普通函数作为参数,并在内部定义了一个函数,在这个内部函数中实现了一些功能,并调用传递进来的函数,最后将内部函数作为返回值返回。如果一个函数把这个步骤全走了一遍,我们就可以认为,这个函数是一个装饰器函数,或者说是装饰器

def func(f):
	def inner_func():
		print('{}函数开始运行'.format(f.__name__))
		f()
		print('{}函数运行结束'.format(f.__name__))
	return inner_func

def do_something():
	print('正在完成的功能')

if __name__ == '__main__':
	do_something = func(do_something)
	do_something()

在上面代码中,我们将do_something方法作为参数传递给func函数,在func内部我们定义了一个inner_func方法,并在这个方法中添加了函数开始执行和结束执行的提示,在func方法最后,我们将inner__func作为参数返回,然后我们将func函数的返回值赋值给了do_something,所以,最后一次调用的do_something函数已经不再是最初的do_something函数,而是func函数内部定义的inner__func函数,所以最后执行do_something函数时,会有函数开始执行和结束执行的提示功能,而后面在调用do_something函数时,因为返回值是inner_func单纯的函数名,所以执行do_something时,需要加括号,do_something()。
一般装饰器大多是与’@‘符号结合起来用,@符号所实行的功能就是do_something = func(do_something)这行代码的功能。

def func(f):
	def inner_func():
		print('{}函数开始执行'.format(f.__name__))
		f()
		print('{}函数结束运行'.format(f.__name__))
	return inner_func

@func
def do_something():
	print('正在执行功能')

if __name__ == '__main__':
	do_something()

输出结果:
do_something函数开始执行
正在执行功能
do_something函数结束运行

为什么要用装饰器

1.可以在不对被装饰函数做任何修改的前提下,给被装饰函数附加一些功能。使用@func对do_something函数进行装饰时,我们没有对do_someting函数代码做任何改动,但是被装饰后的do_something函数却多了其他功能。
2.不改变被装饰函数的调用方式。在被装饰前,我们通过do_something()调用这个函数,被装饰后,还是通过do_something调用这个函数。
3.代码更加精简。如果有多个函数需要添加开始运行和结束运行的提示功能,我们只需要在函数前面添加@func就可以了。

import time
def timmer(f):
	def inner_func():
		start_ = time.time()
		f()
		end_ = time.time()
		print('{}函数运行消耗时间为:{}'.format(f.__name__,end_-start_))
	return inner_func

@timmer
def do_something():
	print('函数正在执行')
	time.sleep(1)
if __name__ == '__main__':
	do_something()
	

深入理解装饰器

被装饰的函数带返回值

针对有返回值的函数,装饰器该怎么写呢?

def func(f):
	def inner_func():
		print('{}函数开始执行'.format(f.__name__))
		ret = f()
		print('{}函数结束运行'.format(f.__name__))
		return ret #这里返回值
	return inner_func

@func
def do_something():
	print('正在完成功能')
	return'我是返回值'

if __name__ == '__main__':
	ret = do_something()
	print(ret)

我们知道,被装饰后的do_something函数其实不再时最初的do_something函数,而是装饰器内部定义的inner_func函数,所以,被装饰的函数的返回值只需要通过装饰器内部定义的inner_func函数返回值返回即可。

被装饰函数带参数

对于装饰器,我们要深刻理解一件事:被装饰后的do_something函数已经不再是原来的do_something函数,而是装饰器内部的inner_func函数。 如果被装饰的函数有参数a,我们还是通过do_something(a)的方式传递输出,不过我们调用do_someting实质调用的inner_func函数,那么在定义装饰器时,定义的inner_func函数时也需要接受参数。

def func(f):
	def inner_func(a):
		print('{}函数开始运行'.format(f.__name__))
		ret = f(a)
		print('{}函数结束运行'.format(f.__name__))
		return ret
	return inner_func

@func		
def do_something(a):
 	print('你好',a)
 	return '我是返回值'
 	
if __name__ == '__main__':
	ret = do_something('姚明')
	print(ret)
 	

如果不知道有多少个位置参数,多少个关键字参数时,我们可以用arg和*kwargs

"""
    在不改变原有功能(fun01 fun02)调用与定义情况下,
    为其增加新功能(打印函数执行时间).
"""

import time

def print_execute_time(func):
    def wrapper(*args, **kwargs):
        # 记录调用前的时间
        start_time = time.time()
        result = func(*args, **kwargs)
        # 记录调用后的时间
        execute_time = time.time() - start_time
        print("执行时间是:", execute_time)
        return result

    return wrapper


@print_execute_time
def fun01():
    time.sleep(2)  # 睡眠2秒,用于模拟程序执行的过程
    print("fun01执行完毕喽")


@print_execute_time
def fun02(a):
    time.sleep(1)
    print("fun02执行完毕喽,参数是:", a)

if __name__ == '__main__':
	fun01()
	fun02(100)

装饰器本身带参数

我们上面所写的装饰器都没有参数,或者说只有一个自带的参数,也就是被装饰函数函数名。其实,装饰器也是可以有其他参数的,这样装饰器更加灵活。

def language(lang='中文'):#这里带参数
	def func(f):#嵌套一层
		def inner_func(*args,**kwargs):
			if lang=='中文':
				print('{}函数开始运行'.format(f.__name__))
			else:
				print('The function of {} starts running'.format(f.__name__))
			ret = f(*args,**kwargs)
			if lang=='中文':
				print('{}函数结束运行'.format(f.__name__))
			else:
				print('The function of {} ends running'.format(f.__name__))
			return ret
		return inner_func
	return func

@language('中文')
def do_something(a):
	print('你好',a)
	
@language('English')
def do_something_2(a):
    print('你好,{}!'.format(a))
    
if __name__ == '__main__':
    do_something('姚明')
    print('-------------------------')
    do_something_2('姚明')

装饰器也是可以多层嵌套使用的,也就是说,一个函数可以被多个装饰器所装饰,执行顺序是从下到上的优先顺序加载装饰

import time

print(1)
def func(f):
    print(2)
    def inner_func(*name1, **name2):
        print('{}函数开始运行……'.format(f.__name__))
        f(*name1, **name2)
        print('{}函数结束运行……'.format(f.__name__))
    print(3)
    return inner_func

print(4)
def timmer(f):
    print(5)
    def inner_timmer(*args, **kwargs):
        print('开始计时……')
        start_time = time.time()
        f(*args, **kwargs)
        end_time = time.time()
        print('开始结束……')
        time_cost = end_time - start_time
        print('{}函数运行时长为:{}秒'.format(f.__name__, time_cost))
    print(6)
    return inner_timmer

print(7)
@func
@timmer
def do_something(name):
    time.sleep(1)
    print('你好,{}!'.format(name))

print(8)
def do_something_2(name):
    time.sleep(1)
    print('你好,{}!'.format(name))


if __name__ == '__main__':
    print(9)
    do_something(name='姚明')
    print('-------------------------')
    func(timmer(do_something_2))(name='姚明')  # 执行效果与上面使用了@符号的do_something一样
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值