欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python各種類型裝飾器詳細(xì)介紹

 更新時間:2021年12月09日 11:02:12   作者:上帝De助手  
大家好,本篇文章主要講的是Python各種類型裝飾器詳細(xì)介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽

裝飾器說明

Python中的裝飾器是一種可以裝飾其它對象的工具。該工具本質(zhì)上是一個可調(diào)用的對象(callable),所以裝飾器一般可以由函數(shù)、類來實現(xiàn)。裝飾器本身需要接受一個被裝飾的對象作為參數(shù),該參數(shù)通常為函數(shù)、方法、類等對象。裝飾器需要返回一個對象,該對象可以是 經(jīng)過處理的原參數(shù)對象、一個包裝且類似原參數(shù)的對象;或者返回一個不相干內(nèi)容(通常不建議使用)

相信通過上述一段文字的描述,大家應(yīng)該更加的迷惑了!所以下面我們就結(jié)合代碼來理解Python中的裝飾器。

裝飾器分類

最簡單的裝飾器

def warp(obj):
    return obj

沒錯?。?!這就是最簡單的裝飾器,并且是一個沒有任何用處的裝飾器。但是它確實是一個裝飾器,并且可以用的很好。比如:

@warp    # 等價于 foo = warp(foo)
def foo():    
    print('hello decorator!')
 
foo()    # => hello decorator!

而上面使用了裝飾器的代碼,其實我們可以通過其它方式達(dá)到相同的效果。具體見下:

def foo():
    print('hello decorator!')
 
foo = warp(foo)
foo()    # => hello decorator!

So,通過最簡單的代碼,我們可以發(fā)現(xiàn)裝飾器其實就是接受了一個函數(shù)(對象),并且返回了一個函數(shù)(對象)的函數(shù)(可調(diào)用對象)。

用于修改對象的裝飾器

在理解了裝飾器的含義之后,再來看一個稍微有點作用的裝飾器。代碼如下:

def warp(obj):
    obj.name = 'python'
    return obj

這個裝飾器在上一個例子的基礎(chǔ)上,只添加了一行代碼,但是卻有了實際的作用。它的作用就是給被裝飾的對象,添加一個name屬性并且設(shè)置值為python。這個裝飾器的使用效果如下:

@warp        # => Bar = warp(Bar)
class Bar(object):
    def __init__(self):
        pass
 
print(Bar.name)     # => python

可以看到實際的使用過程中,warp裝飾器已經(jīng)成功的給Bar對象添加了name屬性。除了給類對象添加屬性之外,它還可以給函數(shù)對象添加屬性。

@warp       # => foo = warp(foo)
def foo():
    pass
 
print(foo.name)         # => python

用于模擬對象的裝飾器--函數(shù)裝飾器

上面例子中的裝飾器,是直接修改了傳入對象;而裝飾器最常用的方式卻是模擬一個傳入對象。即返回一個和原對象相似的對象(即調(diào)用接口完全一樣的另一個對象),并且該模擬對象是包裝了原對象在內(nèi)的。具體代碼如下:

def outer(func):         # 函數(shù)裝飾器
    def inner():
        func()
 
    return inner

上面是一個函數(shù)裝飾器,即用來修飾函數(shù)的裝飾器。因為它返回了一個模擬func對象的inner對象。而這里inner對象是一個函數(shù),所以這個裝飾器只能裝飾函數(shù)。(因為inner對象只能模擬func這樣的函數(shù)對象,不能模擬class對象)

@outer      # foo = outer(foo)
def foo():
    print('hello foo')
 
foo()    # => hello foo

上述代碼中最后一行foo(),其實質(zhì)上是執(zhí)行的inner()。為了證明這一點,我們可以在inner中打印一條信息。并查看下foo的__name__屬性。

def outer(func):         # 函數(shù)裝飾器
    def inner():
        print('hello inner')
        func()
 
    return inner
 
@outer      # foo = outer(foo)
def foo():
    print('hello foo')
 
print(foo.__name__)
foo()

上述代碼執(zhí)行后的結(jié)果如下:

inner
hello inner
hello foo

可以看到首先打印的是 foo.__name__代碼,注意內(nèi)容是inner而不是foo(說明其本質(zhì)上是inner函數(shù));其次打印的時候,先打印inner函數(shù)中的內(nèi)容,后打印foo函數(shù)中的內(nèi)容。

用于模擬對象的裝飾器--類方法裝飾器

與函數(shù)裝飾器類似的還有類方法裝飾器,其作用相同,格式相近。只是些微有些區(qū)別,下面就是類方法裝飾器的代碼。

def outer(obj):         # 類方法裝飾器
    def inner(self):
        print('hello inner')
        obj(self)
 
    return inner
 
class Zoo(object):
    def __init__(self):
        pass
 
    @outer        # => zoo = outer(zoo)
    def zoo(self):
        print('hello zoo')
 
zoo = Zoo()
print(zoo.zoo.__name__)
zoo.zoo()

可以看到類方法裝飾器和函數(shù)裝飾器,唯一的區(qū)別就是多了一個默認(rèn)的self參數(shù);這是因為類方法本身就比函數(shù)多這么一個參數(shù)。其執(zhí)行的結(jié)果如下:

inner
hello inner
hello zoo

所以最后一行代碼zoo.zoo函數(shù)執(zhí)行的其實是inner函數(shù)。

用于模擬對象的裝飾器--類裝飾器

裝飾器除了可以裝飾函數(shù)、方法之外,還可以裝飾器類對象。具體的代碼如下:

def outer(clss):         # 類裝飾器
    class Inner(object):
        def __init__(self):
            self.clss = clss()
 
        def __getattr__(self, attr):
            return getattr(self.clss, attr)
 
    return Inner
 
 
@outer          # Zoo = outer(Zoo)
class Zoo(object):
    def __init__(self):
        pass
 
    def say(self):
        print('hello world!')
 
zoo = Zoo()
print(zoo.__class__)    # <class '__main__.outer.<locals>.Inner'>
zoo.say()               # hello world!

通過代碼可以看出,類裝飾器與函數(shù)裝飾器類似。即模擬一個與原參數(shù)接口一致的類對象。所以對于模擬類的裝飾器,只能用在其可以模擬的對象之上,并不能互相修飾其它類型的對象。

特殊應(yīng)用的裝飾器

上面都是比較常規(guī)的裝飾器,python中還有另外一些特殊的裝飾器。比如:類靜態(tài)屬性裝飾器。比如下面的代碼:

class Foo(object):
    def __init__(self, height, weigth):
        self.height = height
        self.weigth = weigth
 
    @property
    def ratio(self):
        return self.height / self.weigth
 
foo = Foo(176, 120)
print(foo.ratio)    # => 1.4666666666666666

上述代碼中的@property裝飾器就是一個特殊的裝飾器,它把ratio方法變成了一個屬性。從最后一句調(diào)用代碼可以看出,使用的是foo.ratio而不是foo.ratio()。

對于這類裝飾器需要Python的特定屬性和機制的支持才可以實現(xiàn),不同特性的裝飾器所需機制不同。如上述代碼中的@property裝飾器就可以使用下面的代碼來實現(xiàn)。

class Prop(object):
    def __init__(self, fget):
        self.fget = fget
 
    def __get__(self, instance, owner):
        return self.fget(instance)

具體的使用效果如下:

class Foo(object):
    def __init__(self, height, weigth):
        self.height = height
        self.weigth = weigth
 
    @Prop
    def ratio(self):
        return self.height / self.weigth
 
foo = Foo(176, 120)
print(foo.ratio)    # => 1.4666666666666666

可以看到效果和原生的@property裝飾器是一樣的。

類實現(xiàn)的裝飾器

在之前對于裝飾器的說明中,有說道裝飾器是一個callable對象。除了函數(shù)可以實現(xiàn)裝飾器之外,還可以通過類來實現(xiàn)。那么類實現(xiàn)裝飾器的具體代碼如下:

class Warp(object):
    def __init__(self):
        pass
 
    def __call__(self, obj):
        obj.name = 'warp'
        return obj

這個類裝飾器實現(xiàn)的功能,也是給傳入的對象添加name屬性,并設(shè)置其值為warp。其調(diào)用效果如下:

@Warp()
def foo():
    pass
 
print(foo.name)    # => warp

裝飾帶參數(shù)/返回值的對象

前面列舉的所有例子,被裝飾的對象都是無參數(shù)的。如果你需要裝飾一個帶參數(shù)的對象。那么就需要響應(yīng)的修改下裝飾器代碼了。注意:這里特指那些模擬類型的裝飾器。即函數(shù)裝飾器、類方法裝飾器、類裝飾器。

假設(shè)我們先有一個帶參數(shù)的函數(shù),其內(nèi)容如下:

def add(x, y):
    return x * y

如果使用原來的函數(shù)裝飾器,肯定就會出錯。主要因為這個函數(shù)帶參數(shù),并且也有返回值。而原來的函數(shù)裝飾器則不能支持,原函數(shù)裝飾器如下:

def outer(func):         # 函數(shù)裝飾器
    def inner():
        func()
 
    return inner

可以看到inner模擬的僅僅是一個無參數(shù)、無返回值的對象。所以需要進行如下的修改:

def outer(func):         # 函數(shù)裝飾器
    def inner(x, y):
        print('hello inner')
        return func(x, y)
 
    return inner

這樣的函數(shù)裝飾器就可以裝飾add函數(shù)了。因為inner函數(shù)添加了x,y參數(shù),調(diào)用func對象時也添加了參數(shù),并且返回了func對象的返回值。具體使用效果如下:

@outer
def add(x, y):
    return x * y
 
print(add(2, 3))    # => 6

上述代碼雖然可以實現(xiàn)add的裝飾功能,但是如果現(xiàn)在我們在出現(xiàn)一個三個參數(shù)的函數(shù)需要裝飾,或者一個帶默認(rèn)值參數(shù)的韓式需要裝飾怎么辦。我們不可能為沒一個不同參數(shù)的函數(shù)都寫一個相同功能的裝飾器。所以終極的函數(shù)裝飾器的寫法如下:

def outer(func):         # 函數(shù)裝飾器
    def inner(*args, **kwargs):
        print('hello inner')
        return func(*args, **kwargs)
 
    return inner

這里使用了python中動態(tài)參數(shù)的概念,這樣裝飾器就可以支持任意的組合參數(shù)的函數(shù)了。

裝飾器帶參數(shù)

上面說到的是被修飾的對象帶參數(shù)的情況,還有一種情況就是裝飾器本身希望支持帶參數(shù)。這種情況類似于函數(shù)模塊通過帶參數(shù)可以更加靈活的道理一樣。通過給裝飾器帶上參數(shù),可以使得裝飾器的功能更加的靈活。代碼如下:

url_mapping = {}
 
def route(url):
    def decorator(func):         # 函數(shù)裝飾器
        url_mapping[url] = func
        return func
    return decorator

上面是一個URL路由映射的裝飾器,可以給不同的函數(shù)綁定不同的路由。如果裝飾器不能帶參數(shù),則無法實現(xiàn)這樣的功能。其使用效果如下:

@route('/home')
def home():
    pass
    
@route('/index')
def index():
    pass
    
print(url_mapping)  # => {'/home': <function home at 0x01DAD810>, '/index': <function index at 0x01DAD7C8>}

裝飾器應(yīng)用

Python裝飾器的應(yīng)用比較廣泛,大部分場景的公共處理邏輯都可以使用裝飾器去簡化。(使用上類似于JAVA中的注解)一般比較常見的場景比如:

日志記錄

權(quán)限驗證單

例模式競爭

資源管理

到此這篇關(guān)于Python各種類型裝飾器詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Python裝飾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python合并2個字典成1個新字典的方法(9種)

    Python合并2個字典成1個新字典的方法(9種)

    這篇文章主要介紹了Python合并2個字典成1個新字典的方法,本文通過實例代碼給大家分享9中方法,需要的朋友可以參考下
    2019-12-12
  • Pandas數(shù)據(jù)類型轉(zhuǎn)換df.astype()及數(shù)據(jù)類型查看df.dtypes的使用

    Pandas數(shù)據(jù)類型轉(zhuǎn)換df.astype()及數(shù)據(jù)類型查看df.dtypes的使用

    Python,numpy都有自己的一套數(shù)據(jù)格式,本文主要介紹了Pandas數(shù)據(jù)類型轉(zhuǎn)換df.astype()及數(shù)據(jù)類型查看df.dtypes的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • 使用django自帶的user做外鍵的方法

    使用django自帶的user做外鍵的方法

    這篇文章主要介紹了使用django自帶的user做外鍵的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Python枚舉之Enum模塊的原理與應(yīng)用詳解

    Python枚舉之Enum模塊的原理與應(yīng)用詳解

    前段時間在閱讀別人的代碼時,看到代碼中有好多數(shù)字,雖然增加的注釋,哪個值代表哪種狀態(tài),但還是看起來很難受,不優(yōu)雅,如何改善這個問題呢?當(dāng)然是枚舉,本文將深入探討Python枚舉中的Enum模塊,需要的朋友可以參考下
    2023-11-11
  • Python利用Pydub實現(xiàn)自動分割音頻

    Python利用Pydub實現(xiàn)自動分割音頻

    pydub是一個輕量級的音頻處理庫,安裝方便,使用簡單。而且pydub提供了豐富的音頻處理功能,包括切割、合并、轉(zhuǎn)換等。本文將利用Pydub實現(xiàn)自動分割音頻功能,感興趣的可以了解一下
    2023-05-05
  • 基于Python制作一鍵桌面整理工具

    基于Python制作一鍵桌面整理工具

    相信大家雖然有很多一鍵整理桌面的軟件,但是對于其他路徑下的文件,同樣需要整理,還是很麻煩的。于是本文將利用Python制作一個桌面整理小工具,需要的可以參考一下
    2022-04-04
  • Python版的文曲星猜數(shù)字游戲代碼

    Python版的文曲星猜數(shù)字游戲代碼

    最近開始研究python,于是寫了個Python版的文曲星猜數(shù)字游戲,喜歡的朋友可以參考下
    2013-09-09
  • Python爬蟲進階之爬取某視頻并下載的實現(xiàn)

    Python爬蟲進階之爬取某視頻并下載的實現(xiàn)

    這篇文章主要介紹了Python爬蟲進階之爬取某視頻并下載的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 使用Keras訓(xùn)練好的.h5模型來測試一個實例

    使用Keras訓(xùn)練好的.h5模型來測試一個實例

    這篇文章主要介紹了使用Keras訓(xùn)練好的.h5模型來測試一個實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • Python打包exe文件一步步圖解明了簡單

    Python打包exe文件一步步圖解明了簡單

    之前看很多人都在問,Python怎么打包exe可執(zhí)行文件,雀氏有點多,那么我來了,給大家整一個Python打包exe可執(zhí)行文件的究極教程
    2021-11-11

最新評論