裝飾器整理

2022-07-24 02:39:07 字數 4707 閱讀 5667

現在,我們已經明白了裝飾器的原理。接下來,我們還有很多事情需要搞清楚。比如:裝飾帶引數的函式、多個裝飾器同時裝飾乙個函式、帶引數的裝飾器和類裝飾器。

def foo(func):  # 接收的引數是乙個函式名

def bar(x, y): # 這裡需要定義和被裝飾函式相同的引數

print("這裡是新功能...") # 新功能

func(x, y) # 被裝飾函式名和引數都有了,就能執行被裝飾函式了

return bar

# 定義乙個需要兩個引數的函式

@foo

def f1(x, y):

print("{}+{}={}".format(x, y, x+y))

# 呼叫被裝飾函式

f1(100, 200)

輸出:

這裡是新功能...

100+200=300

def foo1(func):

print("d1")

def inner1():

print("inner1")

return "{}".format(func())

return inner1

def foo2(func):

print("d2")

def inner2():

print("inner2")

return "{}".format(func())

return inner2

@foo1

@foo2

def f1():

return "hello andy"

# f1 = foo2(f1) ==> print("d2") ==> f1 = inner2

# f1 = foo1(f1) ==> print("d1") ==> f1 = foo1(inner2) ==> inner1

ret = f1() # 呼叫f1() ==> inner1() ==> inner2() ==>inner1()==>hello andy

print(ret)

被裝飾的函式可以帶引數,裝飾器同樣也可以帶引數。

回頭看我們上面寫得那些裝飾器,它們預設把被裝飾的函式當成唯一的引數。但是呢,有時候我們需要為我們的裝飾器傳遞引數,這種情況下應該怎麼辦呢?

接下來,我們就一步步實現帶引數的裝飾器:

首先我們來回顧下上面的**:

def f1(func):  # f1是我們定義的裝飾器函式,func是被裝飾的函式

def f2(*arg, **kwargs): # *args和**kwargs是被裝飾函式的引數

func(*arg, **kwargs)

return f2

從上面的**,我們發現了什麼?

我的裝飾器如果有引數的話,沒地方寫了…怎麼辦呢?

還是要使用閉包函式!

# 三層巢狀的函式1

def f1():

def f2():

name = "andy"

def f3():

print(name)

return f3

return f2

巢狀三層之後的函式呼叫:

f = f1()  # f --> f2

ff = f() # ff --> f3

ff() # ff() --> f3() --> print(name) --> andy

注意:在內部函式f3中能夠訪問到它外層函式f2中定義的變數,當然也可以訪問到它最外層函式f1中定義的變數。

# 三層巢狀的函式2

def f1():

name = "andy"

def f2():

def f3():

print(name)

return f3

return f2

呼叫:

f = f1()  # f --> f2

ff = f() # ff --> f3

ff() # ff() --> f3() --> print(name) --> andy

好了,現在我們就可以實現我們的帶引數的裝飾器函式了:

# 帶引數的裝飾器需要定義乙個三層的巢狀函式

def d(name): # d是新新增的最外層函式,為我們原來的裝飾器傳遞引數,name就是我們要傳遞的函式

def f1(func): # f1是我們原來的裝飾器函式,func是被裝飾的函式

def f2(*arg, **kwargs): # f2是內部函式,*args和**kwargs是被裝飾函式的引數

print(name) # 使用裝飾器函式的引數

func(*arg, **kwargs) # 呼叫被裝飾的函式

return f2

return f1

上面就是乙個帶參裝飾器的**示例,現在我們來寫乙個完整的應用:

def d(a=none):  # 定義乙個外層函式,給裝飾器傳引數--role

def foo(func): # foo是我們原來的裝飾器函式,func是被裝飾的函式

def bar(*args, **kwargs): # args和kwargs是被裝飾器函式的引數

# 根據裝飾器的引數做一些邏輯判斷

if a:

print("歡迎來到{}頁面。".format(a))

else:

print("歡迎來到首頁。")

# 呼叫被裝飾的函式,接收引數args和kwargs

func(*args, **kwargs)

return bar

return foo

@d() # 不給裝飾器傳引數,使用預設的'none'引數

def index(name):

print("hello {}.".format(name))

@d("電影") # 給裝飾器傳乙個'電影'引數

def movie(name):

print("hello {}.".format(name))

if __name__ == '__main__':

index("andy")

movie("andy")

輸出:

歡迎來到首頁。

hello andy.

歡迎來到電影頁面。

hello andy.

除了用函式去裝飾函式外,我們還可以使用類去裝飾函式。

class d(object):

def __init__(self, a=none):

self.a = a

self.mode = "裝飾"

def __call__(self, *args, **kwargs):

if self.mode == "裝飾":

self.func = args[0] # 預設第乙個引數是被裝飾的函式

self.mode = "呼叫"

return self

# 當self.mode == "呼叫"時,執行下面的**(也就是呼叫使用類裝飾的函式時執行)

if self.a:

print("歡迎來到{}頁面。".format(self.a))

else:

print("歡迎來到首頁。")

self.func(*args, **kwargs)

@d()

def index(name):

print("hello {}.".format(name))

@d("電影")

def movie(name):

print("hello {}.".format(name))

if __name__ == '__main__':

index("andy")

movie("andy")

我們上面所有的例子都是裝飾乙個函式,返回乙個可執行函式。python中的裝飾器除了能裝飾函式外,還能裝飾類。

可以使用裝飾器,來批量修改被裝飾類的某些方法:

# 定義乙個類裝飾器

class d(object):

def __call__(self, cls):

class inner(cls):

# 重寫被裝飾類的f方法

def f(self):

print("hello andy.")

return inner

@d()

class c(object): # 被裝飾的類

# 有乙個例項方法

def f(self):

print("hello world.")

if __name__ == '__main__':

c = c()

c.f()

整理Python裝飾器

需要理解的三個方面 1 函式即 變數 2 高階函式 a 把函式名當做實參傳給另乙個函式 在不修改被裝飾函式源 的情況下進行功能擴充套件 b 返回值中包含函式名 不修改函式的呼叫方式 3 巢狀函式 函式裡面用def宣告另乙個函式 高階函式 巢狀函式 裝飾器 一 未使用裝飾器 usr bin env p...

python基礎知識整理 裝飾器

最簡裝飾器 def deco func def wrap args,kwargs return func args,kwargs return wrap deco def foo a,b return a b原理 對比被裝飾前後的foo.name 和foo.doc from functools im...

裝飾器之類裝飾器

外部的方法至今都玩過了,現在來思索一下的方法這麼裝飾 類方法修飾器 類的方法唯一的特殊點在於,self內部是可以呼叫的,但是在外部卻是隱藏的,那這個怎麼搞 為求穩妥,先定參修飾乙個 def godme fun def godme self,message print before fun self,...