日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Python 闭包、单个装饰器、多个装饰器、装饰器修饰类、应用场景

發布時間:2023/11/28 生活经验 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python 闭包、单个装饰器、多个装饰器、装饰器修饰类、应用场景 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 閉包

Python 中,函數也可以作為參數。我們可以執行下面的代碼:

def func(a, b):return a + bprint(func)

我們直接輸出函數名,而沒有加括號。輸出結果如下:

<function func at 0x000002C83CC96678>

可以看懂結果是一個 function 的對象,我們可以把它賦值給另外的變量:

def func(a, b):return a + bmy_func = func
print(my_func(1, 3))

我們把 func 賦值給 my_func 變量,然后發現 my_func 可以和 func 一樣使用。輸出結果如下:

4

結果和 func 的結果一樣。那我們能不能把函數當做參數或者返回值呢?我們可以嘗試一下:

def func():def inner():print("執行了 inner 函數")return innerin_func = func()
in_func()

我們在 func 里面定義了一個 inner 函數,按理我們是不能在外部調用 inner 函數的,但是我們把 inner 當作返回值返回到外部,這樣我們就能在外部調用 inner 函數了。我們來看看運行結果:

執行了 inner 函數

可以看到確實執行了 inner 函數。其實 inner 函數我們就可以叫做閉包函數。我們可以利用閉包來實現裝飾器。那裝飾器又是什么呢?下面我們來詳細看一下。
?

2. 裝飾器

裝飾器如果從字面意思來講就是用來裝飾的東西,它裝飾的對象是函數。我們可以用裝飾器在不改變原函數的情況下對函數進行擴展。我們先不說裝飾器,我們想想要怎么才能擴展一個函數,最簡單的辦法就是如下:

def func(a, b):return a + bprint("在 func 之前執行")
func(1, 2)
print("在 func 之后執行")

我們直接調用這個函數,然后在函數前面添加一些代碼,再在函數執行后面添加一些代碼。這樣很好的完成了我們的任務,但是這種方式屬實有點矬略。如果我們經常要用到這種擴展,或者多個函數需要用到這樣的擴展我們這種方式就束手無策了。
?
這個時候我們就可以使用閉包,閉包能很好的解決這個問題。我們看下面這段代碼:

def say_hi(func):print("nice to meet you")def inner(*args, **kwargs):return func(*args, **kwargs)print("good bye")return innerdef func(greet):print(greet)say_hi_func = say_hi(func)

我們先定義一個函數 say_hi,它的參數是一個函數,也就是我們要擴展的函數。然后我們在里面定義一個 inner 函數,在 inner 函數中完成 func 函數的調用,并接收 func 的參數和返回值。最后將 inner 函數作為參數返回。
?
我們想對 func 函數進行擴展,我們只需要調用 say_hi(func),它就會給我們返回一個加強后的函數。我們可以執行看看:

def say_hi(func):print("nice to meet you")def inner(*args, **kwargs):return func(*args, **kwargs)print("good bye")return innerdef func(a, b):return a + bsay_hi_func = say_hi(func)
result = say_hi_func(1, 2)
print(result)

執行結果如下:

nice to meet you
good bye
3

可以看到我們成功擴展了 func 函數。但是這樣有點混亂,我們還需要先加強函數才能使用,而另一種簡單的方式就是使用 @ 符號:

def say_hi(func):print("nice to meet you")def inner(*args, **kwargs):return func(*args, **kwargs)print("good bye")return inner@say_hi
def func(a, b):return a + bprint(func(1, 2))

我們在 func 函數定義的時候執行了添加了 @say_hi,這個時候 func 就是解釋器會幫我們完成下面幾句代碼:

func = say_hi(func)

這樣就不需要再使用一個新的函數了。

3. 多裝飾器

我們可以給一個函數添加多個裝飾器,其實使用也是一樣的。我們可以這樣里面,假如我們有如下函數:

def func():print("這是函數體")

假如我們有如下裝飾器:

def decorate(func):print("函數執行前")def inner(*args, **kwargs):return func(*args, **kwargs)print("函數執行后")return inner

在外面對 func 函數進行裝飾后,func 的內容變為:

def func():print("函數執行前")print("函數體")print("函數執行后")

這時使用裝飾器后的函數和普通函數沒有區別,外面依舊可以用同樣的方式給他添加多個裝飾器:

def dec1(func):print("start dec1")def inner(*args, **kwargs):return func(*args, **kwargs)print("end dec1")return innerdef dec2(func):print("start dec2")def inner(*args, **kwargs):return func(*args, **kwargs)print("end dec2")return inner@dec2
@dec1
def func(a, b):return a + bprint(func(1, 2))

不過外面需要注意一下生效的順序:

start dec1
end dec1
start dec2
end dec2
3

可以看到時 dec1 裝飾器先起作用,對于多個裝飾器也是一樣的。

3.1 帶參裝飾器

def add(func):def fun(a, b):print("相乘", a * b)print("相除", a / b)func(a, b)return fun@add
def add_num(a, b):# 打印兩個數相加print("相加:", a + b)add_num(11, 22)

3.2 通用裝飾器

果同一個裝飾器既要裝飾有參數的函數,又要裝飾無參數的函數。那么我們在傳參的時候就設置成不定長參數,這樣不管被裝飾的函數有沒有參數都能用。

# 通用裝飾器
def add(func):def fun(*args, **kwargs):print("裝飾器的功能代碼:登錄前")func(*args,**kwargs)print("裝飾器的功能代碼:登錄后")return fun@add
def index():print("這個是網站的首頁")@add
def good_list(num):print("這個是商品列表第{}頁".format(num))index()
print("------------")
good_list(9)

其實裝飾器也是可以帶參數的,我們可以定義一個更加復雜的裝飾器:

def dec1(name):def decorator(func):def inner(*args, **kwargs):if name == "wohu":print("hi wohu")elif name == "jack":print("hi jack")return func(*args, **kwargs)return innerreturn decorator@dec1("wohu")
def func(a, b):return a+bprint(func(1, 2))

我們先來看下面的代碼:

@dec1("wohu")
def func(a, b):return a +b 

我們可以對 @dec1("wohu") 進行如下理解,其中 dec1("wohu") 的操作是執行 dec1 函數,并傳入參數,而 dec1 的返回值是一個裝飾器。這樣我們就很好理解了。
?
因此,我們需要在 dec1 函數中定義一個裝飾器。這可以從代碼中看到。其它部分和之前沒有區別,下面是輸出結果:

hi wohu
3

這種帶參數的裝飾器可以讓我們的裝飾器更加靈活,我們只需要通過不同參數就能讓裝飾器裝飾不同的效果。
?

4. 裝飾器裝飾類

4.1 不帶參數

#裝飾器裝飾類def add(func):def fun(*args, **kwargs):print("裝飾器的功能代碼:登錄")return func(*args,**kwargs)return fun@add  # MyClass=add(MyClass)
class MyClass:def __init__(self):passm = MyClass()
print("m 的值:",m)

把類當作一個參數傳到裝飾器里面。return fun返回的是 funMyClass接收到的是 fun
MyClass()調用的是 fun
?
執行代碼:

 def fun(*args, **kwargs):print("裝飾器的功能代碼:登錄")return func(*args,**kwargs)

這里面的功能。先執行裝飾器的功能,return func(*args,**kwargs)func()來自def add(func)
?
調用 MyClass這個類,return func(*args,**kwargs)創建了個對象,MyClass()調用完了接收,m 就能接收這個對象了。

4.2 帶參數

#裝飾器裝飾類def add(func):def fun(*args, **kwargs):print("裝飾器的功能代碼:登錄")# 裝飾器裝飾類和裝飾函數的不同點,下面這個 return 必須要寫 類需要把對象返回出來。return func(*args,**kwargs)return fun@add  # MyClass=add(MyClass)
class MyClass:def __init__(self,name,age):self.name=nameself.age=agem = MyClass("qinghan","18")
print("m 的值:",m)

這里用的是不定行參數,所以不管你裝飾的類是有參數的還是沒參數的,都可以。

5. 裝飾器的應用場景

  • 函數運行時間統計;
  • 執行函數之前做準備工作;
  • 執行函數后清理功能;

?

總結

以上是生活随笔為你收集整理的Python 闭包、单个装饰器、多个装饰器、装饰器修饰类、应用场景的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。