手動實現property裝飾器

首先,property裝飾器是經過數據描述符實現的。用法很簡單,你們應該都知道,這裏就不細說了。html

這裏主要分析一下property是如何經過描述符實現的。python

class Property:
    def __init__(self, fget):
        self.fget = fget    # 爲實例增長方法,這裏的方法是未綁定實例的,不會自動傳入實例self
        self.fset = None    # 同上,未綁定實例

    def __get__(self, instance, owner):
        if instance is not None:
            return self.fget(instance)  # 調用原方法,傳入實例self
        return self

    def __set__(self, instance, value):
        self.fset(instance, value)  # 調用原方法,傳入實例self和value

    def setter(self, func):
        self.fset = func  # 更新屬性
        return self

class A:
    def __init__(self, data):
        self._data = data

    @Property  # data = Property(data) 描述符實例
    def data(self):
        return self._data

    @data.setter  # data = data.setter(data) 更新屬性,並返回描述符實例
    def data(self, value):
        self._data = value

訪問函數

a = A(100)
print(a.data)  # 訪問描述符實例,調用__get__()方法
# 100

執行過程以下:
1. 在裝飾器中,data變量指向Property(func)描述符實例
2. 原data()函數被賦值給fget變量
3. a.data就是訪問描述符實例,觸發調用__get__()方法
4. 最後,調用fget()也就是原data()方法,並傳入owner class的實例,亦即調用data(self)

賦值code

a.data = 200  # 訪問描述符實例,調用__set__()方法
print(a.data)  # 訪問描述符實例,調用__get__()方法
# 200

執行過程以下:
1. 在裝飾器中,data變量指向data.setter(func)描述符實例。注意,後面的data是__get__()方法返回的描述符實例
2. 原data()函數被賦值給fset變量
3. 賦值操做觸發調用__set__方法
4. 最後,調用fset也就是原data()方法,並傳入owner class的實例和要賦的值,亦即調用data(self, value)

這裏涉及到裝飾器,須要對裝飾器和麪向對象有足夠的瞭解才能弄明白當中的變量傳遞,但願你不會被擋住。htm

參考:
https://docs.python.org/3/library/functions.html#property對象

相關文章
相關標籤/搜索