二十六 裝飾器

2021-08-13 15:15:03 字數 2310 閱讀 4036

裝飾器

由於函式也是乙個物件,而且函式物件可以被賦值給變數,所以,通過變數也能呼叫該函式。

>>> def now():... print('2015-3-25')...>>> f = now>>> f()2015-3-25

函式物件有乙個

__name__屬性,可以拿到函式的名字:

>>> now.__name__'now'>>> f.__name__'now'

現在,假設我們要增強

now()函式的功能,比如,在函式呼叫前後自動列印日誌,但又不希望修改

now()函式的定義,這種在**執行期間動態增加功能的方式,稱之為「裝飾器」(decorator)。

本質上,decorator就是乙個返回函式的高階函式。所以,我們要定義乙個能列印日誌的decorator,可以定義如下:

觀察上面的

log,因為它是乙個decorator,所以接受乙個函式作為引數,並返回乙個函式。我們要借助python的@語法,把decorator置於函式的定義處:

@logdef now(): print('2015-3-25') 呼叫

now()函式,不僅會執行

now()函式本身,還會在執行

now()函式前列印一行日誌:

>>> now()call now():2015-3-25 把

@log放到

now()函式的定義處,相當於執行了語句:

now = log(now) 由於

log()是乙個decorator,返回乙個函式,所以,原來的

now()函式仍然存在,只是現在同名的

now變數指向了新的函式,於是呼叫

now()將執行新函式,即在

log()函式中返回的

(*args, **kw),因此,

如果decorator本身需要傳入引數,那就需要編寫乙個返回decorator的高階函式,寫出來會更複雜。比如,要自定義log的文字:

這個3層巢狀的decorator用法如下:

@log('execute')def now(): print('2015-3-25')

執行結果如下:

>>> now()execute now():2015-3-25

和兩層巢狀的decorator相比,3層巢狀的效果是這樣的:

>>> now = log('execute')(now)

我們來剖析上面的語句,首先執行

log('execute'),返回的是

decorator函式,再呼叫返回的函式,引數是

now函式,返回值最終是

以上兩種decorator的定義都沒有問題,但還差最後一步。因為我們講了函式也是物件,它有

__name__等屬性,但你去看經過decorator裝飾之後的函式,它們的

__name__已經從原來的

'now'變成了

因為返回的那個

__name__等屬性複製到

不需要編寫

functools.wraps就是幹這個事的,所以,乙個完整的decorator的寫法如下:

或者針對帶引數的decorator:

import functools是匯入

functools模組。模組的概念稍候講解。現在,只需記住在定義

@functools.wraps(func)即可。練習

# -*- coding: utf-8 -*-import time, functools

# 測試@metricdef fast(x, y): time.sleep(0.0012) return x + y;@metricdef slow(x, y, z): time.sleep(0.1234) return x * y * z;f = fast(11, 22)s = slow(11, 22, 33)if f != 33: print('測試失敗!')elif s != 7986: print('測試失敗!')小結

在物件導向(oop)的設計模式中,decorator被稱為裝飾模式。oop的裝飾模式需要通過繼承和組合來實現,而python除了能支援oop的decorator外,直接從語法層次支援decorator。python的decorator可以用函式實現,也可以用類實現。

decorator可以增強函式的功能,定義起來雖然有點複雜,但使用起來非常靈活和方便。

請編寫乙個decorator,能在函式呼叫的前後列印出

'begin call'和

'end call'的日誌。

再思考一下能否寫出乙個

@log的decorator,使它既支援:

@logdef f(): pass

又支援:

@log('execute')def f(): pass

二十六 遮蔽中斷

1.6410和210採用向量中斷,由硬體執行。有兩組中斷源,相應的控制暫存器也有多個 2.6410和210使能和遮蔽是分開的暫存器 3.遮蔽控制暫存器的讀寫操作從而遮蔽中斷,都是寫入全1 4.6410的 遮蔽中斷,要操作兩個暫存器,目的是將使能中斷暫存器的相關位清除 define vic0inten...

每日程式設計(二十六)

如果不存在下乙個更大的排列,則將數字重新排列成最小的排列 即公升序排列 必須原地修改,只允許使用額外常數空間。以下是一些例子,輸入位於左側列,其相應輸出位於右側列。1,2,3 1,3,2 3,2,1 1,2,3 1,1,5 1,5,1 分析 很明顯從後想前遍歷,直到找到乙個前面的數比後面的小,然後在...

出差(二十六)調節

週日,下雨的一天,沒有因為昨晚的最強大腦影響今天起床,電視節目依舊精彩,再次被鬼才之眼的超能力震撼,直接又一次秒殺日本對手,給力。想到兒子這段時間連續上課,補課,大家都在努力,當老爸的也得加油。今天上午把新調整的功能重新過了一遍,對頁面布局,資料聯動做了一輪驗證,按著正常的流程基本能走通。由於是週日...