成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

90 % 的 Python 開(kāi)發(fā)者不知道的描述符應(yīng)用

0x584a / 2836人閱讀

摘要:由上面的注釋?zhuān)梢钥闯銎鋵?shí)就相當(dāng)于一個(gè)描述符類(lèi),而在此刻變成了一個(gè)描述符。調(diào)用這個(gè)方法可以知道,每調(diào)用一次,它都會(huì)經(jīng)過(guò)描述符類(lèi)的?;诿枋龇绾螌?shí)現(xiàn)同樣的也是一樣。我想你應(yīng)該對(duì)描述符在中的應(yīng)用有了更深的理解。

好吧,我承認(rèn)我標(biāo)題黨了。但是這篇文章的知識(shí)點(diǎn),你有極大的可能并不知道。

前段時(shí)間,我寫(xiě)了一篇描述符的入門(mén)級(jí)文章,從那些文章里你知道了如何定義描述符,且明白了描述符是如何工作的。

如果你還未學(xué)習(xí),可以點(diǎn)擊這里進(jìn)行閱讀:Python為什么要使用描述符

正常人所見(jiàn)過(guò)的描述符的用法就是上篇文章提到的那些,我想說(shuō)的是那只是描述符協(xié)議最常見(jiàn)的應(yīng)用之一,或許你還不知道,其實(shí)有很多 Python 的特性的底層實(shí)現(xiàn)機(jī)制都是基于 描述符協(xié)議 的,比如我們熟悉的@property 、@classmethod@staticmethodsuper 等。

這些裝飾器方法,你絕對(duì)熟悉得不得了,但是今天并不是要講他們的用法,而是要講是如何自己通過(guò) 純Python 實(shí)現(xiàn)這些特性。

先來(lái)說(shuō)說(shuō) property 吧。

有了第一篇的基礎(chǔ),我們知道了 property 的基本用法。這里我直接切入主題,從第一篇的例子里精簡(jiǎn)了一下。

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

    @property
    def math(self):
        return self._math

    @math.setter
    def math(self, value):
        if 0 <= value <= 100:
            self._math = value
        else:
            raise ValueError("Valid value must be in [0, 100]")

不防再簡(jiǎn)單回顧一下它的用法,通過(guò)property裝飾的函數(shù),如例子中的 math 會(huì)變成 Student 實(shí)例的屬性。而對(duì) math 屬性賦值會(huì)進(jìn)入 使用 math.setter 裝飾函數(shù)的邏輯代碼塊。

為什么說(shuō) property 底層是基于描述符協(xié)議的呢?通過(guò) PyCharm 點(diǎn)擊進(jìn)入 property 的源碼,很可惜,只是一份類(lèi)似文檔一樣的偽源碼,并沒(méi)有其具體的實(shí)現(xiàn)邏輯。

不過(guò),從這份偽源碼的魔法函數(shù)結(jié)構(gòu)組成,可以大體知道其實(shí)現(xiàn)邏輯。

這里我自己通過(guò)模仿其函數(shù)結(jié)構(gòu),結(jié)合「描述符協(xié)議」來(lái)自己實(shí)現(xiàn)類(lèi) property 特性。

代碼如下:

class TestProperty(object):

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        print("in __get__")
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError
        return self.fget(obj)

    def __set__(self, obj, value):
        print("in __set__")
        if self.fset is None:
            raise AttributeError
        self.fset(obj, value)

    def __delete__(self, obj):
        print("in __delete__")
        if self.fdel is None:
            raise AttributeError
        self.fdel(obj)


    def getter(self, fget):
        print("in getter")
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        print("in setter")
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        print("in deleter")
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

然后 Student 類(lèi),我們也相應(yīng)改成如下

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

    # 其實(shí)只有這里改變
    @TestProperty
    def math(self):
        return self._math

    @math.setter
    def math(self, value):
        if 0 <= value <= 100:
            self._math = value
        else:
            raise ValueError("Valid value must be in [0, 100]")

為了盡量讓你少產(chǎn)生一點(diǎn)疑惑,我這里做兩點(diǎn)說(shuō)明:

    使用TestProperty裝飾后,math 不再是一個(gè)函數(shù),而是TestProperty 類(lèi)的一個(gè)實(shí)例。所以第二個(gè)math函數(shù)可以使用 math.setter 來(lái)裝飾,本質(zhì)是調(diào)用TestProperty.setter 來(lái)產(chǎn)生一個(gè)新的 TestProperty 實(shí)例賦值給第二個(gè)math。

    第一個(gè) math 和第二個(gè) math 是兩個(gè)不同 TestProperty 實(shí)例。但他們都屬于同一個(gè)描述符類(lèi)(TestProperty),當(dāng)對(duì) math 對(duì)于賦值時(shí),就會(huì)進(jìn)入 TestProperty.__set__,當(dāng)對(duì)math 進(jìn)行取值里,就會(huì)進(jìn)入 TestProperty.__get__。仔細(xì)一看,其實(shí)最終訪問(wèn)的還是Student實(shí)例的 _math 屬性。

說(shuō)了這么多,還是運(yùn)行一下,更加直觀一點(diǎn)。

# 運(yùn)行后,會(huì)直接打印這一行,這是在實(shí)例化 TestProperty 并賦值給第二個(gè)math
in setter
>>>
>>> s1.math = 90
in __set__
>>> s1.math
in __get__
90

對(duì)于以上理解 property 的運(yùn)行原理有困難的同學(xué),請(qǐng)務(wù)必參照我上面寫(xiě)的兩點(diǎn)說(shuō)明。如有其他疑問(wèn),可以加微信與我進(jìn)行探討。

1.17.4 基于描述符如何實(shí)現(xiàn)staticmethod

說(shuō)完了 property ,這里再來(lái)講講 @classmethod@staticmethod 的實(shí)現(xiàn)原理。

我這里定義了一個(gè)類(lèi),用了兩種方式來(lái)實(shí)現(xiàn)靜態(tài)方法。

class Test:
    @staticmethod
    def myfunc():
        print("hello")

# 上下兩種寫(xiě)法等價(jià)

class Test:
    def myfunc():
        print("hello")
    # 重點(diǎn):這就是描述符的體現(xiàn)
    myfunc = staticmethod(myfunc)

這兩種寫(xiě)法是等價(jià)的,就好像在 property 一樣,其實(shí)以下兩種寫(xiě)法也是等價(jià)的。

@TestProperty
def math(self):
    return self._math
  
math = TestProperty(fget=math)

話(huà)題還是轉(zhuǎn)回到 staticmethod 這邊來(lái)吧。

由上面的注釋?zhuān)梢钥闯?staticmethod 其實(shí)就相當(dāng)于一個(gè)描述符類(lèi),而myfunc 在此刻變成了一個(gè)描述符。關(guān)于 staticmethod 的實(shí)現(xiàn),你可以參照下面這段我自己寫(xiě)的代碼,加以理解。

調(diào)用這個(gè)方法可以知道,每調(diào)用一次,它都會(huì)經(jīng)過(guò)描述符類(lèi)的 __get__ 。

>>> Test.myfunc()
in staticmethod __get__
hello
>>> Test().myfunc()
in staticmethod __get__
hello
1.17.4 基于描述符如何實(shí)現(xiàn)classmethod

同樣的 classmethod 也是一樣。

class classmethod(object):
    def __init__(self, f):
        self.f = f

    def __get__(self, instance, owner=None):
        print("in classmethod __get__")
        
        def newfunc(*args):
            return self.f(owner, *args)
        return newfunc

class Test:
    def myfunc(cls):
        print("hello")
        
    # 重點(diǎn):這就是描述符的體現(xiàn)
    myfunc = classmethod(myfunc)

驗(yàn)證結(jié)果如下

>>> Test.myfunc()
in classmethod __get__
hello
>>> Test().myfunc()
in classmethod __get__
hello

講完了 propertystaticmethodclassmethod 與 描述符的關(guān)系。我想你應(yīng)該對(duì)描述符在 Python 中的應(yīng)用有了更深的理解。對(duì)于 super 的實(shí)現(xiàn)原理,就交由你來(lái)自己完成。


文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/6982.html

相關(guān)文章

  • 90 % Python 開(kāi)發(fā)者知道描述應(yīng)用

    摘要:由上面的注釋?zhuān)梢钥闯銎鋵?shí)就相當(dāng)于一個(gè)描述符類(lèi),而在此刻變成了一個(gè)描述符。調(diào)用這個(gè)方法可以知道,每調(diào)用一次,它都會(huì)經(jīng)過(guò)描述符類(lèi)的?;诿枋龇绾螌?shí)現(xiàn)同樣的也是一樣。我想你應(yīng)該對(duì)描述符在中的應(yīng)用有了更深的理解。好吧,我承認(rèn)我標(biāo)題黨了。但是這篇文章的知識(shí)點(diǎn),你有極大的可能并不知道。 前段時(shí)間,我寫(xiě)了一篇描述符的入門(mén)級(jí)文章,從那些文章里你知道了如何定義描述符,且明白了描述符是如何工作的。 如果你還...

    番茄西紅柿 評(píng)論0 收藏0
  • Python descriptor(上)

    摘要:事實(shí)上實(shí)例的實(shí)現(xiàn)方式與上面的實(shí)例類(lèi)似。其次,為了實(shí)現(xiàn)確實(shí)對(duì)屬性的調(diào)用順序做出了相應(yīng)的調(diào)整,這些將會(huì)的下中介紹。參考資料如何理解的中基于的一些概念上中基于的一些概念下的官方文檔描述符解密的官方文檔 Python 在 2.2 版本中引入了descriptor(描述符)功能,也正是基于這個(gè)功能實(shí)現(xiàn)了新式類(lèi)(new-styel class)的對(duì)象模型,同時(shí)解決了之前版本中經(jīng)典類(lèi) (classi...

    yexiaobai 評(píng)論0 收藏0
  • Bottle框架中裝飾器類(lèi)和描述應(yīng)用

    摘要:最近在閱讀微型框架的源碼,發(fā)現(xiàn)了中有一個(gè)既是裝飾器類(lèi)又是描述符的有趣實(shí)現(xiàn)。所以第三版的代碼可以這樣寫(xiě)第三版的代碼沒(méi)有使用裝飾器,而是使用了描述符這個(gè)技巧。更大的問(wèn)題來(lái)自如何將描述符與裝飾器結(jié)合起來(lái),因?yàn)槭且粋€(gè)類(lèi)而不是方法。 最近在閱讀Python微型Web框架Bottle的源碼,發(fā)現(xiàn)了Bottle中有一個(gè)既是裝飾器類(lèi)又是描述符的有趣實(shí)現(xiàn)。剛好這兩個(gè)點(diǎn)是Python比較的難理解,又混合在...

    Panda 評(píng)論0 收藏0
  • python 描述解析

    摘要:之所以是這樣是因?yàn)楫?dāng)訪問(wèn)一個(gè)實(shí)例描述符對(duì)象時(shí),會(huì)將轉(zhuǎn)換為。而類(lèi)的字典中則有描述符對(duì)象。這主要就是因?yàn)槊枋龇麅?yōu)先。此外,非數(shù)據(jù)描述符的優(yōu)先級(jí)低于實(shí)例屬性。參考以上就是本人對(duì)描述符的一些理解,有什么不正確的地方還請(qǐng)不吝指出,謝謝 什么是描述符 python描述符是一個(gè)綁定行為的對(duì)象屬性,在描述符協(xié)議中,它可以通過(guò)方法重寫(xiě)屬性的訪問(wèn)。這些方法有 __get__(), __set__(), 和...

    rozbo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<