裝飾器的理解

裝飾器:
1.用于裝飾其他函數(shù)
2.增強(qiáng)被裝飾函數(shù)的功能
裝飾器需要接受一個(gè)函數(shù)對(duì)象作為參數(shù),以對(duì)其進(jìn)行增強(qiáng)

def deco(func):
    def wrapper():
        print "decorate something"
        func()
        print "decorate finish"
    return wrapper
@deco
def test_func():
    return "test func"
test_func()

output:
decorate something
test func
decorate finish

test_func()被裝飾之后,運(yùn)行函數(shù)test_func(),會(huì)運(yùn)行裝飾器這個(gè)函數(shù)

當(dāng)你在用某個(gè)@decorator來修飾某個(gè)函數(shù)func時(shí),如下所示:

@decorator
def func():
    pass

其解釋器會(huì)解釋成下面這樣的語句:

func = decorator(func)

先看一個(gè)簡單的裝飾器如下:

def hello(fn):
    def wrapper():
        print "hello, %s" % fn.__name__
        fn()
        print "goodby, %s" % fn.__name__
    return wrapper

@hello
def foo():
    print "i am foo"
  
foo()

輸出:

hello, foo
i am foo
goodby, foo

對(duì)于一個(gè)裝飾器的定義:

@hello
def foo():
    print "i am foo"

實(shí)際上可以理解成foo = hello(foo),將被包裝的函數(shù)(foo)當(dāng)作參數(shù)傳入裝飾器(hello)中,通過一系列包裝后將包裝后的函數(shù)再返回給被包裝的函數(shù)(foo),實(shí)際上就是返回了一個(gè)新函數(shù),只不過是根據(jù)原函數(shù)改造而來并且名字不變。

def out_func(**kwds):
    def real_decorator(fn):
        arg = kwds['arg1'] + kwds['arg2']
        def wapper():
            fn()
            return kwds['arg1'] + kwds['arg2'] + arg
        return wapper
    return real_decorator

@out_func(arg1='11111', arg2='22222')
def hello_world():
    print('hello world')

print(hello_world())

分析:我的理解是裝飾器有兩層,內(nèi)層wapper用于包裝,外層decorator(real_decorator)用于接收被包裝的函數(shù)(hello_world)作為參數(shù),并將包裝后的函數(shù)(wapper)返回給外部。此處的例子有三層,外層還有一個(gè)out_func函數(shù)的用處是給內(nèi)層傳遞參數(shù),由于外部多了一層函數(shù)所以裝飾器函數(shù)(real_decorator)將裝飾器本身返回給out_func,于是@out_func就相當(dāng)于裝飾器。

functools.wraps

我們?cè)谑褂?Decorator 的過程中,難免會(huì)損失一些原本的功能信息。

def logged(func):
    def with_logging(*args, **kwargs):
        print func.__name__ + " was called"
        return func(*args, **kwargs)
    return with_logging

@logged
def f(x):
   """does some math"""
   return x + x * x

def f(x):
    """does some math"""
    return x + x * x
f = logged(f)

In [24]: f.__name__
Out[24]: with_logging

由于返回的是包裝后的with_logging,所以name等基本信息變成了返回的新函數(shù)

而functools.wraps 則可以將原函數(shù)對(duì)象的指定屬性復(fù)制給包裝函數(shù)對(duì)象, 默認(rèn)有 module、name、doc,或者通過參數(shù)選擇。代碼如下:

from functools import wraps
def logged(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print func.__name__ + " was called"
        return func(*args, **kwargs)
    return with_logging

@logged
def f(x):
   """does some math"""
   return x + x * x

print f.__name__  # prints 'f'
print f.__doc__   # prints 'does some math'

from functools import wraps
def logged(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print func.__name__ + " was called"
        return func(*args, **kwargs)
    return with_logging
 
@logged
def f(x):
   """does some math"""
   return x + x * x
 
print f.__name__  # prints 'f'
print f.__doc__   # prints 'does some math'
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 部分細(xì)節(jié)自己改了點(diǎn),也加了點(diǎn)自己例子,基本上屬于轉(zhuǎn)載。轉(zhuǎn)載出處:https://my.oschina.net/le...
    洛克黃瓜閱讀 2,100評(píng)論 0 3
  • 本文為《爬著學(xué)Python》系列第四篇文章。從本篇開始,本專欄在順序更新的基礎(chǔ)上,會(huì)有不規(guī)則的更新。 在Pytho...
    SyPy閱讀 2,570評(píng)論 4 11
  • 每個(gè)人都有的內(nèi)褲主要功能是用來遮羞,但是到了冬天它沒法為我們防風(fēng)御寒,咋辦?我們想到的一個(gè)辦法就是把內(nèi)褲改造一下,...
    chen_000閱讀 1,403評(píng)論 0 3
  • Python的裝飾器的英文名叫Decorator,要對(duì)一個(gè)已有的模塊做一些“修飾工作”,所謂修飾工作就是想給現(xiàn)有的...
    Spareribs閱讀 733評(píng)論 1 11
  • 數(shù)據(jù)結(jié)構(gòu)是一門比較難學(xué)的課程,如同修煉乾坤大挪移,需要有一定的內(nèi)功作為基礎(chǔ)。我大學(xué)學(xué)過數(shù)據(jù)結(jié)構(gòu),綠皮的那本。現(xiàn)在想...
    放不下屠刀的佛閱讀 271評(píng)論 0 0

友情鏈接更多精彩內(nèi)容