1. 程式人生 > >Python基本語法之描述符

Python基本語法之描述符

 

 

描述符定義

       描述符是一種類,我們把實現了__get__()、__set__()和__delete__()中的其中任意一種方法的類稱之為描述符。

       描述符的作用是用來代理一個類的屬性,需要注意的是描述符不能定義在被使用類的建構函式中,只能定義為類的屬性,它只屬於類的,不屬於例項,我們可以通過檢視例項和類的字典來確認這一點。

       描述符是實現大部分Python類特性中最底層的資料結構的實現手段,我們常使用的@classmethod、@staticmethd、@property、甚至是__slots__等屬性都是通過描述符來實現的。它是很多高階庫和框架的重要工具之一,是使用到裝飾器或者元類的大型框架中的一個非常重要元件。注:裝飾器和元類等概念我們在以後文章中說明。

      如下示例一個描述符及引用描述符類的程式碼:

class Descriptors:

    def __init__(self, key, value_type):
        self.key = key
        self.value_type = value_type

    def __get__(self, instance, owner):
        print("執行Descriptors的get")
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        print("執行Descriptors的set")
        if not isinstance(value, self.value_type):
            raise TypeError("引數%s必須為%s"%(self.key, self.value_type))
        instance.__dict__[self.key] = value 

    def __delete__(self, instance):
        print("執行Descriptors的delete")
        instance.__dict__.pop(self.key) 

class Person:

    name = Descriptors("name", str)
    age = Descriptors("age", int)

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


person = Person("xiaoming", 15)
print(person.__dict__)
person.name
person.name = "jone"
print(person.__dict__)

        其中,Descriptors類就是一個描述符,Person是使用描述符的類。

        類的__dict__屬性是類的一個內建屬性,類的靜態函式、類函式、普通函式、全域性變數以及一些內建的屬性都是放在類__dict__裡。

        在輸出描述符的變數時,會呼叫描述符中的__get__方法,在設定描述符變數時,會呼叫描述符中的__set__方法。

        如上例子的執行結果如下:

 

描述符的種類和優先順序

       描述符分為資料描述符和非資料描述符。

       至少實現了內建__set__()和__get__()方法的描述符稱為資料描述符;實現了除__set__()以外的方法的描述符稱為非資料描述符。

      描述符的優先順序的高低順序:類屬性 > 資料描述符 > 例項屬性 > 非資料描述符 > 找不到的屬性觸發__getattr__()。

      在上述“描述符定義”章節的例子中,例項person的屬性優先順序低於資料描述符Descriptors,所以在賦值或獲取值過程中,均呼叫了描述符的方法。

      如下例子描述了類屬性高於資料描述符:

class Descriptors:
    def __get__(self, instance, owner):
        print("執行Descriptors的get")
    def __set__(self, instance, value):
        print("執行Descriptors的set")
    def __delete__(self, instance):
        print("執行Descriptors的delete")

class University:
    name = Descriptors()
    def __init__(self, name):
            self.name = name

University.name
University.name = "深圳大學"
print(University.name)

my_university = University("廈門大學")
my_university.name
print(my_university.name)

    在該例子中,University類的變數被賦值,由於該優先順序最高,所以使用的一直為University類的變數,示例執行結果如下:

    如果在這個例子中,刪除University.name = "深圳大學"這一行,則列印是怎麼樣的?

     為什麼物件的name屬性沒有值了呢,因為物件的的優先順序沒有描述符高,所以使用描述符的值,而描述符沒有賦值,所以為None,所以雖然物件的屬性有值,仍然無法正常獲取。

     描述符相關的優先順序,理解難度稍微大一點,請各位看官仔細品味,大家可以自己寫小例子嘗試列印結果,可以讓您更快的理解該原理。

 

 

如果您喜歡這篇文章,別忘了點贊和評論哦!


                        十年一夢

                   一覺醒來思未變,

                  未知恍然已十年。

                  啜啜小兒成才俊,

                  市井矗樓連成片。