1. 程式人生 > >python 學習彙總23:裝飾器 decorator( tcy)

python 學習彙總23:裝飾器 decorator( tcy)

裝飾器 decorator  2018 / 8 / 11
    
==================================================================
1.1.定義:
    # 在程式碼執行期間動態增加功能的方式,稱之為裝飾器Decorator
    # decorator是一個返回函式的高階函式;函式賦值給變數,通過變數呼叫該函式。
    
==================================================================
1.2.例
    
# 例項1:定義decorator無引數:
import functools
    
def log(func):
    print('裝飾器開始...')
    
    @functools.wraps(func)
    def inner(*args, **kwargs):
        print('ready call add...')
        return func(*args, **kwargs)  # 無返回值可省略return
    
    return inner
    
@log  # 相當於add=log(add)
def add(a, b):
    print('runing add...' )
    return a + b
    
#呼叫
print('a+b= %s' % add(2, 4))
    
#裝飾器開始...
#ready call add...
#runing add...
#a+b= 6
    
# 例項2:裝飾器輸入引數
import functools
    
def log(name='Tom'):
    print('裝飾器開始...')
    
    def inner_log(func):
        print('inner_log start...')
    
        def inner(*args, **kwargs):
            inner.__name__ = func.__name__
            print('%s ready call %s...' % (name,inner.__name__))
            return func(*args, **kwargs)
    
        return inner
    
    return inner_log
    

@log('John')  # add = log('John')(add)
def add(a, b):
    print('runing add...')
    return a + b
    
#呼叫:
print('a+b= %s' % add(2, 4))
    
# 裝飾器開始...
# inner_log start...
# John ready call add...
# runing add...
# a+b= 6
    
# 例項3:協程
def coroutine(func):
    def start(*args, **kwargs):
        g = func(*args, **kwargs)
        next(g)
        return g
    
    return start
    
@coroutine
def receiver():
    print('ready to receive')
    while True:
        n = (yield)
        print('got %s' % n)
    
#呼叫:
r = receiver()
r.send('hello world')
    
#ready to receive
# got hello world
    
===================================================================
2.類裝飾器
    
    #裝飾器函式是一個介面約束,必須接受callable物件作為引數,返回callable物件。
    #callable物件是函式,物件重寫call方法
    
#例項1:無引數類裝飾器
class log (object):
    def __init__(self, func):
        print('func name = %s ' % func.__name__)
        self.__func = func
    
    def __call__(self, *args, **kwargs):
        print('裝飾器開始...')
        return self.__func(*args, **kwargs)
    
@log
def add(x, y):
    print('runing add...' )
    return x + y
    
#呼叫:
print('add()=', add(2, 4))
    
#func name = add
#裝飾器開始...
#runing add...
#add()= 6
    
#例項2:帶引數類裝飾器
class log(object):
    def __init__(self, level='INFO'):
        self.level = level
    
    def __call__(self, func):  # 接受函式
        def wrapper(*args, **kwargs):
            print("裝飾器{}開始...[ enter function {}()]".format(
                                                                self.level,func.__name__))
            func(*args, **kwargs)
    
        return wrapper  # 返回函式
    

@log('INFO')
def add(x,y):
    print("runing add...[z={}]".format(x+y))
    
#呼叫:
add(2,3)
    
# 裝飾器INFO開始...[ enter function add()]
# runing add...[z=5]
    
=================================================================
3.兩個裝飾器執行流程
    
def log1(func):
    print('----a----')
    
    def inner(*args, **kwargs):
        print('----1----')
        return ('log1=%s' % func(*args, **kwargs))
    
    return inner
    

def log2(func):
    print('----b----')
    
    def inner(*args, **kwargs):
        print('----2----')
        return ('log2=%s' % func(*args, **kwargs))
    
    return inner
    
@log1
@log2
def add(x, y):
    print('----3----')
    return x + y
    
#呼叫:
ret = add(2, 4)
print(ret)
    
##輸出結果:
#----b----
#----a----
#----1----
#----2----
#----3----
#log1=log2=6
#
"""
說明:
    1)先用第二個裝飾器(log2)進行裝飾再用第一個裝飾器(log1)進行裝飾
    呼叫過程中,先執行第一個裝飾器(log1),接著再執行第二個裝飾器(log2)。
    
    2)裝飾時機
    在執行到 @ log1時,需要對下面的函式進行裝飾,此時直譯器繼續往下走,
    發現並不是一個函式名,而又是一個裝飾器,這時@log1裝飾器暫停執行 ,
    執行接下來裝飾器 @ log2,接著把add函式名傳入裝飾器函式從而列印’b’
    
    在log2裝飾完後此時add指向log2的inner函式地址,這時返回來執行 @ log1
    接著把新add傳入log1裝飾器函式中,因此列印了’a’。
    
    呼叫add函式的時候,根據上述分析,此時add指向log1.inner函式,因此會
    先列印‘1‘,接下來,在呼叫func()的時候,其實是呼叫的log2.inner()函式,
    所以列印‘2‘,在log2.inner中,呼叫的func其實才是我們最原聲的add函式,
    所以列印原add函式中的‘3‘,所以在一層層調完之後,列印的結果為
    log1 = log2 = 6
"""
=================================================================
4.other
    
4.1.裝飾器函式—傳遞文件說明
def wrap(func):
    def call(*args,**kwargs):
        return func(*args,**kwargs)
    call.__doc__=func.__doc__
    call.__name__=func.__name__
    return call
    
=================================================================
4.2. from functools import wraps
#模組@wraps(func)裝飾器可以將屬性從func傳遞給要定義的包裝器函式
    
def wrap(func):
    @wraps(func)
    def call(*args,**kwargs):
        return func(*args,**kwargs)
    return call
    
@wrap
def factorial(n):
    """tcy define function used wraps."""
    
# 呼叫:
help(factorial)
    
# 結果:
# Help on function factorial in module __main__:
# factorial(n)
# tcy define function used wraps.
    
================================================================
4.3.#函式屬性
    
def wrap(func):
    def call(*args,**kwargs):
        return func(*args,**kwargs)
    call.__doc__=func.__doc__
    call.__name__=func.__name__
    call.__dict__.update(func.__dict__)
    return call
    
@wrap
def foo():
    'foo function define'
    pass
    
#呼叫:
foo.secure=1
foo.private=1
help(foo)
print(foo.__dict__)
    
# 結果
'''''''''
Help on function foo in module __main__:
    
foo(*args, **kwargs)
    foo function define
    
{'secure': 1, 'private': 1}
'''
=================================================================