装饰器

据说装饰器采用的是一种切面的思想。即在不改动源码的情况下从切面为函数增加功能。

def myl():
	print('this is myl')

这是一个函数,如果我想实现在运行函数之前打印start 之后打印end 要怎么办呢

def myl():
	print('start')
	print('this is myl')
	print('end')
---------------
def do1():
	print('start')
def do2():
	print('end')
	
def myl():
	do1()
	print('this is myl')
	do2()

采用装饰器的方式:
一、最简单的装饰器

def de(func):
    def w():
        print('w')
        return func()
    return w

@de
def myl():
    print('im is x')

myl() 
######
w
im is x
######
myl()这个过程:
1、myl
调用myl后先将myl函数传入装饰器de,并且调用了装饰器函数,并返回了装饰器的内部函数
此时的 myl 已经不是原来的myl了,相当于调用了
de(myl)
print(myl)					# <function de.<locals>.w at 0x109f74620>		可见已经是w函数了
print(type(myl))			# <class 'function'>
print(myl.__name__)			#w
2、myl()
那调用myl()  就相当于调用de(myl)()  即w() ps: w为内部方法,在外部不能调用,这里只是比较
3、w函数被调用了,则执行w中的代码
作为一个装饰器,w除了执行自己的代码外还必须调用传进来的参数,也就是被装饰的函数。也可以不返回函数调用,在内部直接调用,都会一样的。
当然也可以不调用,但这将失去装饰器的意义。

那要实现刚才的功能可以这样写:

def de(func):
	def w():
		print('start')
		func()
		print('end')
@de
def myl():
	print('this is myl')
myl()

为了证明上面的第一点:

def de(f):
    def w():
        print('w')
        return f
    return w()	#将这里改成直接调用
@de
def myl():
    print('im is myl1')
    return 'xxx'

print(myl)
######
w
im is myl1
xxx
######

1的改变可以用functiontools中的装饰器wraps优化

def de(f):
    from functools import wraps
    @wraps(f)
    def w():
        print('w')
        return f()

    return w

@de
def myl():
    print('im is myl1')
    return 'xxx'
    
print(myl)
#######
<function myl at 0x10667a620>  看又变回来了,但是没有影响装饰器的使用。
#######

二、我的函数需要传入参数,并且使用装饰器

def de(func):
	def w(*args,**kwargs):
		print('this is w')
		return func(*args,**kwargs)
	return w

@de
def myl(x):
	print('this is myl {0}'.format(x))

根据上面简单的装饰器可以知道整个过程就是 myl() ---> de(myl)() -->  w() --->func()
myl('x') ---> de(myl)('x') ---> w('x') --- > func('x')
所以只要在w函数处接收参数就可以了,为了可以接到任意的参数,使用*args 和 **kwargs

三、给装饰器传递参数

具体方案就是在装饰器的外边加如一层函数,让这层函数返回内部函数

def de1(num):
	def de(func):
		def w():
			print('this is w {num}'.format(num = num))
			return func()
		return w
	return de

@de1(100)
def myl(x):
	print('this is myl {0}'.format(x))

个人感觉应该是这样运行的(估计感觉错了)  de1(100)(myl)()  --- return ---> func()

四、用一个类作为装饰器
主要是用到了__call__ 方法。由于__call__ 方法的作用,使本来不可调用的类变成了可以调用的。

class Loo():
    def __init__(self,func):
        self.func = func
    def __call__(self, *args, **kwargs):
        print('this is call {aaa}'.format(aaa = self.func.__name__))
        return self.func(*args, **kwargs)
@Loo
def myl(x):
    print('this is myl %s'%(x))

myl(100)
########
this is call myl
this is myl 100
########
如果不传参__call__ 方法可以不需要*args 和 **kwargs

五、用一个类作为装饰器并且传参

class Loo1():
    def __init__(self,x):
        self.x = x
    def __call__(self, func):
        def w(y):
            print('this is w {aaa}-->{bbb}'.format(aaa = func.__name__,bbb = self.x))
            return func(y)
        return w

@Loo1(100)
def myl2(y):
    print('this is myl2 %s'%(y))

a = myl2('x')
########
this is w myl2-->100
this is myl2 x
########
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值