python装饰器 随笔

1 装饰器

装饰器的基础是闭包,同时装饰器是闭包的一种应用,总的来说,装饰器就是对原函数的一种功能扩展

1.1单个装饰器

我们先来认识下装饰器的语法

def decorator(func):
	def funcdeco():
		print(f"{func.__name__} is running")#修饰部分
		func()#原有函数功能实现
	return funcdeco

@decorator
def fun():
	pass
fun1=fun#这里得到的是funcdeco函数
fun1()#开始装饰fun并执行fun函数

执行结果:

fun is running

1.2 传参的装饰器

1.2.1 函数带参数

在上面的例子中,我们发现所执行的函数是不带任何参数的,也就是无参无返,若我们要执行一个有参有返的函数的话,我们只需要在fundeco()中接受参数

	def funcdeco(*args,**kawrgs):#接受参数
		print(f"{func.__name__} is running")
		func(*args,**kawrgs)#原有函数传入参数
	return funcdeco

1.2.2 修饰带参数

现在我们要给装饰函数加入一些装饰信息,比如说进程ID,来修饰这个函数的进程执行中的ID

@decorator("652156")#进程id为652156
def fun():
	pass

这个时候我们就有必要对decorator函数进行相应的修改,那就是再增加一层闭包

def decorator(pid):
    def decoratorSub(func):
        def funcdeco(*args):
            print("pid: %s function name:%s"%(pid,func.__name__))
            return func(*args)
        return funcdeco
    return decoratorSub

@decorator("652156")#进程id为652156
def fun(*args):
	pass

fun()

执行结果:

pid: 652156 function name:fun

1.3 多个装饰器

如果有多个装饰修饰器的话,那么被装饰的顺序是怎样的,下面给出一个例子

def log3(func):
    print("log3")
    def wrapper3(*args, **kw):
        print('log3 call %s():' % func.__name__)
        func(*args, **kw)
    return wrapper3

def log2(func):
    print("log2")
    def wrapper2(*args, **kw):
        print('log2 call %s():' % func.__name__)
        func(*args, **kw)
    return wrapper2


def log1(func):
    print("log1")
    def wrapper1(*args, **kw):
        print('log1 call %s():' % func.__name__)
        func(*args, **kw)
    return wrapper1
    
@log1
@log2
@log3
def now():
    print('2015-3-25')

now()

执行结果:

log3
log2
log1
log1 call wrapper2():
log2 call wrapper3():
log3 call now():
2015-3-25

如果你对这样的结果感到不解的话,让我们猜想一下多种装饰器的函数究竟是怎样工作的,下面给出一个函数now2(为了区分now),并且给出一段代码执行来猜测多个装饰器是如何工作的

def now2():
    print("2015-3-25")
f1=log3(now2)
f2=log2(f1)
f3=log1(f2)
f3()

结果打印:

log3
log2
log1
log1 call wrapper2():
log2 call wrapper3():
log3 call now2():
2015-3-25

很明显这里的结果和now的结果是一样的,也就是说我们的猜想得到了证实,将f3展开
f 3 = l o g 1 ( l o g 2 ( l o g 3 ( n o w 2 ) ) ) f_3=log_1(log_2(log_3(now_2))) f3=log1(log2(log3(now2)))
如果我们不执行f3而是将f3打印出来

<function __main__.log1.<locals>.wrapper1(*args, **kw)>

也就是说
l o g 1 ( l o g 2 ( l o g 3 ( n o w 2 ) ) ) − > w r a p p e r 1 − > l o g 1 l o g 2 ( l o g 3 ( n o w 2 ) ) − > w r a p p e r 2 − > l o g 2 l o g 3 ( n o w 2 ) − > w r a p p e r 3 − > l o g 3 log_1(log_2(log_3(now_2)))->wrapper1->log_1\\ log_2(log_3(now_2))->wrapper2->log_2\\ log_3(now_2)->wrapper3->log_3\\ log1(log2(log3(now2)))>wrapper1>log1log2(log3(now2))>wrapper2>log2log3(now2)>wrapper3>log3
在下面几行中我们发现log1,log2,log3是按照顺序出现的,但是后面的信息好像不是很规则

log1 call wrapper2():
log2 call wrapper3():
log3 call now2():

这其实不难理解,刚才我们是像洋葱一样一层一层往外拨开,现在我们从洋葱内部一步一步扩展

log_3(now_2)#表示log_3修饰的now_2函数
所以会打印log3 call now2():
并且会执行now2()函数

这一步执行完后就会返回一个wrapper3给log_2(log_3(now_2))也就是
log_2(wrapper3)#表示log_2修饰wrapper3
所以会打印log2 call wrapper3()
并且会执行wrapper3()函数

并且返回一个wrapper2给log_1(log_2(log_3(now_2)))也就是
log1(wrapper2)#表示log_2修饰wrapper3
所以会打印log1 call wrapper2():
并且会执行wrapper2()函数

别忘了当我们使用f3()的时候已经调用了wrapper1()函数
现在让我们回到洋葱的外面
因此多个装饰器的运行过程如下
wrapper1(wrapper2)->wrapper2(wrapper3)->wrapper3(now2)->now2()

到了这里,我想你对装饰器有了一定的了解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值