python装饰器

python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。

一般而言,我们要想拓展原来函数代码,最直接的办法就是侵入代码里面修改,但是最简单的方式并不是最安全最合适的方式,根据扩展开放修改封闭的原则,修改原函数代码是不可取的.比如下面的有一个案例:

A公司有一个核心接口部门M提供核心业务接口,有三个业务部门(N,W,Z)需要调用核心业务接口,在正常运行了一年后,公司规范接口调用需要验证用户权限进行接口调用,现在需要实现这个扩展功能如何在花费最小成本完成?

样例代码如下:

############### 核心接口部门 ###############

def f1():
    print('f1')

def f2():
    print('f2')

def f3():
    print('f3')

def f4():
    print('f4')


############### 业务部门N 调用核心接口提供的功能 ###############

f1()
f2()
f3()
f4()

############### 业务部门W 调用核心接口提供的功能 ###############

f1()
f2()
f3()
f4()

############### 业务部门Z 调用核心接口提供的功能 ###############

f1()
f2()
f3()
f4()

.核心接口部门重构原函数,添加验证代码

############### 核心接口部门 ###############
def verify():
	print('验证代码')

def f1():
   verify()
    print('f1')

def f2():
    verify()
    print('f2')

def f3():
    verify()
    print('f3')

def f4():
   verify()
    print('f4')

分析:违反了开放封闭原则!对扩展是开放的,对修改封闭。对于核心的功能写好之后是不应许进入到功能里面去修改的。如果有1000个接口,你就得改一千次,虽然对于调用者无感,但核心接口部门成本很高。

核心接口部门扩展验证接口,业务部门调用时验证

############### 核心接口部门 ###############
def verify():
	print('验证代码')
	
def f1():
    print('f1')

def f2():
    print('f2')

def f3():
    print('f3')

def f4():
    print('f4')


############### 业务部门N 调用核心接口提供的功能 ###############
if(verify()){
f1()
f2()
f3()
f4()
} else {
	print('未通过验证')
}

############### 业务部门W 调用核心接口提供的功能 ###############
if(verify()){
f1()
f2()
f3()
f4()
} else {
	print('未通过验证')
}


############### 业务部门Z 调用核心接口提供的功能 ###############
if(verify()){
f1()
f2()
f3()
f4()
} else {
	print('未通过验证')
}

分析: 上述代码满足开放封闭原则。核心接口部门也是只要扩展一个验证功能即可,但业务调用部门需要进行验证功能调用,这不利于调用者使用。

核心接口装饰器进行验证,业务部门无感

############### 核心接口部门 ###############

def verify(func):
    def inner():
        # 验证1
        # 验证2
        # 验证3
        return func()
    return inner

@verify
def f1():
    print('f1')
@verify
def f2():
    print('f2')
@verify
def f3():
    print('f3')
@verify
def f4():
    print('f4')

分析:

上述装饰器解决验证问题,只要核心接口部门进行操作,并且满足开放封闭原则。下面以f1为例,
执行verify函数,并将 @verify 下面的 函数 作为verify函数的参数,即:@verify 等价于verify(f1)
所以,内部就会去执行:
def inner:
    #验证
    return f1()   # func是参数,此时 func 等于 f1
return inner     # 返回的 inner,inner代表的是函数,非执行函数
	其实就是将原来的 f1 函数塞进另外一个函数中
	将执行完的 verify 函数返回值赋值给@verify下面的函数的函数名
	verify函数的返回值是:
	def inner:
    #验证
    return 原来f1()  # 此处的 f1 表示原来的f1函数
			然后,将此返回值再重新赋值给 f1,即:
			新f1 = def inner:
						#验证
						return 原来f1() 
	所以,以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,
	在 新f1 函数内部先执行验证,再执行原来的f1函数,然后将 原来f1 函数的返回值 返回给了业务调用者。
	如此一来, 即执行了验证的功能,又执行了原来f1函数的内容,并将原f1函数返回值 返回给业务调用着。

扩展

上面我们写的是没有带参数的,我们如何写带参数的呢?

带一个参数

def verify(func):
    def inner(arg1):
        # 验证1
        # 验证2
        # 验证3
        return func(arg1)
    return inner
@verify
def f1(arg1):
	print('f1')

备注:如果你要指定参数个数,就添加指定个数参数到里面即可。如下:

带两个参数

def verify(func):
    def inner(arg1,arg2):
        # 验证1
        # 验证2
        # 验证3
        return func(arg1,arg2)
    return inner
		
@verify
def f1(arg1,arg2):
	print('f1')

带N个参数

def verify(func):
    def inner(*args,**kwargs):
        # 验证1
        # 验证2
        # 验证3
        return func(*args,**kwargs)
    return inner
		
@verify
def f1(arg1,arg2,arg3,arg4,arg5):
	print('f1')

一个函数可以有多个装饰器

def w1(func):
    def inner(*args,**kwargs):
        # 验证1
        # 验证2
        # 验证3
        return func(*args,**kwargs)
    return inner
 
def w2(func):
    def inner(*args,**kwargs):
        # 验证1
        # 验证2
        # 验证3
        return func(*args,**kwargs)
    return inner
 
 
@w1
@w2
def f1(arg1,arg2,arg3):
    print 'f1'