首页 > 代码库 > Python之装饰器

Python之装饰器

Python之装饰器

 

装饰器

先来看一个例子,一个函数f1接收另一个函数f2作为参数,并将该参数f2返回给f2:

def deco(func):    print("before myfunc() called.")    func()    print("after myfunc() called.")    return funcdef myfunc():    print("myfunc() called.")myfunc = deco(myfunc)myfunc()myfunc()

 

可以使用装饰器(Decorator)语法糖来简化代码:

def deco(func):    print("before myfunc() called.")    func()    print("after myfunc() called.")    return func@decodef myfunc():    print("myfunc() called.")myfunc()myfunc()

跟上面的代码完全一样,也就是说在定义一个函数(比如foo)的时候,加上@deco,就等同于:foo = deco(foo)

简单的看上面的代码似乎没什么价值,无非就是在Decorator中接收一个函数作为参数,并返回给作为参数的函数本身。

但如果我们在Decorator中内嵌定义一个新的函数,并将这个新的函数返回给作为参数的函数,那就不一样了,例如:

def deco(func):    def _newfunc():        print("before myfunc() called.")        func()        print("after myfunc() called.")        # 不需要返回func,实际上应返回原函数的返回值    return _newfunc@decodef myfunc():    print("myfunc() called.")    return okmyfunc()

在这里,myfunc()函数永久的失去了,后续调用myfunc(),真正调用的其实是在Decorator中返回的函数。

可见,Decorator实际上就是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问。

Decorator是在函数之上的修饰,这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用。

 


 

装饰带参数的函数

上面的例子Decorator装饰的参数都是无参的,下面来看如何装饰带参数的函数,

def deco(func):    def _newfunc(a, b):        print("before myfunc() called.")        ret = func(a, b)        print("after myfunc() called. result: %s" % ret)        return ret    return _newfunc@decodef myfunc(a, b):    print("myfunc(%s,%s) called." % (a, b))    return a + bmyfunc(1, 2)

 

如果被装饰函数的参数个数不确定呢,即可变参数的情况:

def deco(func):    def _newfunc(*args, **kwargs):        print("before %s called." % func.__name__)        ret = func(*args, **kwargs)        print("after %s called. result: %s" % (func.__name__, ret))        return ret    return _newfunc@decodef myfunc(a, b=8, c=1):    print("myfunc2(%s,%s,%s) called." % (a, b, c))    return a+b+cmyfunc(1)myfunc(1, 4)myfunc(1, 10, 9)

只要在装饰器中的内嵌函数使用可变参数列表(*args、**kwargs)即可。

 


装饰器自身带参数

 

这种情况需要嵌套两层函数:

def deco(arg):    def _deco(func):        def _newfunc():            print("before %s called [%s]." % (func.__name__, arg))            func()            print("after %s called [%s]." % (func.__name__, arg))        return _newfunc    return _deco@deco("mymodule")def myfunc():    print("myfunc() called.")myfunc()

 

如果装饰器的参数是类类型:

class locker:    def __init__(self):        print("locker.__init__() should be not called.")    @staticmethod    def acquire():        print("locker.acquire() called.(这是静态方法)")    @staticmethod    def release():        print("  locker.release() called.(不需要对象实例)")def deco(cls):    ‘‘‘cls 必须实现acquire和release静态方法‘‘‘    def _deco(func):        def __deco():            print("before %s called [%s]." % (func.__name__, cls))            cls.acquire()            try:                return func()            finally:                cls.release()        return __deco    return _deco@deco(locker)def myfunc():    print(" myfunc() called.")myfunc()

 

 


 

同时使用多个装饰器

 

class mylocker:    def __init__(self):        print("mylocker.__init__() called.")    @staticmethod    def acquire():        print("mylocker.acquire() called.")    @staticmethod    def unlock():        print("  mylocker.unlock() called.")class lockerex(mylocker):    @staticmethod    def acquire():        print("lockerex.acquire() called.")    @staticmethod    def unlock():        print("  lockerex.unlock() called.")def lockhelper(cls):    ‘‘‘cls 必须实现acquire和release静态方法‘‘‘    def _deco(func):        def __deco(*args, **kwargs):            print("before %s called." % func.__name__)            cls.acquire()            try:                return func(*args, **kwargs)            finally:                cls.unlock()        return __deco    return _decoclass example:    @lockhelper(mylocker)    def myfunc(self):        print(" myfunc() called.")    @lockhelper(mylocker)    @lockhelper(lockerex)    def myfunc2(self, a, b):        print(" myfunc2() called.")        return a + ba = example()a.myfunc()print(a.myfunc())print(a.myfunc2(1, 2))print(a.myfunc2(3, 4))                      

 

Python之装饰器