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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

90 % 的 Python 开发者不知道的描述符应用

發布時間:2024/1/17 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 90 % 的 Python 开发者不知道的描述符应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

好吧,我承認我標題黨了。但是這篇文章的知識點,你有極大的可能并不知道。

前段時間,我寫了一篇描述符的入門級文章,從那些文章里你知道了如何定義描述符,且明白了描述符是如何工作的。

如果你還未學習,可以點擊這里進行閱讀:Python為什么要使用描述符

正常人所見過的描述符的用法就是上篇文章提到的那些,我想說的是那只是描述符協議最常見的應用之一,或許你還不知道,其實有很多 Python 的特性的底層實現機制都是基于 描述符協議 的,比如我們熟悉的@property 、@classmethod 、@staticmethod 和 super 等。

這些裝飾器方法,你絕對熟悉得不得了,但是今天并不是要講他們的用法,而是要講是如何自己通過 純Python 實現這些特性。

先來說說 property 吧。

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

class Student:def __init__(self, name):self.name = name @propertydef math(self):return self._math @math.setterdef math(self, value):if 0 <= value <= 100:self._math = valueelse:raise ValueError("Valid value must be in [0, 100]") 復制代碼

不防再簡單回顧一下它的用法,通過property裝飾的函數,如例子中的 math 會變成 Student 實例的屬性。而對 math 屬性賦值會進入 使用 math.setter 裝飾函數的邏輯代碼塊。

為什么說 property 底層是基于描述符協議的呢?通過 PyCharm 點擊進入 property 的源碼,很可惜,只是一份類似文檔一樣的偽源碼,并沒有其具體的實現邏輯。

不過,從這份偽源碼的魔法函數結構組成,可以大體知道其實現邏輯。

這里我自己通過模仿其函數結構,結合「描述符協議」來自己實現類 property 特性。

代碼如下:

class TestProperty(object):def __init__(self, fget=None, fset=None, fdel=None, doc=None):self.fget = fgetself.fset = fsetself.fdel = fdelself.__doc__ = docdef __get__(self, obj, objtype=None):print("in __get__")if obj is None:return selfif self.fget is None:raise AttributeErrorreturn self.fget(obj)def __set__(self, obj, value):print("in __set__")if self.fset is None:raise AttributeErrorself.fset(obj, value)def __delete__(self, obj):print("in __delete__")if self.fdel is None:raise AttributeErrorself.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 類,我們也相應改成如下

class Student:def __init__(self, name):self.name = name# 其實只有這里改變 @TestPropertydef math(self):return self._math @math.setterdef math(self, value):if 0 <= value <= 100:self._math = valueelse:raise ValueError("Valid value must be in [0, 100]") 復制代碼

為了盡量讓你少產生一點疑惑,我這里做兩點說明:

  • 使用TestProperty裝飾后,math 不再是一個函數,而是TestProperty 類的一個實例。所以第二個math函數可以使用 math.setter 來裝飾,本質是調用TestProperty.setter 來產生一個新的 TestProperty 實例賦值給第二個math。

  • 第一個 math 和第二個 math 是兩個不同 TestProperty 實例。但他們都屬于同一個描述符類(TestProperty),當對 math 對于賦值時,就會進入 TestProperty.__set__,當對math 進行取值里,就會進入 TestProperty.__get__。仔細一看,其實最終訪問的還是Student實例的 _math 屬性。

  • 說了這么多,還是運行一下,更加直觀一點。

    # 運行后,會直接打印這一行,這是在實例化 TestProperty 并賦值給第二個math in setter >>> >>> s1.math = 90 in __set__ >>> s1.math in __get__ 90 復制代碼

    對于以上理解 property 的運行原理有困難的同學,請務必參照我上面寫的兩點說明。如有其他疑問,可以加微信與我進行探討。

    1.17.4 基于描述符如何實現staticmethod

    說完了 property ,這里再來講講 @classmethod 和 @staticmethod 的實現原理。

    我這里定義了一個類,用了兩種方式來實現靜態方法。

    class Test: @staticmethoddef myfunc():print("hello")# 上下兩種寫法等價class Test:def myfunc():print("hello")# 重點:這就是描述符的體現myfunc = staticmethod(myfunc) 復制代碼

    這兩種寫法是等價的,就好像在 property 一樣,其實以下兩種寫法也是等價的。

    @TestProperty def math(self):return self._mathmath = TestProperty(fget=math) 復制代碼

    話題還是轉回到 staticmethod 這邊來吧。

    由上面的注釋,可以看出 staticmethod 其實就相當于一個描述符類,而myfunc 在此刻變成了一個描述符。關于 staticmethod 的實現,你可以參照下面這段我自己寫的代碼,加以理解。

    調用這個方法可以知道,每調用一次,它都會經過描述符類的 __get__ 。

    >>> Test.myfunc() in staticmethod __get__ hello >>> Test().myfunc() in staticmethod __get__ hello 復制代碼

    1.17.4 基于描述符如何實現classmethod

    同樣的 classmethod 也是一樣。

    class classmethod(object):def __init__(self, f):self.f = fdef __get__(self, instance, owner=None):print("in classmethod __get__")def newfunc(*args):return self.f(owner, *args)return newfuncclass Test:def myfunc(cls):print("hello")# 重點:這就是描述符的體現myfunc = classmethod(myfunc) 復制代碼

    驗證結果如下

    >>> Test.myfunc() in classmethod __get__ hello >>> Test().myfunc() in classmethod __get__ hello 復制代碼

    講完了 property、staticmethod和classmethod 與 描述符的關系。我想你應該對描述符在 Python 中的應用有了更深的理解。對于 super 的實現原理,就交由你來自己完成。


    總結

    以上是生活随笔為你收集整理的90 % 的 Python 开发者不知道的描述符应用的全部內容,希望文章能夠幫你解決所遇到的問題。

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