亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python學(xué)習(xí)之裝飾器與類(lèi)的裝飾器詳解

 更新時(shí)間:2022年03月11日 08:27:20   作者:渴望力量的哈士奇  
這篇文章通過(guò)示例詳細(xì)為大家介紹了Python中的裝飾器以及類(lèi)的裝飾器。通過(guò)學(xué)習(xí)裝飾器可以讓我們更好更靈活的使用函數(shù),還可以讓我們的代碼更加優(yōu)雅,感興趣的可以學(xué)習(xí)一下

通過(guò)學(xué)習(xí)裝飾器可以讓我們更好更靈活的使用函數(shù),通過(guò)學(xué)會(huì)使用裝飾器還可以讓我們的代碼更加優(yōu)雅。

在我們的實(shí)際工作中,很多場(chǎng)景都會(huì)用到裝飾器,比如記錄一些日志、或者屏蔽一些不太合法的程序執(zhí)行從而使我們的代碼更加安全。

裝飾器

什么是裝飾器?雖然對(duì)這個(gè)次感到陌生,但是完全不需要擔(dān)心。

首先,裝飾器也是一種函數(shù);只不過(guò)裝飾器可以接收 函數(shù) 作為參數(shù)來(lái)傳遞。

并且可以通過(guò) return 可以返回一個(gè)函數(shù),裝飾器通過(guò)接收一個(gè)函數(shù),對(duì)它在裝飾器內(nèi)部進(jìn)行處理、調(diào)用,并返回一個(gè)新的函數(shù),同時(shí)還可以動(dòng)態(tài)增強(qiáng)傳入函數(shù)的功能。

裝飾器整個(gè)流程是這樣的:

  • A函數(shù)是裝飾器,B函數(shù)是A函數(shù)傳入的參數(shù)。
  • 將B函數(shù)在A函數(shù)中執(zhí)行,在A函數(shù)中可以選擇執(zhí)行或不執(zhí)行,也可以對(duì)B函數(shù)的結(jié)果進(jìn)行二次加工處理。

接下來(lái)我們看看 裝飾器長(zhǎng)什么樣子

def a():
    
    def b():
        print(helloworld)
        
    b()
    
    
a()
b()

a() 函數(shù)中書(shū)寫(xiě)了一個(gè) b() 函數(shù),并在 a() 函數(shù)中調(diào)用 b() 函數(shù)。是不是非常類(lèi)似在類(lèi)中定義一個(gè)局部函數(shù)并調(diào)用的例子?其實(shí)裝飾器就是有些類(lèi)似這樣的操作,只不過(guò)被裝飾器調(diào)用的函數(shù)是通過(guò) 參數(shù) 的形式傳進(jìn)去,并在 b() 函數(shù)中執(zhí)行。

我們?cè)诙x完 a() 函數(shù)之后進(jìn)行調(diào)用,可以正常處理。但是 b() 函數(shù) 是 a() 函數(shù)的局部函數(shù) 如果在外部調(diào)用會(huì)報(bào)錯(cuò)。(如上文中的第十行,就會(huì)報(bào)錯(cuò))

裝飾器的定義

示例如下:

def out(func_args):            # 裝飾器的第一層函數(shù)被稱(chēng)為 外圍函數(shù) , 'func_args' 為要處理的函數(shù)
    
    def inter(*args, **kwargs):        # 外圍函數(shù) 的函數(shù)體內(nèi)定義的函數(shù)被稱(chēng)為 內(nèi)嵌函數(shù) ;傳入的參數(shù)為要處理的 func_args 函數(shù)的參數(shù)
                                    # 這里我們并不知道 func_args 函數(shù)需要傳入進(jìn)來(lái)的參數(shù)是什么,所以目前寫(xiě)傳入可變參數(shù)是比較合理的
        return func_args(*args, **kwargs)        # 在 內(nèi)嵌函數(shù) 的函數(shù)體內(nèi)調(diào)用 func_args 函數(shù),并將可變參數(shù)傳入
                                                # 其實(shí)這里我們可以處理更多的邏輯;
                                                # 我們可以選擇執(zhí)行或者不執(zhí)行,甚至可以func_args 函數(shù)的執(zhí)行結(jié)果進(jìn)行二次處理
    
    
    return inter             # 書(shū)寫(xiě)完 內(nèi)嵌函數(shù)的業(yè)務(wù)之后,我們?cè)?外圍函數(shù)體內(nèi)返回 內(nèi)嵌函數(shù)
                            # 需要注意的是,這里是不執(zhí)行的(因?yàn)闆](méi)有加括號(hào)),這是裝飾器的定義規(guī)則,是必不可少的
                            # 只有外圍函數(shù)返回內(nèi)嵌函數(shù),才可以被之后的代碼執(zhí)行;(因?yàn)樗械臉I(yè)務(wù)都在內(nèi)嵌函數(shù)中,不返回就無(wú)法執(zhí)行調(diào)用)

裝飾器的用法

在我們?nèi)粘9ぷ髦?,裝飾器的使用方法有兩種。

第一種:將被調(diào)用的函數(shù)直接作用為參數(shù)傳入裝飾器的外圍函數(shù)括弧內(nèi);示例如下:

def a(func):
    
    def b(*args, **kwargs):
        return func(*args, **kwargs)
    
    return b


def c(name):
    print(name)
    

a(c)('Neo')

# >>> 執(zhí)行結(jié)果如下:
# >>> Neo

第二種:將裝飾器與被調(diào)用函數(shù)綁定在一起, @ 符號(hào) + 裝飾器函數(shù)放在被調(diào)用函數(shù)的上一行,被調(diào)用的函數(shù)正常定義,只需要直接調(diào)用被執(zhí)行函數(shù)即可。示例如下:

def a(func):
    
    def b(*args, **kwargs):
        return func(*args, **kwargs)
    
    return b


@a
def c(name):
    print(name)
    
    
c('Neo')

# >>> 執(zhí)行結(jié)果如下:
# >>> Neo

最常用的裝飾器用法為第二種。

現(xiàn)在我們構(gòu)建一個(gè) 檢查字符串類(lèi)型的裝飾器,加深一下對(duì)裝飾器的理解。

def check_ok(func):

    def inner(*args, **kwargs):
        result = func(*args, **kwargs)
        if result == 'OK':
            return '傳入的參數(shù)數(shù)據(jù)為:\'%s\'' % result
        else:
            return '傳入的參數(shù)數(shù)據(jù)不為:\'OK\''

    return inner


@check_ok
def test_str(data):
    return data


result = test_str('OK')
print(result)

# >>> 執(zhí)行結(jié)果如下:
# >>> 傳入的參數(shù)數(shù)據(jù)為:'OK'

result = test_str('NO')
print(result)

# >>> 執(zhí)行結(jié)果如下:
# >>> 傳入的參數(shù)數(shù)據(jù)不為:'OK'

以上就是一個(gè)裝飾器的簡(jiǎn)單用法,后續(xù)的學(xué)習(xí)內(nèi)容會(huì)接觸到更多的高級(jí)用法。

類(lèi)中的裝飾器

類(lèi)的裝飾器 - classmethod

classmethod 的功能:可以將類(lèi)函數(shù)不經(jīng)過(guò)實(shí)例化即可直接被調(diào)用

classmethod 的用法:示例如下

@classmethod
def func(cls, ...):
    todo
    
# >>> cls 替代普通類(lèi)函數(shù)中的 self ;
# >>> 變更為 cls ,表示當(dāng)前的類(lèi)
# >>> self 代表的是 實(shí)例化對(duì)象,所以只有通過(guò)實(shí)例化后,才可以調(diào)用
# >>> cls 代表的是 類(lèi) ,所以即使不通過(guò)實(shí)例化,也可以調(diào)用 


# *****************************************************


class Test(object):

    @classmethod
    def add(cls, a, b):
        return a + b


print(Test.add(1, 3))

# >>> 執(zhí)行結(jié)果如下:
# >>> 4

演示案例:

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜歡吃魚(yú)')

    @classmethod
    def work(cls):
        print('會(huì)抓老鼠')


dragonLi = Cat('貍花貓')
print(dragonLi.eat(), dragonLi.work())

# >>> 執(zhí)行結(jié)果如下:
# >>> 貍花貓 喜歡吃魚(yú)
# >>> 會(huì)抓老鼠

接下來(lái)我們不使用 類(lèi)的實(shí)例化 ,直接使用 類(lèi) 調(diào)用 eat() 函數(shù) 與 work() 函數(shù)

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜歡吃魚(yú)')

    @classmethod
    def work(cls):
        print('會(huì)抓老鼠')


dragonLi = Cat('貍花貓')

Cat.eat()

# >>> 執(zhí)行結(jié)果如下:
# >>> TypeError: Cat.eat() missing 1 required positional argument: 'self'
# >>> 報(bào)錯(cuò)缺少重要參數(shù) 'self'  (沒(méi)有進(jìn)行實(shí)例化的類(lèi),類(lèi)無(wú)法直接調(diào)用類(lèi)函數(shù))

Cat.work()
# >>> 執(zhí)行結(jié)果如下:
# >>> 會(huì)抓老鼠
# >>> 綁定了 classmethod 裝飾器 的 work() 函數(shù),即使沒(méi)有實(shí)例化,也可以直接被 類(lèi) 調(diào)用

再?lài)L試一下看看 沒(méi)有裝飾器的 eat() 函數(shù) 與 使用了 classmethod 裝飾器 work() 之間可不可以互相調(diào)用

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜歡吃魚(yú)')

    @classmethod
    def work(cls):
        print('會(huì)抓老鼠')
        cls.eat()			# 在 classmethod 裝飾器的 work() 函數(shù)內(nèi) 調(diào)用 eat() 函數(shù)


dragonLi = Cat('貍花貓')
dragonLi.work()

# >>> 執(zhí)行結(jié)果如下:
# >>> TypeError: Cat.eat() missing 1 required positional argument: 'self'
# >>> 同樣報(bào)錯(cuò)缺少重要參數(shù) 'self' 
class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜歡吃魚(yú)')
        self.work()

    @classmethod
    def work(cls):
        print('會(huì)抓老鼠')


dragonLi01 = Cat('貍花貓')
dragonLi01.eat()

# >>> 執(zhí)行結(jié)果如下:
# >>> 執(zhí)行結(jié)果如下:
# >>> 貍花貓 喜歡吃魚(yú)
# >>> 會(huì)抓老鼠

綜合以上兩個(gè)場(chǎng)景,我們得出以下結(jié)論:

  • 在帶有 classmethod 裝飾器 的 函數(shù) 內(nèi),是無(wú)法調(diào)用普通的 帶有 self 的函數(shù)的
  • 但是在普通的帶有 self 的類(lèi)函數(shù)內(nèi),是可以調(diào)用帶有 classmethod 裝飾器 的 函數(shù)的

類(lèi)的裝飾器 - staticmethod

staticmethod 的功能:可以將 類(lèi)函數(shù) 不經(jīng)過(guò)實(shí)例化而直接被調(diào)用,被該裝飾器調(diào)用的函數(shù)不需要傳入 self 、cls 參數(shù),并且無(wú)法在該函數(shù)內(nèi)調(diào)用其他 類(lèi)函數(shù) 或 類(lèi)變量

staticmethod 的用法:參考如下

@staticmethod
def func(...):
    todo
    
# >>> 函數(shù)內(nèi)無(wú)需傳入 cls 或 self 參數(shù)


# *****************************************************


class Test(object):
    
    @staticmethod
    def add(a, b):
        return a + b


print(Test.add(1, 3))

# >>> 執(zhí)行結(jié)果如下:
# >>> 4

接下來(lái)我們?cè)谏衔牡?Cat() 類(lèi)基礎(chǔ)演示一下 staticmethod 裝飾器 (新建一個(gè) color() 函數(shù),使用 staticmethod 裝飾器 )

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜歡吃魚(yú)')
        self.work()

    @classmethod
    def work(cls):
        print('會(huì)抓老鼠')

    @staticmethod
    def color():
        print('黃棕色')


dragonLi = Cat('貍花貓')
print(dragonLi.eat(), dragonLi.color())

# >>> 執(zhí)行結(jié)果如下:
# >>> 貍花貓 喜歡吃魚(yú)
# >>> 會(huì)抓老鼠
# >>> 黃棕色
# >>> 從執(zhí)行結(jié)果來(lái)看, staticmethod 裝飾器的 color() 函數(shù)可以被實(shí)例化后的對(duì)象 dragonLi 調(diào)用。
# >>> 那么可以被 Cat() 類(lèi) 直接調(diào)用么?我們往下看


print(Cat.color())

# >>> 執(zhí)行結(jié)果如下:
# >>> 黃棕色
# >>> 可以看到,staticmethod 裝飾器構(gòu)造的 color() 函數(shù),即使沒(méi)有被實(shí)例化,依然可以直接被 類(lèi) 調(diào)用

同樣的,也嘗試一下 staticmethod 裝飾器構(gòu)造的 color() 函數(shù) 是否能夠在類(lèi)函數(shù)中互相調(diào)用。

class Cat(object):
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(self.name, '喜歡吃魚(yú)')
        self.work()
        self.color()

    @classmethod
    def work(cls):
        print('會(huì)抓老鼠')

    @staticmethod
    def color():
        print('黃棕色')


dragonLi = Cat('貍花貓')
dragonLi.eat()

# >>> 執(zhí)行結(jié)果如下:
# >>> 貍花貓 喜歡吃魚(yú)
# >>> 會(huì)抓老鼠
# >>> 黃棕色				
# >>> 結(jié)合執(zhí)行結(jié)果得出結(jié)論:staticmethod 裝飾器構(gòu)造的 color() 函數(shù) 可以在 eat() 類(lèi)函數(shù)中被調(diào)用

與帶有 classmethod 裝飾器 的 函數(shù) 一樣,staticmethod 裝飾器構(gòu)造的 函數(shù)也是無(wú)法調(diào)用普通的 帶有 self 的函數(shù)的,這里就不再書(shū)寫(xiě)演示代碼進(jìn)行演示了。(staticmethod 裝飾器構(gòu)造的 函數(shù)也是無(wú)法調(diào)用普通的 帶有 self 的函數(shù)會(huì)報(bào)錯(cuò) : NameError: name 'self' is not defined )

類(lèi)的裝飾器 - property

property 的功能:可以將類(lèi)函數(shù)的執(zhí)行免去小括號(hào),類(lèi)似于直接調(diào)用類(lèi)的變量(屬性)

staticmethod 的用法:參考如下

@property
def func(self):
    todo
    
# >>> 不能傳入?yún)?shù),無(wú)重要函數(shù)說(shuō)明


# *************************示例如下*************************


class Test(object):

    def __init__(self, name):
        self.name = name

    @property
    def call_name(self):
        return 'Hello {}'.format(self.name)


test = Test('Neo')
result = test.call_name			# 不需要添加 小括號(hào) 即可調(diào)用 call_name 函數(shù);
								# 關(guān)于 staticmethod 不可傳入?yún)?shù),其實(shí)并不是不可以傳入?yún)?shù),而是傳入的方法比較另類(lèi),我們繼續(xù)往下看
print(result)

# >>> 執(zhí)行結(jié)果如下:
# >>> Hello Neo

重新創(chuàng)建一個(gè) Dog 類(lèi) ,然后我們繼續(xù)演示。

class Dog(object):

    def __init__(self, name):
        self.__name = name

    @property
    def type(self):
        if self.__name in ['哈士奇', '薩摩耶', '阿拉斯基']:
            return self.__name, '是雪橇犬,\'雪橇三傻\'之一'
        elif self.__name in ['吉娃娃', '博美犬', '約克夏']:
            return self.__name, '是小型犬'
        else:
            return self.__name, '我暫時(shí)不知道這是什么犬種,也許它是\'泰日天\'的親戚'


dog = Dog(name='哈士奇')
print(dog.type)			# 這里我們并不需要 dog.type + () 小括號(hào),即可調(diào)用 type() 函數(shù)

# >>> 執(zhí)行結(jié)果如下:
# >>> ('哈士奇', "是雪橇犬,'雪橇三傻'之一")
# >>> 這里我們看到 當(dāng) Dog 類(lèi) 實(shí)例化 dog 變量之后,我們傳入的 '哈士奇' 參數(shù)是不可更改的,如果我們嘗試?yán)觅x值的方式修改傳入的參數(shù)呢?

dog = Dog(name='哈士奇')
dog.type = '約克夏'
print(dog.type)

# >>> 執(zhí)行結(jié)果如下:
# >>> AttributeError: can't set attribute
# >>> 報(bào)錯(cuò):屬性錯(cuò)誤,不可以設(shè)置這個(gè)屬性
# >>> 其實(shí),property 裝飾器綁定的函數(shù)的參數(shù)并不是不可以更改,只是更改的方式比較特殊,并不是不能通過(guò)賦值的形式傳入?yún)?shù),我們繼續(xù)往下看。

首先,我們已經(jīng)使用了 @property 綁定了我們的 type 函數(shù),這是一個(gè)返回值的方法。 所以我們要如何給 type() 函數(shù)賦值呢?其實(shí)很簡(jiǎn)單,我們可以通過(guò) @type 對(duì)應(yīng)上 type() 函數(shù),在它的函數(shù)內(nèi)部有一個(gè)函數(shù) setter ;然后再定義一個(gè) type 函數(shù),在這個(gè)新定義的 type() 函數(shù)內(nèi)定義一個(gè)值 value (可以是任意的名字,但這里需要注意,只能定義一個(gè)值)。然后再通過(guò)設(shè)置一個(gè) self.__name = value ,如此就可以達(dá)到修改傳入?yún)?shù)的目的。廢話(huà)不多說(shuō)了,看下方的示例:

class Dog(object):

    def __init__(self, name):
        self.__name = name

    @property
    def type(self):
        if self.__name in ['哈士奇', '薩摩耶', '阿拉斯基']:
            return self.__name, '是雪橇犬,\'雪橇三傻\'之一'
        elif self.__name in ['吉娃娃', '博美犬', '約克夏']:
            return self.__name, '是小型犬'
        else:
            return self.__name, '我暫時(shí)不知道這是什么犬種,也許它是\'泰日天\'的親戚'

    @type.setter
    def type(self, value):
        self.__name = value


dog = Dog(name='哈士奇')
dog.type = '約克夏'
print(dog.type)

# >>> 執(zhí)行結(jié)果如下:
# >>> ('約克夏', '是小型犬')

附:使用最廣泛的裝飾器為 classmethod

以上就是Python學(xué)習(xí)之裝飾器與類(lèi)的裝飾器詳解的詳細(xì)內(nèi)容,更多關(guān)于Python裝飾器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • opencv實(shí)現(xiàn)圖片模糊和銳化操作

    opencv實(shí)現(xiàn)圖片模糊和銳化操作

    這篇文章主要為大家詳細(xì)介紹了opencv實(shí)現(xiàn)圖片模糊和銳化操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • Python如何實(shí)現(xiàn)定時(shí)器功能

    Python如何實(shí)現(xiàn)定時(shí)器功能

    在本篇文章里小編給大家分享的是關(guān)于Python中的簡(jiǎn)單定時(shí)器實(shí)例及代碼,需要的朋友們可以學(xué)習(xí)下。
    2020-05-05
  • Scrapy模擬登錄趕集網(wǎng)的實(shí)現(xiàn)代碼

    Scrapy模擬登錄趕集網(wǎng)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Scrapy模擬登錄趕集網(wǎng)的實(shí)現(xiàn)代碼,本文通過(guò)代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • VScode查看python f.write()的文件亂碼問(wèn)題及解決方法

    VScode查看python f.write()的文件亂碼問(wèn)題及解決方法

    這篇文章主要介紹了VScode查看python f.write()的文件亂碼問(wèn)題及解決方法,本文通過(guò)圖文并茂的形式給大家分享解決方法,需要的朋友可以參考下
    2023-02-02
  • 深入解析Python的Tornado框架中內(nèi)置的模板引擎

    深入解析Python的Tornado框架中內(nèi)置的模板引擎

    模板引擎是Web開(kāi)發(fā)框架中負(fù)責(zé)前端展示的關(guān)鍵,這里我們就來(lái)以實(shí)例深入解析Python的Tornado框架中內(nèi)置的模板引擎,來(lái)學(xué)習(xí)如何編寫(xiě)Tonardo的模板.
    2016-07-07
  • python 下載m3u8視頻的示例代碼

    python 下載m3u8視頻的示例代碼

    這篇文章主要介紹了python 下載m3u8視頻的示例代碼,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-11-11
  • python輕松實(shí)現(xiàn)代碼編碼格式轉(zhuǎn)換

    python輕松實(shí)現(xiàn)代碼編碼格式轉(zhuǎn)換

    由于某些原因,需要將代碼從A機(jī)房遷移到B機(jī)房,這兩個(gè)之間不能互相訪(fǎng)問(wèn),但是歷史原因?qū)е翧機(jī)房的代碼全是utf8編碼的,B機(jī)房要求是GBK編碼,看看這個(gè)怎么解決。雖然很簡(jiǎn)單,但是還是要推薦給大家,需要的小伙伴參考下吧。
    2015-03-03
  • 基于python log取對(duì)數(shù)詳解

    基于python log取對(duì)數(shù)詳解

    今天小編就為大家分享一篇基于python log取對(duì)數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • 查看Django和flask版本的方法

    查看Django和flask版本的方法

    今天小編就為大家分享一篇查看Django和flask版本的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • python使用裝飾器和線(xiàn)程限制函數(shù)執(zhí)行時(shí)間的方法

    python使用裝飾器和線(xiàn)程限制函數(shù)執(zhí)行時(shí)間的方法

    這篇文章主要介紹了python使用裝飾器和線(xiàn)程限制函數(shù)執(zhí)行時(shí)間的方法,主要涉及timelimited函數(shù)的使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-04-04

最新評(píng)論