Python之裝飾器(二)

                                                    Python之裝飾器(二)

           之前總結了裝飾器的簡單原理,本次主要總結有參函數的裝飾。

一、裝飾有參函數:add(a, b)

       裝飾器通過返回包裝對象實現間接調用,插入額外功能。如下例,裝飾有參函數add(a, b),在函數運行前sleep()一段時間。實際上,add = func = wapper, 所以func()和wapper()需要加上參數,而爲了使程序更加有擴展性,可添加可變參數*agrs和 **kwargs。

def delay(func):
    def wrapper(*args, **kwargs):    # 1
        time.sleep(1)
        ret = func(*args, **kwargs)  # 2
        print("delay 1 second before call %s" % func.__name__)
        return ret                   # 原函數返回值
    return wrapper


@delay
def add(a, b):
    return a + b

二、帶參裝飾器:@decorator(parameter = value)

@delay_p(parameter='A') #
def add1(a, b):
    return a + b

       獲取被裝飾函數的信息,從而可實現不同函數採取不一樣的裝飾效果。而要將parameter參數傳遞到裝飾器中,再加一層函數來接受參數。類似嵌套函數的概念,執行內函數,先執行外函數。以上帶參的裝飾器可寫成如下調用形式:

delay_p = delay_p(parameter)
add1 = delay_p(add1)

裝飾器加一層函數接收參數,其他的與無參裝飾器類似。

def delay_p(parameter):
    def outer_wrapper(func):
        def wrapper(*args, **kwargs):        # 1
            if parameter == 'A':
                time.sleep(5)
                ret = func(*args, **kwargs)
                print("delay 5 second before call %s" % func.__name__)
            else:
                time.sleep(4)
                ret = func(*args, **kwargs)
                print("delay 4 second before call %s" % func.__name__)
            return ret
        return wrapper
    return outer_wrapper


@delay_p(parameter='A')
def add1(a, b):
    return a + b


@delay_p(parameter='B')
def add2(a, b):
    return a + b
各函數調用結果:

 

三、@wraps

       裝飾器(decorator)在實現的時候,被裝飾後的函數其實已經是另外一個函數,函數的屬性已被裝飾器改變。

print(add.__name__, add.__doc__)     # wrapper None
print(add1.__name__, add1.__doc__)   # wrapper decor

     Python的functools包中functools.wraps可消除這樣的影響,將原函數對象的指定屬性複製給包裝函數對象。使其保留原有函數的名稱和docstring。如下 # 1處加入 @wraps(func), 運行結果:add1 Docstring add1

from functools import wraps     # 

def delay_p(parameter):
    def outer_wrapper(func):
        @wraps(func)            # 1
        def wrapper(*args, **kwargs):
            """decor"""
            if parameter == 'A':
                time.sleep(5)
                ret = func(*args, **kwargs)
                print("delay 5 second before call %s" % func.__name__)
            else:
                time.sleep(4)
                ret = func(*args, **kwargs)
                print("delay 4 second before call %s" % func.__name__)
            return ret
        return wrapper
    return outer_wrapper


@delay_p(parameter='A')
def add1(a, b):
    """Docstring add1"""
    return a + b

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章