赞
赏
描述符是任何新式 类,新式类是指继承自 type 或者 object 的类,这种类至少实现了 3 个特殊的方法 __get__
, __set__
, __delete__
中的一个。而这 3 个特殊的方法充当描述符协议的作用。
同时实现了 __get__
和 __set__
的类被称为数据描述符(data descriptor)。只实现了 __get__
方法的类是非数据描述符(常用于方法,当然其他用途也是可以的)。
__get__
原型详解Descriptor.__get__(self, instance, owner) --> value
当我们用类或者实例来调用该属性时,Python 会返回 __get__
函数的结果。
__set__
原型详解Descriptor.__set__(self, instance, value) --> None
当我们用实例来设置属性值时,Python 会调用该函数。对类没有限制作用。
__delete__
原型详解Descriptor.__delete__(self, instance) --> None
当我们用实例试图删除该属性时,Python 会调用该函数。对类没有限制作用。
Python 描述符的核心是 getattribute(),因为任何 实例属性 的访问都会调用到这个特殊的方法。这个方法被用来查找属性,同时也是一个代理,调用它可以进行属性的访问操作。
一般我们的类的 __getattribute__()
方法都是继承自 object,自己改写 __getattribute__()
是很危险的,也会阻止正常的描述符调用。
__getattribute__()
的 Python 描述原型如下:
def __getattribute__(self, key):
"Emulate type_getattro() in Objects/typeobject.c"
v = object.__getattribute__(self, key)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v
如果通过实例 ins 访问描述符,由 __getattribute__()
转化为:type(ins).__dict__['attr'].__get__(ins, type(ins)
,如果通过类 Class 访问描述符,由 __getattribute__()
转化为: Class.__dict__['attr'].__get__(None, Class)
__get__
方法访问类属性时,会自动调用 __get__
方法
print("嗨客网(www.haicoder.net)")
class Descriptor(object):
def __init__(self):
self.name = 'anonymous'
def __get__(self, instance, owner):
print('instance: %s' % instance)
print('owner: %s' % owner)
print("Invoke __get__: %s" % self.name)
return self.name
class Person(object):
name = Descriptor()
# 通过类Person访问
print(Person.name)
print('---------------------------------------')
print(Person.__dict__['name'].__get__(None, Person))
程序运行后,控制台输出如下:
定义了一个 Descriptor 类,该类有一个构造函数和一个 __get__
方法,接着,我们定义了一个 Person 类,Person 类里面有一个类属性 name,类属性 name 使用 Descriptor 类初始化。
最后,我们分别使用类名访问 Person 类的属性和使用 dict 访问 name 属性,我们发现,两种方式,都调用了 Descriptor 类的 __get__
方法。
__get__
方法使用类实例访问类属性时,会自动调用 __get__
方法
print("嗨客网(www.haicoder.net)")
class Descriptor(object):
def __init__(self):
self.name = 'anonymous'
def __get__(self, instance, owner):
print('instance: %s' % instance)
print('owner: %s' % owner)
print("Invoke __get__: %s" % self.name)
return self.name
class Person(object):
name = Descriptor()
user = Person()
# 通过实例user访问, `owner`访问描述符实例的对象。`instance`则是访问描述符实例的实例
print(user.name)
print('-----------------------------------')
print(type(user).__dict__['name'].__get__(user, type(user)))
程序运行后,控制台输出如下:
我们使用类的实例访问类属性时,同样调用了 __get__
方法。
__set__
方法设置类属性时,会自动调用 __set__
方法
print("嗨客网(www.haicoder.net)")
class Descriptor(object):
def __init__(self):
self.name = 'anonymous'
def __set__(self, instance, name):
print("invoke __set__: %s" % name)
self.name = name.title()
class Person(object):
name = Descriptor()
user = Person()
user.name = 'jack'
程序运行后,控制台输出如下:
当我们给类实例的实例属性赋值时,会自动调用 __set__
方法。
__del__
方法设置类属性时,会自动调用 __set__
方法
print("嗨客网(www.haicoder.net)")
class Descriptor(object):
def __init__(self):
self.name = 'anonymous'
def __delete__(self, instance):
print("Invoke __delete__: %s" % self.name)
del self.name
class Person(object):
name = Descriptor()
user = Person()
del user.name
程序运行后,控制台输出如下:
当我们使用 del 删除类的实例属性时,会自动调用 __del__
方法。
描述符是任何新式类,新式类是指继承自 type 或者 object 的类,这种类至少实现了 3 个特殊的方法 __get__
, __set__
, __delete__
中的一个。而这 3 个特殊的方法充当描述符协议的作用。
同时实现了 __get__
和 __set__
的类被称为数据描述符(data descriptor)。只实现了 __get__
方法的类是非数据描述符(常用于方法,当然其他用途也是可以的)。