首頁  >  文章  >  後端開發  >  Python中的描述器怎麼使用

Python中的描述器怎麼使用

PHPz
PHPz轉載
2023-05-29 08:19:281317瀏覽

    概述

    描述器是Python對象,用於定義在存取其他物件屬性時所執行的操作。透過描述器,可以實現多種不同的行為,例如運算屬性、快取屬性值、以及控制屬性存取等。使用描述器可以自訂屬性存取行為,避免在每個屬性使用處編寫重複的程式碼。

    任何類別的屬性,包括實例屬性、類別屬性和靜態屬性都可以使用描述器。 Python程式設計中的描述器是高階特性,對於具備深入了解Python語言和高階程式設計技能的程式設計師非常實用。

    實作方式

    Python描述器是透過實作描述器協定來定義的。描述器協定是Python物件協定的一種,它定義了三個方法:__get__()__set__()__delete__()

    Python解釋器在存取一個物件的屬性時,會先檢查該屬性是否為描述器。如果屬性是描述器,則呼叫__get__()方法取得屬性值。如果屬性不是描述器,則直接傳回屬性值。

    如果我們想要使用一個Python描述器來控制屬性存取行為,我們需要實作描述器協定中的__get__()__set__()__delete__()方法中的至少一個方法。以下是這些方法的具體說明:

    __get__(self, instance, owner):用於取得屬性值。如果存取屬性的是一個實例,則instance參數是實例對象,owner參數是類別對象。如果存取屬性的是類,則instance參數是None,owner參數是類物件。

    __set__(self, instance, value):用來設定屬性值。如果設定屬性值的是一個實例,則instance參數是實例對象,value參數是要設定的值。如果設定屬性值的是一個類,則instance參數是None,value參數是要設定的值。

    __delete__(self, instance):用於刪除屬性值。如果刪除屬性值的是一個實例,則instance參數是實例物件。如果刪除屬性值的是一個類,則instance參數是None。
    如何使用Python描述器

    應用場景

    Python的描述器可套用於多種情境,例如計算屬性、快取屬性值和實作屬性的存取控制。以下是一些使用Python描述器的範例。

    計算屬性

    計算屬性是由其他屬性計算得出的屬性。舉例來說,使用一個描述器可以建立一個計算屬性,該屬性將兩個數字屬性相加。下面是一個實作計算屬性的範例程式碼:

    class SumDescriptor:  
        def __init__(self, a, b):  
            self.a = a  
            self.b = b  
         
        def __get__(self, instance, owner):  
            return getattr(instance, self.a) + getattr(instance, self.b)  
         
    class MyClass:  
        def __init__(self, a, b):  
            self.a = a  
            self.b = b  
            self.sum = SumDescriptor('a', 'b')

    在上面的程式碼中,SumDescriptor是一個描述器,它使用__get__()方法來計算a和b屬性的和。 MyClass是一個包含a和b屬性的類,它也定義了一個sum屬性,該屬性是SumDescriptor的實例。

    當我們使用MyClass建立一個實例時,可以透過存取sum屬性來取得a和b屬性的和,而無需手動計算它們:

    >>> obj = MyClass(1, 2)  
    >>> obj.sum  
    3

    快取屬性值

    另一個常見的用途是快取屬性值。使用描述器可以快取屬性值,從而提高程式效能,特別是當屬性值是較慢的計算或大量資料時。下面是一個快取屬性值的範例程式碼:

    class CachedProperty:  
        def __init__(self, func):  
            self.func = func  
            self.__name__ = func.__name__  
             
        def __get__(self, instance, owner):  
            if instance is None:  
                return self  
            value = self.func(instance)  
            setattr(instance, self.__name__, value)  
            return value  
      
    class MyClass:  
        def __init__(self, data):  
            self._data = data  
             
        @CachedProperty  
        def processed_data(self):  
            # Perform some slow computation  
            result = ...  
            return result

    在上面的程式碼中,CachedProperty是一個描述器,它使用__get__()方法來快取屬性值。 MyClass是一個包含_data屬性的類,它定義了一個processed_data屬性,該屬性使用@CachedProperty裝飾器來實現緩存。當我們存取processed_data屬性時,如果快取中已經存在屬性值,則直接傳回快取的值。否則,計算屬性值,並將其儲存在快取中。

    實作屬性存取控制

    描述器也可以用來實現屬性存取控制。例如,我們可以使用描述器來禁止對一個屬性進行修改。以下是實作屬性存取控制的範例程式碼:

    class ReadOnlyDescriptor:  
        def __init__(self, value):  
            self.value = value  
             
        def __get__(self, instance, owner):  
            return self.value  
         
        def __set__(self, instance, value):  
            raise AttributeError("can't set attribute")  
      
    class MyClass:  
        def __init__(self, data):  
            self._data = ReadOnlyDescriptor(data)

    在上面的程式碼中,ReadOnlyDescriptor是一個描述器,它使用__set__()方法來禁止對屬性進行修改。 MyClass是一個包含 _data屬性的類,它定義了一個唯讀的屬性。當我們嘗試對_data屬性進行修改時,會引發AttributeError異常。

    自訂屬性存取控制

    除了上面介紹的基本描述器,Python還提供了property裝飾器,它可以用來定義自訂的屬性存取控制。使用property裝飾器,我們可以將一個方法轉換為一個唯讀屬性,一個可寫屬性或一個可讀寫屬性。下面是一個自訂屬性存取控制的範例程式碼:

    class MyClass:  
        def __init__(self, value):  
            self._value = value  
             
        @property  
        def value(self):  
            return self._value  
         
        @value.setter  
        def value(self, new_value):  
            if new_value < 0:  
                raise ValueError("value must be non-negative")  
            self._value = new_value

    在上面的代码中,value方法被转换为一个属性。@property装饰器将value方法转换为只读属性,@value.setter装饰器将value方法转换为可写属性。当我们尝试对value属性进行修改时,如果新值小于0,则引发ValueError异常。

    以上是Python中的描述器怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除