在 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
对可读性来说,结合元类,这俩被一块儿滥用的话对维护者而言彻底是地狱吧...