国产乱子伦高清露脸对白-国产精品欧美久久久久天天影视-国产91视频一区-亚洲欧美日产综合在线网-黄视频网站在线看-国产欧美亚洲精品第1页-亚洲www在线-大学生女人三级在线播放-日本在线视频www鲁啊鲁-国产成人精品一区二区仙踪林-69精品欧美一区二区三区-成人欧美亚洲-日本污污网站-中国妞xxxhd露脸偷拍视频-国产精品aⅴ在线观看-精品中文字幕在线

極客小將

您現(xiàn)在的位置是:首頁 » python編程資訊

資訊內(nèi)容

介紹python描述符的意義

極客小將2021-01-17-
簡介你也許經(jīng)常會聽到「描述符」這個概念,但是由于大多數(shù)的程序員很少會使用到他,所以可能你并不太清楚了解它的原理,python視頻教程欄目將詳細(xì)介紹推薦(免費(fèi)):python視頻教程但是如果你想自己的事業(yè)來說更上一層的話,對于python的使用更加熟練的話,我認(rèn)為你還是應(yīng)該對描述符的這個概念有一個清晰的了
www.pxcodes.com 你也許經(jīng)常會聽到「描述符」這個概念,但是由于大多數(shù)的程序員很少會使用到他,所以可能你并不太清楚了解它的原理,python視頻教程欄目將詳細(xì)介紹Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

推薦(免費(fèi)):python視頻教程Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

但是如果你想自己的事業(yè)來說更上一層的話,對于python的使用更加熟練的話,我認(rèn)為你還是應(yīng)該對描述符的這個概念有一個清晰的了解,這對于你以后的發(fā)展有著巨大的幫助,也有利于你將來更深層次的python設(shè)計(jì)的理解。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

盡管在開發(fā)的過程中,我們沒有直接的使用過描述符,但是它在底層的運(yùn)用卻是十分頻繁的存在。例如下面的這些:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

function 、bound method 、unbound method裝是器property 、staticmethod 、classmethod
這些是不是都很熟悉?
其實(shí)這些都與描述符有著千絲萬縷的聯(lián)系,這樣吧,我們通過下面的文章來探討一下描述符背后的工作原理吧。

什么是描述符?Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

在我們了解什么是描述符前,我們可以先找一個例子來看一下Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class A: x = 10print(A.x) # 10

這個例子很簡單,我們先在類A中定義一個類屬性x,然后得出它的值。
除了這種直接定義類屬性的方法外,我們還可以這樣去定義一個類屬性:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class Ten: def __get__(self, obj, objtype=None): return 10class A: x = Ten() # 屬性換成了一個類print(A.x) # 10

我們可以發(fā)現(xiàn),這回的類屬性x不是一個具體的值了,而是一個類Ten,通過這個Ten定義了一個__get__方法,返回具體的值。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

因此可得出:在python中,我們可以把一個類的屬性,托管給一個類,而這樣的屬性就是一個描述符
簡而言之,描述符是一個綁定行為屬性Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

而這又有著什么意思呢?
回想,我們在開發(fā)時,一般情況下,會將行為叫做什么?行為即一個方法。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

所以我們也可以將描述符理解為:對象的屬性并非一個具體的值,而是交給了一個方法去定義。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

可以想像一下,如果我們用一個方法去定義一個屬性,這么做有什么好處?Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

有了方法,我們就可以在方法內(nèi)實(shí)現(xiàn)自己的邏輯,**簡單的,我們可以根據(jù)不同的條件,在方法內(nèi)給屬性賦予不同的值,就像下面這樣:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class Age: def __get__(self, obj, objtype=None): if obj.name == 'zhangsan': return 20 elif obj.name == 'lisi': return 25 else: return ValueError("unknow")class Person: age = Age() def __init__(self, name): self.name = name p1 = Person('zhangsan')print(p1.age) # 20p2 = Person('lisi')print(p2.age) # 25p3 = Person('wangwu')print(p3.age) # unknow

這個例子中,age 類屬性被另一個類托管了,在這個類的 __get__ 中,它會根據(jù) Person 類的屬性 name,決定 age 是什么值。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

通過這樣一個例子,我們可以看到,通過描述符的使用,我們可以輕易地改變一個類屬性的定義方式。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

描述符協(xié)議Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

了解了描述符的定義,現(xiàn)在我們把重點(diǎn)放到托管屬性的類上。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

其實(shí),一個類屬性想要托管給一個類,這個類內(nèi)部實(shí)現(xiàn)的方法不能是隨便定義的,它必須遵守「描述符協(xié)議」,也就是要實(shí)現(xiàn)以下幾個方法:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

__get__(self, obj, type=None) -> value__set__(self, obj, value) -> None__delete__(self, obj) -> None

只要是實(shí)現(xiàn)了以上幾個方法的其中一個,那么這個類屬性就可以稱作描述符。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

另外,描述符又可以分為「數(shù)據(jù)描述符」和「非數(shù)據(jù)描述符」:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

只定義了 __get___,叫做非數(shù)據(jù)描述符除了定義 __get__ 之外,還定義了 __set__ 或 __delete__,叫做數(shù)據(jù)描述符

它們兩者有什么區(qū)別,我會在下面詳述。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

現(xiàn)在我們來看一個包含 __get__ 和 __set__ 方法的描述符例子:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

# coding: utf8class Age: def __init__(self, value=20): self.value = value def __get__(self, obj, type=None): print('call __get__: obj: %s type: %s' % (obj, type)) return self.value def __set__(self, obj, value): if value <= 0: raise ValueError("age must be greater than 0") print('call __set__: obj: %s value: %s' % (obj, value)) self.value = valueclass Person: age = Age() def __init__(self, name): self.name = name p1 = Person('zhangsan')print(p1.age)# call __get__: obj: <__main__.Person object at 0x1055509e8> type: <class '__main__.Person'># 20print(Person.age)# call __get__: obj: None type: <class '__main__.Person'># 20p1.age = 25# call __set__: obj: <__main__.Person object at 0x1055509e8> value: 25print(p1.age)# call __get__: obj: <__main__.Person object at 0x1055509e8> type: <class '__main__.Person'># 25p1.age = -1# ValueError: age must be greater than 0

在這例子中,類屬性 age 是一個描述符,它的值取決于 Age 類。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

從輸出結(jié)果來看,當(dāng)我們獲取或修改 age 屬性時,調(diào)用了 Age 的 __get__ 和 __set__ 方法:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

當(dāng)調(diào)用 p1.age 時,__get__ 被調(diào)用,參數(shù) obj 是 Person 實(shí)例,type 是 type(Person)當(dāng)調(diào)用 Person.age 時,__get__ 被調(diào)用,參數(shù) obj 是 None,type 是 type(Person)當(dāng)調(diào)用 p1.age = 25時,__set__ 被調(diào)用,參數(shù) obj 是 Person 實(shí)例,value 是25當(dāng)調(diào)用 p1.age = -1時,__set__ 沒有通過校驗(yàn),拋出 ValueError

其中,調(diào)用 __set__ 傳入的參數(shù),我們比較容易理解,但是對于 __get__ 方法,通過類或?qū)嵗{(diào)用,傳入的參數(shù)是不同的,這是為什么?Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

這就需要我們了解一下描述符的工作原理。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

描述符的工作原理Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

要解釋描述符的工作原理,首先我們需要先從屬性的訪問說起。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

在開發(fā)時,不知道你有沒有想過這樣一個問題:通常我們寫這樣的代碼 a.b,其背后到底發(fā)生了什么?Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

這里的 a 和 b 可能存在以下情況:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

a 可能是一個類,也可能是一個實(shí)例,我們這里統(tǒng)稱為對象b 可能是一個屬性,也可能是一個方法,方法其實(shí)也可以看做是類的屬性

其實(shí),無論是以上哪種情況,在 Python 中,都有一個統(tǒng)一的調(diào)用邏輯:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

先調(diào)用 __getattribute__ 嘗試獲得結(jié)果如果沒有結(jié)果,調(diào)用 __getattr__

用代碼表示就是下面這樣:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

def getattr_hook(obj, name): try: return obj.__getattribute__(name) except AttributeError: if not hasattr(type(obj), '__getattr__'): raise return type(obj).__getattr__(obj, name)

我們這里需要重點(diǎn)關(guān)注一下 __getattribute__,因?yàn)樗撬袑傩圆檎业娜肟冢鼉?nèi)部實(shí)現(xiàn)的屬性查找順序是這樣的:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

要查找的屬性,在類中是否是一個描述符如果是描述符,再檢查它是否是一個數(shù)據(jù)描述符如果是數(shù)據(jù)描述符,則調(diào)用數(shù)據(jù)描述符的 __get__如果不是數(shù)據(jù)描述符,則從 __dict__ 中查找如果 __dict__ 中查找不到,再看它是否是一個非數(shù)據(jù)描述符如果是非數(shù)據(jù)描述符,則調(diào)用非數(shù)據(jù)描述符的 __get__如果也不是一個非數(shù)據(jù)描述符,則從類屬性中查找如果類中也沒有這個屬性,拋出 AttributeError 異常

寫成代碼就是下面這樣:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

# 獲取一個對象的屬性 def __getattribute__(obj, name): null = object() # 對象的類型 也就是實(shí)例的類 objtype = type(obj) # 從這個類中獲取指定屬性 cls_var = getattr(objtype, name, null) # 如果這個類實(shí)現(xiàn)了描述符協(xié)議 descr_get = getattr(type(cls_var), '__get__', null) if descr_get is not null: if (hasattr(type(cls_var), '__set__') or hasattr(type(cls_var), '__delete__')): # 優(yōu)先從數(shù)據(jù)描述符中獲取屬性 return descr_get(cls_var, obj, objtype) # 從實(shí)例中獲取屬性 if hasattr(obj, '__dict__') and name in vars(obj): return vars(obj)[name] # 從非數(shù)據(jù)描述符獲取屬性 if descr_get is not null: return descr_get(cls_var, obj, objtype) # 從類中獲取屬性 if cls_var is not null: return cls_var # 拋出 AttributeError 會觸發(fā)調(diào)用 __getattr__ raise AttributeError(name)

如果不好理解,你**好寫一個程序測試一下,觀察各種情況下的屬性的查找順序。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

到這里我們可以看到,在一個對象中查找一個屬性,都是先從 __getattribute__ 開始的。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

在 __getattribute__ 中,它會檢查這個類屬性是否是一個描述符,如果是一個描述符,那么就會調(diào)用它的 __get__ 方法。但具體的調(diào)用細(xì)節(jié)和傳入的參數(shù)是下面這樣的:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

如果 a 是一個實(shí)例,調(diào)用細(xì)節(jié)為:type(a).__dict__['b'].__get__(a, type(a))復(fù)制代碼如果 a 是一個類,調(diào)用細(xì)節(jié)為:a.__dict__['b'].__get__(None, a)復(fù)制代碼

所以我們就能看到上面例子輸出的結(jié)果。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

數(shù)據(jù)描述符和非數(shù)據(jù)描述符Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

了解了描述符的工作原理,我們繼續(xù)來看數(shù)據(jù)描述符和非數(shù)據(jù)描述符的區(qū)別。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

從定義上來看,它們的區(qū)別是:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

只定義了 __get___,叫做非數(shù)據(jù)描述符除了定義 __get__ 之外,還定義了 __set__ 或 __delete__,叫做數(shù)據(jù)描述符

此外,我們從上面描述符調(diào)用的順序可以看到,在對象中查找屬性時,數(shù)據(jù)描述符要優(yōu)先于非數(shù)據(jù)描述符調(diào)用。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

在之前的例子中,我們定義了 __get__ 和 __set__,所以那些類屬性都是數(shù)據(jù)描述符。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

我們再來看一個非數(shù)據(jù)描述符的例子:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class A: def __init__(self): self.foo = 'abc' def foo(self): return 'xyz'print(A().foo) # 輸出什么? 復(fù)制代碼

這段代碼,我們定義了一個相同名字的屬性和方法 foo,如果現(xiàn)在執(zhí)行 A().foo,你覺得會輸出什么結(jié)果?Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

答案是 abc。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

為什么打印的是實(shí)例屬性 foo 的值,而不是方法 foo 呢?Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

這就和非數(shù)據(jù)描述符有關(guān)系了。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

我們執(zhí)行 dir(A.foo),觀察結(jié)果:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

print(dir(A.foo))# [... '__get__', '__getattribute__', ...]復(fù)制代碼

看到了嗎?A 的 foo 方法其實(shí)實(shí)現(xiàn)了 __get__,我們在上面的分析已經(jīng)得知:只定義 __get__ 方法的對象,它其實(shí)是一個非數(shù)據(jù)描述符,也就是說,我們在類中定義的方法,其實(shí)本身就是一個非數(shù)據(jù)描述符。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

所以,在一個類中,如果存在相同名字的屬性和方法,按照上面所講的 __getattribute__ 中查找屬性的順序,這個屬性就會優(yōu)先從實(shí)例中獲取,如果實(shí)例中不存在,才會從非數(shù)據(jù)描述符中獲取,所以在這里優(yōu)先查找的是實(shí)例屬性 foo 的值。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

到這里我們可以總結(jié)一下關(guān)于描述符的相關(guān)知識點(diǎn):Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

描述符必須是一個類屬性__getattribute__ 是查找一個屬性(方法)的入口__getattribute__ 定義了一個屬性(方法)的查找順序:數(shù)據(jù)描述符、實(shí)例屬性、非數(shù)據(jù)描述符、類屬性如果我們重寫了 __getattribute__ 方法,會阻止描述符的調(diào)用所有方法其實(shí)都是一個非數(shù)據(jù)描述符,因?yàn)樗x了 __get__

描述符的使用場景Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

了解了描述符的工作原理,那描述符一般用在哪些業(yè)務(wù)場景中呢?Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

在這里我用描述符實(shí)現(xiàn)了一個屬性校驗(yàn)器,你可以參考這個例子,在類似的場景中去使用它。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

首先我們定義一個校驗(yàn)基類 Validator,在 __set__ 方法中先調(diào)用 validate 方法校驗(yàn)屬性是否符合要求,然后再對屬性進(jìn)行賦值。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class Validator: def __init__(self): self.data = {} def __get__(self, obj, objtype=None): return self.data[obj] def __set__(self, obj, value): # 校驗(yàn)通過后再賦值 self.validate(value) self.data[obj] = value def validate(self, value): pass 復(fù)制代碼

接下來,我們定義兩個校驗(yàn)類,繼承 Validator,然后實(shí)現(xiàn)自己的校驗(yàn)邏輯。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class Number(Validator): def __init__(self, minvalue=None, maxvalue=None): super(Number, self).__init__() self.minvalue = minvalue self.maxvalue = maxvalue def validate(self, value): if not isinstance(value, (int, float)): raise TypeError(f'Expected {value!r} to be an int or float') if self.minvalue is not None and value < self.minvalue: raise ValueError( f'Expected {value!r} to be at least {self.minvalue!r}' ) if self.maxvalue is not None and value > self.maxvalue: raise ValueError( f'Expected {value!r} to be no more than {self.maxvalue!r}' )class String(Validator): def __init__(self, minsize=None, maxsize=None): super(String, self).__init__() self.minsize = minsize self.maxsize = maxsize def validate(self, value): if not isinstance(value, str): raise TypeError(f'Expected {value!r} to be an str') if self.minsize is not None and len(value) < self.minsize: raise ValueError( f'Expected {value!r} to be no smaller than {self.minsize!r}' ) if self.maxsize is not None and len(value) > self.maxsize: raise ValueError( f'Expected {value!r} to be no bigger than {self.maxsize!r}' )復(fù)制代碼

**后,我們使用這個校驗(yàn)類:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class Person: # 定義屬性的校驗(yàn)規(guī)則 內(nèi)部用描述符實(shí)現(xiàn) name = String(minsize=3, maxsize=10) age = Number(minvalue=1, maxvalue=120) def __init__(self, name, age): self.name = name self.age = age # 屬性符合規(guī)則 p1 = Person('zhangsan', 20)print(p1.name, p1.age)# 屬性不符合規(guī)則 p2 = person('a', 20)# ValueError: Expected 'a' to be no smaller than 3p3 = Person('zhangsan', -1)# ValueError: Expected -1 to be at least 1復(fù)制代碼

現(xiàn)在,當(dāng)我們對 Person 實(shí)例進(jìn)行初始化時,就可以校驗(yàn)這些屬性是否符合預(yù)定義的規(guī)則了。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

function與methodIjv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

我們再來看一下,在開發(fā)時經(jīng)常看到的 function、unbound method、bound method 它們之間到底有什么區(qū)別?Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

來看下面這段代碼:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class A: def foo(self): return 'xyz'print(A.__dict__['foo']) # <function foo at 0x10a790d70>print(A.foo) # <unbound method A.foo>print(A().foo) # <bound method A.foo of <__main__.A object at 0x10a793050>>復(fù)制代碼

從結(jié)果我們可以看出它們的區(qū)別:Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

function 準(zhǔn)確來說就是一個函數(shù),并且它實(shí)現(xiàn)了 __get__ 方法,因此每一個 function 都是一個非數(shù)據(jù)描述符,而在類中會把 function 放到 __dict__ 中存儲當(dāng) function 被實(shí)例調(diào)用時,它是一個 bound method當(dāng) function 被類調(diào)用時, 它是一個 unbound method

function 是一個非數(shù)據(jù)描述符,我們之前已經(jīng)講到了。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

而 bound method 和 unbound method 的區(qū)別就在于調(diào)用方的類型是什么,如果是一個實(shí)例,那么這個 function 就是一個 bound method,否則它是一個 unbound method。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

property/staticmethod/classmethodIjv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

我們再來看 property、staticmethod、classmethod。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

這些裝飾器的實(shí)現(xiàn),默認(rèn)是 C 來實(shí)現(xiàn)的。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

其實(shí),我們也可以直接利用 Python 描述符的特性來實(shí)現(xiàn)這些裝飾器,Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

property 的 Python 版實(shí)現(xiàn):Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class property: 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): if obj is None: return self.fget if self.fget is None: raise AttributeError(), "unreadable attribute" return self.fget(obj) def __set__(self, obj, value): if self.fset is None: raise AttributeError, "can't set attribute" return self.fset(obj, value) def __delete__(self, obj): if self.fdel is None: raise AttributeError, "can't delete attribute" return self.fdel(obj) def getter(self, fget): return type(self)(fget, self.fset, self.fdel, self.__doc__) def setter(self, fset): return type(self)(self.fget, fset, self.fdel, self.__doc__) def deleter(self, fdel): return type(self)(self.fget, self.fset, fdel, self.__doc__)復(fù)制代碼

staticmethod 的 Python 版實(shí)現(xiàn):Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class staticmethod: def __init__(self, func): self.func = func def __get__(self, obj, objtype=None): return self.func 復(fù)制代碼

classmethod 的 Python 版實(shí)現(xiàn):Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

class classmethod: def __init__(self, func): self.func = func def __get__(self, obj, klass=None): if klass is None: klass = type(obj) def newfunc(*args): return self.func(klass, *args) return newfunc 復(fù)制代碼

除此之外,你還可以實(shí)現(xiàn)其他功能強(qiáng)大的裝飾器。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

由此可見,通過描述符我們可以實(shí)現(xiàn)強(qiáng)大而靈活的屬性管理功能,對于一些要求屬性控制比較復(fù)雜的場景,我們可以選擇用描述符來實(shí)現(xiàn)。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

總結(jié)Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

這篇文章我們主要講了 Python 描述符的工作原理。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

首先,我們從一個簡單的例子了解到,一個類屬性是可以托管給另外一個類的,這個類如果實(shí)現(xiàn)了描述符協(xié)議方法,那么這個類屬性就是一個描述符。此外,描述符又可以分為數(shù)據(jù)描述符和非數(shù)據(jù)描述符。 Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

之后我們又分析了獲取一個屬性的過程,一切的入口都在 __getattribute__ 中,這個方法定義了尋找屬性的順序,其中實(shí)例屬性優(yōu)先于數(shù)據(jù)描述符調(diào)用,數(shù)據(jù)描述符要優(yōu)先于非數(shù)據(jù)描述符調(diào)用。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

另外我們又了解到,方法其實(shí)就是一個非數(shù)據(jù)描述符,如果我們在類中定義了相同名字的實(shí)例屬性和方法,按照 __getattribute__ 中的屬性查找順序,實(shí)例屬性優(yōu)先訪問。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

**后我們分析了 function 和 method 的區(qū)別,以及使用 Python 描述符也可以實(shí)現(xiàn) property、staticmethod、classmethod 裝飾器。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

Python 描述符提供了強(qiáng)大的屬性訪問控制功能,我們可以在需要對屬性進(jìn)行復(fù)雜控制的場景中去使用它。Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

本作品采用《CC 協(xié)議》,轉(zhuǎn)載必須注明作者和本文鏈接

以上就是介紹python描述符的意義的詳細(xì)內(nèi)容,更多請關(guān)注少兒編程網(wǎng)其它相關(guān)文章!Ijv少兒編程網(wǎng)-Scratch_Python_教程_免費(fèi)兒童編程學(xué)習(xí)平臺

預(yù)約試聽課

已有385人預(yù)約都是免費(fèi)的,你也試試吧...

国产乱子伦高清露脸对白-国产精品欧美久久久久天天影视-国产91视频一区-亚洲欧美日产综合在线网-黄视频网站在线看-国产欧美亚洲精品第1页-亚洲www在线-大学生女人三级在线播放-日本在线视频www鲁啊鲁-国产成人精品一区二区仙踪林-69精品欧美一区二区三区-成人欧美亚洲-日本污污网站-中国妞xxxhd露脸偷拍视频-国产精品aⅴ在线观看-精品中文字幕在线

        国产精品日韩三级| 午夜激情影院在线观看| 国产一区一区三区| 野外做受又硬又粗又大视频√| www.国产视频.com| 艳母动漫在线观看| 国产无限制自拍| 免费看涩涩视频| 欧美精品在欧美一区二区| 凹凸国产熟女精品视频| 三级一区二区三区| 无码少妇一区二区三区芒果| 99re6这里有精品热视频| 日韩激情免费视频| 久久久久久久久久伊人| jizzzz日本| 成人在线观看你懂的| 国产无遮挡猛进猛出免费软件| 国产69精品久久久久999小说| 中文字幕永久有效| www.av片| 日韩a级黄色片| 久久久无码中文字幕久...| 欧美色图色综合| 97超碰青青草| 国内外免费激情视频| 国产69精品久久久久久久| 亚洲图片 自拍偷拍| 一级日本黄色片| xxx中文字幕| 亚洲啊啊啊啊啊| 天堂av在线中文| 人体内射精一区二区三区| 992kp免费看片| 国产在线视频综合| 国产人妻777人伦精品hd| 欧美色图色综合| 亚洲欧洲日本精品| 久久男人资源站| 天天操天天摸天天爽| 91网址在线观看精品| 黄色影视在线观看| 日日碰狠狠躁久久躁婷婷| 天天综合网久久| 黄色动漫网站入口| 久久精品国产精品亚洲精品色| 人妻少妇精品久久| 色婷婷一区二区三区在线观看| avav在线播放| 女同激情久久av久久| 国产素人在线观看| 国产一区一区三区| 午夜精品中文字幕| 国产视频在线视频| 99国产精品白浆在线观看免费| 人人干人人视频| 国产情侣第一页| 91精品国产毛片武则天| 中文字幕国产免费| 亚洲一级免费在线观看| 老头吃奶性行交视频| 午夜激情福利在线| 尤蜜粉嫩av国产一区二区三区| 国产99久久九九精品无码| 欧美性受xxxx黑人猛交88| 九九九九九国产| 中文字幕一区二区三区四| 99九九精品视频| 三年中文高清在线观看第6集| 成年网站在线播放| 手机在线成人免费视频| 九九热免费在线观看| 国产成人三级视频| 日本在线xxx| 国产成年人视频网站| 大地资源网在线观看免费官网| 免费高清一区二区三区| 丰满爆乳一区二区三区| 亚洲精品综合在线观看| 免费在线黄网站| 色一情一乱一伦一区二区三区日本 | 在线黄色免费观看| 国产欧美日韩小视频| 国内外成人免费在线视频| 青青在线视频免费观看| 激情 小说 亚洲 图片: 伦| 香港三级日本三级a视频| 性欧美极品xxxx欧美一区二区| 日韩国产精品毛片| 日本中文字幕影院| 亚洲第一中文av| 久久99爱视频| 激情视频综合网| 天天综合网日韩| 超碰在线播放91| 久久午夜夜伦鲁鲁一区二区| 日韩久久久久久久久久久久| 黄色a级在线观看| 伊人成人免费视频| 久久成人福利视频| 亚洲熟妇无码一区二区三区| 免费视频爱爱太爽了| 欧美一级视频在线播放| 青草网在线观看| 欧美综合在线观看视频| 亚洲人成色77777| 国产原创精品在线| 色综合色综合色综合色综合| 高清av免费看| 永久av免费在线观看| www.成年人视频| 黄色免费网址大全| 91看片淫黄大片91| 国产精品自拍片| 91国内在线播放| 春日野结衣av| 9191国产视频| 热久久精品免费视频| 91成人综合网| 午夜xxxxx| 免费高清在线观看免费| 欧美少妇一级片| 黑人粗进入欧美aaaaa| 91视频 - 88av| 亚洲最新免费视频| 欧美三级午夜理伦三级富婆| 久久这里只有精品18| 51自拍视频在线观看| 美女福利视频在线| 欧美性受xxxx黑人猛交88| 五月婷婷之婷婷| 欧美污视频网站| 1024精品视频| 天堂在线中文在线| 欧美国产日韩另类| 日本熟妇人妻xxxxx| 欧美与动交zoz0z| 91社在线播放| 三级黄色片免费观看| av不卡在线免费观看| 91女神在线观看| 深夜做爰性大片蜜桃| 欧美与动交zoz0z| av免费观看大全| 97xxxxx| 成人高清在线观看视频| 小泽玛利亚av在线| 日韩少妇内射免费播放| 天堂在线资源视频| 免费极品av一视觉盛宴| 国模吧无码一区二区三区| 北条麻妃在线一区| 人人妻人人澡人人爽欧美一区| 日本天堂免费a| 中文字幕 91| 成年人免费在线播放| aaaaaaaa毛片| 一起操在线视频| 一区二区三区免费播放| 亚洲爆乳无码精品aaa片蜜桃| 国产乱子伦农村叉叉叉| 国产欧美综合一区| 五月天男人天堂| 黄色a级三级三级三级| 成年人网站大全| 国产成人av影视| 激情五月亚洲色图| 女人和拘做爰正片视频| 妞干网在线观看视频| 欧美a级免费视频| www.好吊操| 国产成人黄色片| 午夜在线观看av| 色天使在线观看| 青青草视频国产| 日韩小视频在线播放| 日韩一级性生活片| 免费裸体美女网站| 亚洲综合在线一区二区| gogogo免费高清日本写真| 热这里只有精品| 久久福利一区二区| 国产日韩成人内射视频| 日本人视频jizz页码69| 7777在线视频| 少妇高清精品毛片在线视频| 中文字幕第21页| 一二三四视频社区在线| 亚洲成熟丰满熟妇高潮xxxxx| 人人爽人人av| 国产综合免费视频| 国产911在线观看| 色一情一乱一伦一区二区三区日本| 污色网站在线观看| 男女激情无遮挡| 97干在线视频| www.亚洲一区二区| 国产福利影院在线观看| 久久久久久久久久久99| 亚洲高清av一区二区三区|