python 裝飾器 decorator,描述器 descriptor,@property屬性,@wrap,update_wrapper

裝飾器 decorator

官方文檔定義

decorator -- 裝飾器 返回值為另一個函數(shù)的函數(shù)航邢,通常使用 @wrapper 語法形式來進行函數(shù)變換施绎。裝飾
器的常見例子包括 classmethod() 和 staticmethod()溯革。
裝飾器語法只是一種語法糖,以下兩個函數(shù)定義在語義上完全等價:

def f(...):
... 
f = staticmethod(f)
@staticmethod
def f(...):
... 

同的樣概念也適用于類谷醉,但通常較少這樣使用致稀。有關裝飾器的詳情可參見 函數(shù)定義和 類定義的文
檔。

相關知識點

  • 函數(shù)俱尼,類都是對象

函數(shù)可以當做參數(shù)傳遞或返回值

  • 閉包

內(nèi)部函數(shù)使用外部函數(shù)定義的變量
返回內(nèi)部函數(shù)對象在外邊調(diào)用

參考范例

  • 不帶參數(shù)的裝飾器
import time
def showtime(func):
    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        print('spend is {}'.format(end_time - start_time))

    return wrapper

@showtime  #foo = showtime(foo)
def foo():
    print('foo..')
    time.sleep(3)

@showtime #doo = showtime(doo)
def doo():
    print('doo..')
    time.sleep(2)

foo()
doo()
  • 被裝飾的函數(shù)帶參數(shù)
import time
def showtime(func):
    def wrapper(a, b):
        start_time = time.time()
        func(a,b)
        end_time = time.time()
        print('spend is {}'.format(end_time - start_time))

    return wrapper

@showtime #add = showtime(add)
def add(a, b):
    print(a+b)
    time.sleep(1)

@showtime #sub = showtime(sub)
def sub(a,b):
    print(a-b)
    time.sleep(1)

add(5,4)
sub(3,2)
  • 帶參數(shù)的裝飾器
import time
def time_logger(flag = 0):
    def showtime(func):
        def wrapper(a, b):
            start_time = time.time()
            func(a,b)
            end_time = time.time()
            print('spend is {}'.format(end_time - start_time))

            if flag:
                print('將此操作保留至日志')

        return wrapper

    return showtime

@time_logger(2)  #得到閉包函數(shù)showtime,add = showtime(add)
def add(a, b):
    print(a+b)
    time.sleep(1)

add(3,4)
  • 定義類裝飾器裝飾函數(shù)
import time
class Foo(object):
    def __init__(self, func):
        self._func = func

    def __call__(self):
        start_time = time.time()
        self._func()
        end_time = time.time()
        print('spend is {}'.format(end_time - start_time))

@Foo  #bar = Foo(bar)
def bar():
    print('bar..')
    time.sleep(2)

bar()
  • 裝飾器裝飾類
# 定義一個裝飾器
def decorator(cls):
    print("這里可以寫被裝飾類新增的功能") 
    return cls


# 定義一個類 A,并使用decorator裝飾器裝飾
@decorator # 裝飾器的本質(zhì) A = decorator(A)抖单,裝飾器返回類本身,還是之前的類遇八,只是在返回之前增加了額外的功能
class A(object):
    def __init__(self):
        pass

    def test(self):
        print("test")

描述器 descriptor

官方文檔定義

descriptor -- 描述器 任何定義了 get(), set() 或 delete() 方法的對象矛绘。當一個類屬
性為描述器時,它的特殊綁定行為就會在屬性查找時被觸發(fā)刃永。通常情況下货矮,使用 a.b 來獲取、設置
或刪除一個屬性時會在 a 的類字典中查找名稱為 b 的對象斯够,但如果 b 是一個描述器囚玫,則會調(diào)用對應
的描述器方法喧锦。理解描述器的概念是更深層次理解 Python 的關鍵,因為這是許多重要特性的基礎抓督,
包括函數(shù)裸违、方法、屬性本昏、類方法供汛、靜態(tài)方法以及對超類的引用等等。
有關描述符的方法的詳情可參看 descriptors涌穆。

@property屬性

@property是個描述器 descriptor

參考源碼

class property(object):
    """
    Property attribute.
    
      fget
        function to be used for getting an attribute value
      fset
        function to be used for setting an attribute value
      fdel
        function to be used for del'ing an attribute
      doc
        docstring
    
    Typical use is to define a managed attribute x:
    
    class C(object):
        def getx(self): return self._x
        def setx(self, value): self._x = value
        def delx(self): del self._x
        x = property(getx, setx, delx, "I'm the 'x' property.")
    
    Decorators make defining new properties or modifying existing ones easy:
    
    class C(object):
        @property
        def x(self):
            "I am the 'x' property."
            return self._x
        @x.setter
        def x(self, value):
            self._x = value
        @x.deleter
        def x(self):
            del self._x
    """
    ...

@wrap,update_wrapper

修改被裝飾函數(shù)的元信息

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')

參考源碼

################################################################################
### update_wrapper() and wraps() decorator
################################################################################

# update_wrapper() and wraps() are tools to help write
# wrapper functions that can handle naive introspection

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
                   wrapped,
                   assigned = WRAPPER_ASSIGNMENTS,
                   updated = WRAPPER_UPDATES):
    """Update a wrapper function to look like the wrapped function

       wrapper is the function to be updated
       wrapped is the original function
       assigned is a tuple naming the attributes assigned directly
       from the wrapped function to the wrapper function (defaults to
       functools.WRAPPER_ASSIGNMENTS)
       updated is a tuple naming the attributes of the wrapper that
       are updated with the corresponding attribute from the wrapped
       function (defaults to functools.WRAPPER_UPDATES)
    """
    for attr in assigned:
        try:
            value = getattr(wrapped, attr)
        except AttributeError:
            pass
        else:
            setattr(wrapper, attr, value)
    for attr in updated:
        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
    # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
    # from the wrapped function when updating __dict__
    wrapper.__wrapped__ = wrapped
    # Return the wrapper so this can be used as a decorator via partial()
    return wrapper

def wraps(wrapped,
          assigned = WRAPPER_ASSIGNMENTS,
          updated = WRAPPER_UPDATES):
    """Decorator factory to apply update_wrapper() to a wrapper function

       Returns a decorator that invokes update_wrapper() with the decorated
       function as the wrapper argument and the arguments to wraps() as the
       remaining arguments. Default arguments are as for update_wrapper().
       This is a convenience function to simplify applying partial() to
       update_wrapper().
    """
    return partial(update_wrapper, wrapped=wrapped,
                   assigned=assigned, updated=updated)

參考資源鏈接

python3 裝飾器全解
Python 使用裝飾器裝飾類
Python@property詳解及底層實現(xiàn)介紹

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末怔昨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宿稀,更是在濱河造成了極大的恐慌趁舀,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祝沸,死亡現(xiàn)場離奇詭異矮烹,居然都是意外死亡,警方通過查閱死者的電腦和手機罩锐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門奉狈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人涩惑,你說我怎么就攤上這事仁期。” “怎么了竭恬?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵跛蛋,是天一觀的道長。 經(jīng)常有香客問我痊硕,道長赊级,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任岔绸,我火速辦了婚禮理逊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘亭螟。我一直安慰自己挡鞍,他們只是感情好骑歹,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布预烙。 她就那樣靜靜地躺著,像睡著了一般道媚。 火紅的嫁衣襯著肌膚如雪扁掸。 梳的紋絲不亂的頭發(fā)上翘县,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音谴分,去河邊找鬼锈麸。 笑死,一個胖子當著我的面吹牛牺蹄,可吹牛的內(nèi)容都是我干的忘伞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼沙兰,長吁一口氣:“原來是場噩夢啊……” “哼氓奈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鼎天,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤舀奶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后斋射,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體育勺,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年罗岖,在試婚紗的時候發(fā)現(xiàn)自己被綠了涧至。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡桑包,死狀恐怖化借,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捡多,我是刑警寧澤蓖康,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站垒手,受9級特大地震影響蒜焊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜科贬,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一泳梆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧榜掌,春花似錦优妙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至胞皱,卻和暖如春邪意,著一層夾襖步出監(jiān)牢的瞬間九妈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工雾鬼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萌朱,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓策菜,卻偏偏與公主長得像晶疼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子又憨,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容