在 python 代碼中,property 是很是常見的一個內置函數。property 能夠爲一個 python 類的 attribute 設置 getter/setter,能夠類比之 C# 的 properties。python
見下面的例子。框架
class A: def __init__(self): self.a = 1 @property() def hello(self): return self.a @hello.setter() def hell(self, value): self.a = value print(A().hello) # output: # 1 obj = A() obj.hello = "hello world" print(obj.hello) # output: # hello world
python 中的 descriptor 指的是實現了__get__
、__set__
、__delete__
三個方法之一的類。函數
當一個 descriptor 類的實例做爲其餘類的成員時,經過obj.attr
語法訪問該實例將會調用 descriptor 實例的__get__
方法。同理,__set__
和__delete__
也是類似的邏輯。設計
先看個例子。code
class DescriptorClass: def __get__(self, instance, owner): print(self) print(instance) print(owner) return 'some value' class SomeClass: some_attr = DescriptorClass() print(SomeClass().some_attr) # output: # <__main__.DescriptorClass object at 0x0000027AAE777160> # <__main__.SomeClass object at 0x0000027AAE777198> # <class '__main__.SomeClass'> # some value
property 的邏輯在於,當實例訪問這個屬性時,調用方法。descriptor 恰好處在那個正確的位置上。ip
看代碼。ci
class PropertyDescriptor: def __init__(self, fn): self.getter = fn def __get__(self, instance, owner): return self.getter(instance) def __set__(self, instance, value): return self.setter(instance, value) def setter(self, func): self.setter = func return self def my_property(func): return PropertyDescriptor(func) class SimpleClass: @my_property def simple_attr(self): return 'a simple property' @simple_attr.setter def simple_attr(self, value): print('simple attr setter') print(SimpleClass().simple_attr) SimpleClass().simple_attr = 'something' # output: # a simple property # simple attr setter
我的見解,謹慎參考get
descriptor 避免了重複編寫getter
和setter
方法,很是直覺的一種用途就是相似於SQLAlchemy
這樣的 ORM 框架的的字段映射。不須要爲每個特定類型的字段在基類或元類裏編寫大量樣板代碼。it
但這種設計是侵入式的(須要修改目標類的代碼),並且很是不直觀。在合適的地方使用相信能夠有其發光發熱的空間。io
對可讀性來說,結合元類,這倆被一塊兒濫用的話對維護者而言徹底是地獄吧...