如何理解 Python 的 Descriptor?

時間 2021-05-31 08:44:18

1樓:一起吃鰻魚飯啊

簡單來說,對與既支援函式式程式設計又支援物件導向式程式設計的語言來說,統一函式和類方法有兩種解決方案,一種是像Ruby一樣所有的callable都是類方法,或者像Python這樣,類方法只是帶有物件的特殊函式,descriptor就是為了解決這個而引入的。

2樓:影之心

描述器有三個特殊方法:__get__(self, obj, type=None) –> value、__set__(self, obj, value) –> None、__delete__(self, obj) –> None。實現任一方法的物件都可以稱作描述器物件。

描述器物件又分為兩種:實現了__get__和__set__的稱為data descriptor;只實現了__get__的稱為non-data descriptor。python中的屬性、方法、靜態方法和類方法裝飾器都是基於描述器機制實現的,所以了解了描述器對了解python的某些底層實現是很有幫助的。

那描述器到底乾有什麼神操作呢?

敲黑板了!如果先把乙個描述器物件賦值給要查詢的屬性,那麼這個時候再訪問這個屬性時,其查詢順序就會被改變了,根據descriptor的型別會進行不同的查詢順序。如果是data descriptor,則會優先呼叫描述器物件的__get__方法,即a.

__dict__[『x』].__get__(a, type(a)),沒有查到則按物件屬性的預設查詢順序繼續執行;如果是non-data descriptor,則會先查詢屬性字典,如果沒有查到則呼叫a.__dict__[『x』].

__get__(a, type(a)),經過這兩步都沒有查到則再呼叫__getattr__,也就是說__getattr__這個特殊方法的呼叫優先順序是最低的。有幾點需要說明下:

從上邊可以看到,無論是哪種描述器,在呼叫__get__時都得先呼叫a.__dict__[『x』],也就是必須先呼叫__getattribute__方法,可見描述器的觸發都是__getattribute__。如果重寫了例項物件的__getattribute__特殊方法,則會影響描述器的自動呼叫,該特殊方法絕大多數情況下不要重寫。

__get__方法中有兩個引數:obj和type(obj),如果是通過obj.x訪問屬性,則obj和type(obj)都會被自動傳入;如果是type(obj).

x通過類訪問屬性,則obj為None。在實現__get__方法時需針對不同情況做相應處理。__set__和 __delete__是同樣的道理。

乙個描述器物件可以將其作為屬性繫結給物件,也可以像普通類那樣例項化,畢竟它只是乙個類。

直接上個比較有深度的例子,利用描述器模擬python函式或方法的實現:

import types

class FuncDes:

'''模擬python函式或方法的實現'''

__name__ = 'hello'

def __init__(self, argself.arg = arg

def __get__(self, obj, clsif obj is Nonereturn selfMethodType第乙個引數必須為可呼叫物件

return types.MethodType(self, obj)

def __call__(self, obj=None, arg=Noneif arg is Noneraise SyntaxError

if obj is Noneprint('I am a function'elseprint("Im method '{}' of object '{}'".format(self.__name__, objprint('my args:

', arg)

class T:

hello = FuncDes(arg=None)

def __init__(selfself.a = 1

self.b = 999

t = T()

print(t.hello)

t.hello('hello')

func = FuncDes(arg=None)

func(arg='world')

>>>output:

>Im method 'hello' of object '<__main__.T object at 0x006FF490>'

my args: hello

I am a function

my args: world

如何理解python的sqlalchemy這種orm框架?

回答這個問題之前,首先讓我們回顧一下,乙個關聯式資料庫中都有什麼?沒錯,簡單來說,就是一張張表。表中又有什麼?行和列,一行就是一條記錄,一列就代表著一條記錄的某個屬性。舉例來說,乙個學籍資料庫可能包含一張學生資訊表,表中每行記錄著乙個學生的資訊,由很多列組成,每一列表示學生的乙個屬性,比如姓名 年齡...

如何理解Python裝飾器?

這是我見過的最好的Python裝飾器教學文章 Primer on Python Decorators Real Python 假設我們有乙個 decorator defcount time name def decorator func def arg,kw start time time func...

如何理解python的類與物件?

rainzee 類 class 是抽象化的概括 物件 object 是具象化的例項 上述是一切思想的根本,任何物件導向程式設計都遵守這個思想,下面來具體理解。當我們想描述一類事物的時候,我們首先需要尋找這一類事物的共同點,例如,學生 很顯然,每個學生都至少擁有 姓名 年齡 無論是小明,還是小紅,所以...