1. 程式人生 > >課時46:魔法方法:描述符(property的原理)

課時46:魔法方法:描述符(property的原理)

屬性。 none 道理 sta object __init__ 實例 span module

目錄:

  一、描述符(property的原理)

  二、課時46課後習題及答案

**********************************

一、描述符(property的原理)

**********************************

本節要講的內容叫作描述符,用一句話解釋,描述符就是將某種特殊類型的類的實例指派給另一個類的屬性。那什麽是特殊類型的類呢?就是至少要在這個類裏邊定義__get__()、__set__()或__delete__()三個特殊方法中的任意一個。

下表列舉了描述符相關的魔法方法:

__get__(self, instance, owner)     用於訪問屬性,它返回屬性的值
__set__(self, instance, value) 將在屬性分配操作中調用,不返回任何內容 __delete__(self, instance) 控制刪除操作,不返回任何內容

舉個直觀的例子:

class MyDescriptor:
    def __get__(self, instance, owner):
        print("getting...", self, instance, owner)
        
    def __set__(self, instance, value):
        print("setting...
", self, instance, value) def __delete__(self, instance): print("deleting...", self, instance) class Test: x = MyDescriptor()

由於MyDescriptor實現了__get__()、__set__()和__delete__()方法,並且將它的類實例指派給Test類的屬性,所以MyDescriptor就是所謂描述符類。到這裏,大家有沒有看到property()的影子?

好,實例化Test類,然後嘗試著對x屬性進行各種操作,看看描述符類會有怎樣的響應:

>>> test = Test()
>>> test.x
getting... <__main__.MyDescriptor object at 0x000001559C681CF8> <__main__.Test object at 0x000001559C67A588> <class __main__.Test>

當訪問x屬性的時候,Python會自動調用描述符的__get__()方法,幾個參數的內容分別是:self是描述符類自身的實例;instance是這個描述符的擁有者所在的類的實例,在這裏也就是Test類的實例;owner是這個描述符的擁有者所在的類本身。

>>> test.x = X-man
setting... <__main__.MyDescriptor object at 0x000001559C681CF8> <__main__.Test object at 0x000001559C67A588> X-man

對x屬性進行賦值操作的時候,Python會自動調用__set__()方法,前兩個參數跟__get__()方法是一樣的,最後一個參數value是等號右邊的值。

最後一個del操作也是同樣的道理:

>>> del test.x
deleting... <__main__.MyDescriptor object at 0x000001559C681CF8> <__main__.Test object at 0x000001559C67A588>

只要弄清楚描述符,那麽property的秘密就不再是秘密了!property事實上就是一個描述符類。下邊就定義一個屬於我們自己的MyProperty:

class MyProperty:
    def __init__(self, fget=None, fset=None, fdel=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        
    def __get__(self, instance, owner):
        return self.fget(instance)
    
    def __set__(self, instance, value):
        self.fset(instance, value)
        
    def __delete__(self, instance):
        self.fdel(instance)

class C:
    def __init__(self):
        self._x = None
        
    def getX(self):
        return self._x
    
    def setX(self, value):
        self._x = value
        
    def delX(self):
        del self._x
        
    x = MyProperty(getX, setX, delX)
>>> c = C()
>>> c.x = X-man
>>> c.x
X-man
>>> c._x
X-man
>>> del c.x
>>> c.x
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    c.x
  File "C:\Users\14158\Desktop\MyProperty.py", line 8, in __get__
    return self.fget(instance)
  File "C:\Users\14158\Desktop\MyProperty.py", line 21, in getX
    return self._x
AttributeError: C object has no attribute _x

看,這不就實現了property()函數了嘛,簡單吧?!

最後講一個實例:

先定義一個溫度類,然後定義兩個描述符類用於描述攝氏度和華氏度兩個屬性。
要求兩個屬性會自動進行轉換,也就是說你可以給攝氏度這個屬性賦值,然後打印的華氏度屬性是自動轉換後的結果。
class Celsius:
    def __init__(self, value = 26.0):
        self.value = float(value)

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = float(value)

class Fahrenheit:
    def __get__(self, instance, owner):
        return instance.cel * 1.8 + 32

    def __set__(self, instance, value):
        instance.cel = (float(value) - 32) / 1.8

class Temperature:
    cel = Celsius()
    fah = Fahrenheit()
>>> temp = Temperature()
>>> temp.cel
26.0
>>> temp.fah
78.80000000000001

*******************************

二、課時46課後習題及答案

*******************************

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

技術分享圖片

課時46:魔法方法:描述符(property的原理)