Python高階之裝飾器

2021-07-31 23:17:55 字數 4280 閱讀 9378

要理解python裝飾器,首先要明白在python中,函式也是一種物件,因此可以把定義函式時的函式名看作是函式物件的乙個引用。既然是引用,因此可以將函式賦值給乙個變數,也可以把函式作為乙個引數傳遞或返回。同時,函式體中也可以再定義函式。

可以通過編寫乙個純函式的例子來還原裝飾器所要做的事。

def

decorator

(func):

defwrap

(): print("doing someting before executing func()")

func()

print("doing someting after executing func()")

return wrap

deffun_test

(): print("func")

fun_test = decorator(fun_test)

fun_test()

# output:

# doing someting before executing func()

# func

# doing someting after executing func()

fun_test所指向的函式的引用傳遞給decorator()函式

decorator()函式中定義了wrap()子函式,這個子函式會呼叫通過func引用傳遞進來的fun_test()函式,並在呼叫函式的前後做了一些其他的事情

decorator()函式返回內部定義的wrap()函式引用

fun_test接收decorator()返回的函式引用,從而指向了乙個新的函式物件

通過fun_test()呼叫新的函式執行wrap()函式的功能,從而完成了對fun_test()函式的前後裝飾

在python中可以通過@符號來方便的使用裝飾器功能。

def

decorator

(func):

defwrap

(): print("doing someting before executing func()")

func()

print("doing someting after executing func()")

return wrap

@decorator

deffun_test

(): print("func")

fun_test()

# output:

# doing someting before executing func()

# func

# doing someting after executing func()

裝飾的功能已經實現了,但是此時執行:

print(fun_test.__name__)

# output:

# wrap

fun_test.__name__已經變成了wrap,這是應為wrap()函式已經重寫了我們函式的名字和注釋文件。此時可以通過functools.wraps來解決這個問題。wraps接受乙個函式來進行裝飾,並加入了複製函式名稱、注釋文件、引數列表等等功能。這可以讓我們在裝飾器裡面訪問在裝飾之前的函式的屬性。

更規範的寫法:

from functools import wraps

defdecorator

(func):

@wraps(func)

defwrap

(): print("doing someting before executing func()")

func()

print("doing someting after executing func()")

return wrap

@decorator

deffun_test

(): print("func")

fun_test()

print(fun_test.__name__)

# output:

# doing someting before executing func()

# func

# doing someting after executing func()

# fun_test

通過返回乙個包裹函式的函式,可以模仿wraps裝飾器,構造出乙個帶引數的裝飾器。

from functools import wraps

defloginfo

(info='info1'):

defloginfo_decorator

(func):

@wraps(func)

defwrap_func

(*args, **kwargs):

print(func.__name__ + ' was called')

print('info: %s' % info)

return func(*args, **kwargs)

return wrap_func

return loginfo_decorator

@loginfo()

deffunc1

():pass

func1()

# output:

# func1 was called

# info: info1

@loginfo(info='info2')

deffunc2

():pass

func2()

# output:

# func2 was called

# info: info2

通過編寫類的方法也可以實現裝飾器,並讓裝飾器具備繼承等物件導向中更實用的特性

首先編寫乙個裝飾器基類:

from functools import wraps

class

loginfo:

def__init__

(self, info='info1'):

self.info = info

def__call__

(self, func):

@wrap

defwrap_func

(*args, **kwargs):

print(func.__name__ + ' was called')

print('info: %s' % self.info)

self.after() # 呼叫after方法,可以在子類中實現

return func(*args, **kwargs)

return wrap_func

defafter

(self):

pass

@loginfo(info='info2')

deffunc1

():pass

# output:

# func1 was called

# info: info1

再通過繼承loginfo類,擴充套件裝飾器的功能:

class

loginfo_after

(loginfo):

def__init__

(self, info2='info2', *args, **kwargs):

self.info2 = info2

super(loginfo_after, self).__init__(*args, **kwargs)

defafter

(self):

print('after: %s' % self.info2)

@loginfo_after()

deffunc2

():pass

func2()

# output:

# func2 was called

# info: info1

# after: info2

python高階裝飾器 Python裝飾器高階

對帶引數的函式進行裝飾 對帶引數的函式進行裝飾,內嵌包裝函式的形參和返回值與原函式相同,裝飾函式返回內嵌包裝函式物件 def deco func def deco a,b print before myfunc called.ret func a,b print after myfunc calle...

Python高階特性之裝飾器

裝飾器 定義乙個裝飾函式,函式必須返回乙個閉包 閉包就是執行時所需要的外部變數 函式物件,關於閉包的具體介紹,可參考函式,並且被裝飾的函式會被python自動傳遞給裝飾函式,作為裝飾函式的乙個引數。裝飾器的具體定義 1 把要裝飾的方法作為輸入引數 2 在函式體內可以進行任意的操作 可以想象其中會有很...

python基礎高階之裝飾器

一 閉包 1 閉包概念 def fn num 閉包的基本格式 def fn in print s num return fn in ret fn 30 ret 以上,ret fn 30 做了一下幾件事情 1,讓fn in指向某個記憶體空間 函式 2,在這個空間中建立乙個num指向30 3,把fn i...