Python各式裝飾器

jopen 9年前發布 | 16K 次閱讀 Python Python開發

Python裝飾器,分兩部分,一是裝飾器本身的定義,一是被裝飾器對象的定義。

一、函數式裝飾器:裝飾器本身是一個函數。

1.裝飾函數:被裝飾對象是一個函數

[1]裝飾器無參數:

a.被裝飾對象無參數:

>>> def test(func):
    def _test():
        print 'Call the function %s().'%func.func_name
        return func()
    return _test

>>> @test def say():return 'hello world'

>>> say() Call the function say(). 'hello world' >>></pre>

 b.被裝飾對象有參數:

>>> def test(func):
    def _test(args,**kw):
        print 'Call the function %s().'%func.func_name
        return func(args,**kw)
    return _test

>>> @test def left(Str,Len):     #The parameters of _test can be '(Str,Len)' in this case.     return Str[:Len]

>>> left('hello world',5) Call the function left(). 'hello' >>></pre>

 [2]裝飾器有參數:

a.被裝飾對象無參數:

>>> def test(printResult=False):
    def _test(func):
        def test():
            print 'Call the function %s().'%func.func_name
            if printResult:
                print func()
            else:
                return func()
        return test
    return _test

>>> @test(True) def say():return 'hello world'

>>> say() Call the function say(). hello world >>> @test(False) def say():return 'hello world'

>>> say() Call the function say(). 'hello world' >>> @test() def say():return 'hello world'

>>> say() Call the function say(). 'hello world' >>> @test def say():return 'hello world'

>>> say()

Traceback (most recent call last):   File "<pyshell#224>", line 1, in <module>     say() TypeError: _test() takes exactly 1 argument (0 given) >>></pre>

 由上面這段代碼中的最后兩個例子可知:當裝飾器有參數時,即使你啟用裝飾器的默認參數,不另外傳遞新值進去,也必須有一對括號,否則編譯器會直接將func傳遞給test(),而不是傳遞給_test()

b.被裝飾對象有參數:

>>> def test(printResult=False):
    def _test(func):
        def test(args,**kw):
            print 'Call the function %s().'%func.func_name
            if printResult:
                print func(args,kw)
            else:
                return func(*args,kw)
        return test
    return _test

>>> @test() def left(Str,Len):     #The parameters of __test can be '(Str,Len)' in this case.     return Str[:Len]

>>> left('hello world',5) Call the function left(). 'hello' >>> @test(True) def left(Str,Len):     #The parameters of __test can be '(Str,Len)' in this case.     return Str[:Len]

>>> left('hello world',5) Call the function left(). hello >>></pre>

2.裝飾類:被裝飾的對象是一個類

[1]裝飾器無參數:

a.被裝飾對象無參數:

>>> def test(cls):
    def _test():
        clsName=re.findall('(\w+)',repr(cls))[-1]
        print 'Call %s.__init().'%clsName
        return cls()
    return _test

>>> @test class sy(object):     value=32

     >>> s=sy() Call sy.init(). >>> s <main__.sy object at 0x0000000002C3E390> >>> s.value 32 >>></pre>

 b.被裝飾對象有參數:

>>> def test(cls):
    def _test(args,**kw):
        clsName=re.findall('(\w+)',repr(cls))[-1]
        print 'Call %s.__init().'%clsName
        return cls(args,**kw)
    return _test

>>> @test class sy(object):     def init(self,value):                 #The parameters of _test can be '(value)' in this case.         self.value=value

         >>> s=sy('hello world') Call sy.init(). >>> s <main__.sy object at 0x0000000003AF7748> >>> s.value 'hello world' >>></pre>

[2]裝飾器有參數:

a.被裝飾對象無參數:

>>> def test(printValue=True):
    def _test(cls):
        def test():
            clsName=re.findall('(\w+)',repr(cls))[-1]
            print 'Call %s.init().'%clsName
            obj=cls()
            if printValue:
                print 'value = %r'%obj.value
            return obj
        return __test
    return _test

>>> @test() class sy(object):     def init(self):         self.value=32

         >>> s=sy() Call sy.init(). value = 32 >>> @test(False) class sy(object):     def init__(self):         self.value=32

         >>> s=sy() Call sy.__init(). >>></pre>

 b.被裝飾對象有參數:

>>> def test(printValue=True):
    def _test(cls):
        def test(*args,**kw):
            clsName=re.findall('(\w+)',repr(cls))[-1]
            print 'Call %s.init().'%clsName
            obj=cls(*args,**kw)
            if printValue:
                print 'value = %r'%obj.value
            return obj
        return __test
    return _test

>>> @test() class sy(object):     def init(self,value):         self.value=value

         >>> s=sy('hello world') Call sy.init(). value = 'hello world' >>> @test(False) class sy(object):     def init__(self,value):         self.value=value

         >>> s=sy('hello world') Call sy.init(). >>></pre>

 二、類式裝飾器:裝飾器本身是一個類,借用init()和call__()來實現職能 </p>

1.裝飾函數:被裝飾對象是一個函數

[1]裝飾器無參數:

a.被裝飾對象無參數:

>>> class test(object):
    def init(self,func):
        self._func=func
    def call(self):
        return self._func()

     >>> @test def say():     return 'hello world'

>>> say() 'hello world' >>></pre>

b.被裝飾對象有參數:

>>> class test(object):
    def init(self,func):
        self._func=func
    def call(self,args,**kw):
        return self._func(args,**kw)

     >>> @test def left(Str,Len):     #The parameters of call can be '(self,Str,Len)' in this case.     return Str[:Len]

>>> left('hello world',5) 'hello' >>></pre>

 [2]裝飾器有參數

a.被裝飾對象無參數:

>>> class test(object):
    def init(self,beforeinfo='Call function'):
        self.beforeInfo=beforeinfo
    def call(self,func):
        def _call():
            print self.beforeInfo
            return func()
        return _call

     >>> @test() def say():     return 'hello world'

>>> say() Call function 'hello world' >>></pre>

或者:

>>> class test(object):
    def init(self,beforeinfo='Call function'):
        self.beforeInfo=beforeinfo
    def call(self,func):
        self._func=func
        return self._call
    def _call(self):
        print self.beforeInfo
        return self._func()

     >>> @test() def say():     return 'hello world'

>>> say() Call function 'hello world' >>></pre>

b.被裝飾對象有參數:

>>> class test(object):
    def init(self,beforeinfo='Call function'):
        self.beforeInfo=beforeinfo
    def call(self,func):
        def _call(args,**kw):
            print self.beforeInfo
            return func(args,**kw)
        return _call

     >>> @test() def left(Str,Len):     #The parameters of _call can be '(Str,Len)' in this case.     return Str[:Len]

>>> left('hello world',5) Call function 'hello' >>></pre>

或者:

>>> class test(object):
    def init(self,beforeinfo='Call function'):
        self.beforeInfo=beforeinfo
    def call(self,func):
        self._func=func
        return self._call
    def _call(self,args,**kw):
        print self.beforeInfo
        return self._func(args,**kw)

     >>> @test() def left(Str,Len):     #The parameters of _call can be '(self,Str,Len)' in this case.     return Str[:Len]

>>> left('hello world',5) Call function 'hello' >>></pre>

 2.裝飾類:被裝飾對象是一個類

[1]裝飾器無參數:

a.被裝飾對象無參數:

>>> class test(object):
    def init(self,cls):
        self._cls=cls
    def call(self):
        return self._cls()

     >>> @test class sy(object):     def init(self):         self.value=32

     >>> s=sy() >>> s <main.sy object at 0x0000000003AAFA20> >>> s.value 32 >>></pre>

 b.被裝飾對象有參數:

>>> class test(object):
    def init(self,cls):
        self._cls=cls
    def call(self,args,**kw):
        return self._cls(args,**kw)

     >>> @test class sy(object):     def init(self,value):         #The parameters of call can be '(self,value)' in this case.         self.value=value

         >>> s=sy('hello world') >>> s <main.sy object at 0x0000000003AAFA20> >>> s.value 'hello world' >>></pre>

[2]裝飾器有參數:

a.被裝飾對象無參數:

>>> class test(object):
    def init(self,printValue=False):
        self._printValue=printValue
    def call(self,cls):
        def _call():
            obj=cls()
            if self._printValue:
                print 'value = %r'%obj.value
            return obj
        return _call

     >>> @test(True) class sy(object):     def init(self):         self.value=32

         >>> s=sy() value = 32 >>> s <main.sy object at 0x0000000003AB50B8> >>> s.value 32 >>></pre>

 b.被裝飾對象有參數:

>>> class test(object):
    def init(self,printValue=False):
        self._printValue=printValue
    def call(self,cls):
        def _call(args,**kw):
            obj=cls(args,**kw)
            if self._printValue:
                print 'value = %r'%obj.value
            return obj
        return _call

     >>> @test(True) class sy(object):     def init(self,value):         #The parameters of _call can be '(value)' in this case.         self.value=value

         >>> s=sy('hello world') value = 'hello world' >>> s <main.sy object at 0x0000000003AB5588> >>> s.value 'hello world' >>></pre>

總結:【1】@decorator后面不帶括號時(也即裝飾器無參數時),效果就相當于先定義func或cls,而后執行賦值操作func=decorator(func)或cls=decorator(cls);

          【2】@decorator后面帶括號時(也即裝飾器有參數時),效果就相當于先定義func或cls,而后執行賦值操作 func=decorator(decoratorArgs)(func)或cls=decorator(decoratorArgs)(cls);

          【3】如上將func或cls重新賦值后,此時的func或cls也不再是原來定義時的func或cls,而是一個可執行體,你只需要傳入參數就可調用,func(args)=>返回值或者輸出,cls(args)=>object of cls;

           【4】最后通過賦值返回的執行體是多樣的,可以是閉包,也可以是外部函數;當被裝飾的是一個類時,還可以是類內部方法,函數;

           【5】另外要想真正了解裝飾器,一定要了解func.func_code.co_varnames,func.func_defaults,func.func_argcount,通過它們你可以以func的定義之外,還原func的參數列表,詳見Python多重裝飾器中的最后一個例子中的ArgsType;另外關鍵字參數是因為調用而出現的,而不是因為func的定義,func的定義中的用等號連接的只是有默認值的參數,它們并

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!