一文详解 python中的修饰器 decorater @ 有计时器例子

概念

所谓decorater,就是wrapper
在函数定义时使用一个包装器,使得这个函数在执行的时候外面码 被裹了一层代码 \color{red}{被裹了一层代码} 被裹了一层代码
修饰器在被读取时立即执行,因此修饰器函数的定义得在使用之前,编译器来不及找


def 包装器(传入的需要修饰函数):
	def 包装器要做什么(*args):
		预处理函数()
		包装器输出 = 传入的需要修饰函数(*args)
		善后函数()
		return 包装器输出
	return 包装器要做什么
		

@包装器
def 被包装函数(传入参数a):
	return 传出参数

作用

计时器

#定义一个函数用来统计传入函数的运行时间
import time
def timmer(func):    #传入的参数是一个函数
    def deco(*args, **kwargs): #本应传入运行函数的各种参数
        print('\n函数:{_funcname_}开始运行:'.format(_funcname_=func.__name__))
        start_time = time.time()#调用代运行的函数,并将各种原本的参数传入
        res = func(*args, **kwargs)
        end_time = time.time()
        print('函数:{_funcname_}运行了 {_time_}秒'
              .format(_funcname_=func.__name__, _time_=(end_time - start_time)))
        return res#返回值为函数
    return deco

初始版本

等价于 t h i s D e c o r a t e d = d e c o r a t e r ( t h i s D e c o r a t e d ) \color {green}{thisDecorated= decorater(thisDecorated) } thisDecorated=decorater(thisDecorated)
因此装饰器一定得有个输入
还得有个输出

def decorater(func):
    print('传入装饰器%s'%func)
    return func

@decorater
def thisDecorater():
    print("被装饰函数调用")

print('decorater地址%s'%decorater)
print('thisDecorater地址 %s'%thisDecorater)

print("**********************************")
thisDecorater()
print("thisDecorater : ",thisDecorater.__name__)
print(thisDecorater)
print("**********************************")
thisDecorated = decorater(thisDecorater)
thisDecorated()
print(thisDecorated)
print("thisDecorated : ",thisDecorated.__name__)

输出

传入装饰器<function thisDecorater at 0x000001BDF3CB4F70>
decorater地址<function decorater at 0x000001BDF3BE1F70>
thisDecorater地址 <function thisDecorater at 0x000001BDF3CB4F70>**********************************
被装饰函数调用
thisDecorater : thisDecorater<function thisDecorater at 0x000001BDF3CB4F70>**********************************
传入装饰器<function thisDecorater at 0x000001BDF3CB4F70>
被装饰函数调用
<function thisDecorater at 0x000001BDF3CB4F70>
thisDecorated : thisDecorater

奇怪的是,这里的被修饰函数名称和地址竟然还是原来的

被包装函数带传入参数

使用 ∗ a r g s * args args ,这是一个元组truple
注意它只能作为可迭代对象的参数传入迭代器。
关于迭代对象,可以使用以下代码查看。

from collections import abc
isinstance(a,abc.Iterable)

如果没有就得自己实现一下__iter__ 方法。或者,你也可以实现__getitem__方法,在调用iter()迭代器时,编译器也会利用它创建一个__iter__。

被包装函数带传出参数

由于被包装函数原有的return用在了包装器里面,而此时调用返回的return是由包装函数来定的,因此需要 手动把被包装函数返回值给到包装函数return的地方

def dec(*args):
	print(name)
	print('pre action')
	result = func(*args)
	print('post action')
	return result

修饰器带传入参数

三层结构
使得修饰器传入参数多样化,便于多态。比如计算时间,传入参数“按秒”、按“GT+8”等方法。

def wap(name):
    def decorator1(func):
        def dec(*args):
            print(name)
            print('pre action')
            result = func(*args)
            print('post action')
            return result
        return dec
    return decorator1
 
@wap('f1')
def test_f1(name):
    print (name)
    return None
 
test_f1('name1') 
print(test_f1.__name__)

输出

f1
pre action
被修饰函数 name1
post action
dec

注意这里的函数就被替换了,这才是正常现象
内部逻辑为: test_f1 = wap(‘f1’)(test_f1)

这里wap(‘f1’)返回是decorator1函数对象,这样的话,wap(‘f1’)(test_f1)其实就是decorator1(test_f1),这样就和上面的一样了。只不过这里传递了一个参数’f1’进入decorator内部,使得我们可以操作这个参数。

reference

http://thecodeship.com/patterns/guide-to-python-function-decorators/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值