目錄:
一、描述符(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課後習題及答案
*******************************