Dict
每个实例和类都有相应的__dict__属性,这个属性是一个dictonary。
对于实例,存放实例相关的实例属性等。
对于类,存放类定义中的类属性,函数对象等。
new style class指的是继承自object的类,而old style class则不继承自object. 这两种类python的处理方式有所不同。
我们先来看A.__dict__和B.__dict__的区别。
我们可以通过dir函数来获取类和实例的属性,dir将会提供更加详细的信息。对于实例,不仅给出实例的属性,而且还给出类的属性(包括类的成员属性,成员函数定义)。
另外一个函数vars,只给出实例的属性。
Member Attribute
The time before descriptor
当我们经由构造函数__init__来对一个成员进行初始化的时候,python会把一个成员变量存放在__dict__中。我们可以由如下代码验证
经过a.foo赋值后,__dict__中多出了一项,这个就是我们通过直接添加成员变量所致。
NOTE:
python的class是对外部开放的,没有必要直接在__init__中初始化成员。这就是动态语言的好处。
What is descriptor
在现在的python中,函数,成员变量等都是用descriptor来实现的。
descriptor分为
- 数据描述符
- 非数据描述符
数据描述符的定义是拥有__set__、__get__接口的类,而非数据描述符是指只实现了__get__方法。
另外一个可选实现的接口是__delete__。
descriptor可以用来封装对一个属性的访问。
我们来看一个加入descriptor对于一个实例的影响。
以下是descriptor的定义,descriptor是类的静态属性
来看一下访问代码
可以看到,加入了descriptor后,python会先调用我们的set, get函数,最后再对属性做处理。这样我们就有了更多的控制权。__dict__在赋值后也没有改变。
如果我们将descriptor a改为一个非数据描述符,并且对其进行赋值会怎么样呢?
这里我们直接通过del将__set__函数删除,使其成为一个非数据描述符,也可以使用delattr来删除,这个调用是等价的。
在成为非数据描述符后,我们给f.a = 1赋值成功,此时直接在__dict__加入了一项。
这里,我们给出一段python的伪代码,用来描述整个过程:
对于读取一个属性,将会有所不同,如果一个属性是非数据描述符,那么将会先从__dict__中获取,如果没有找到,则再去调用非数据描述符的__get__函数。
测试代码如下:
当我们在f.__dict__中加入了a属性后,python就直接从__dict__中获取该值了。
读取一个属性的伪代码如下:
1 # when read an attribute from a class instance 2 3 # check if there's a data descriptor named 'attribute' 4 if hasattr(MyClass, 'attribute'): 5 klsAttr = MyClass.attribute.__class__ 6 if hasattr(klsAttr, '__set__'): 7 if hasattr(klsAttr, '__get__'): 8 return klsAttr.__get__(attribute, instance, value) 9 else: 10 return attribute 11 12 # we check against the __dict__ of the instance 13 if hasattr(obj, 'attribute'): 14 return obj.__dict__['attribute'] 15 16 if hasattr(klsAttr, '__get__'): 17 return klsAttr.__get__(attribute, instance, value) 18 19 raise AttributeError('cannot find "attribute"')
Descriptor Precedence
这里我们给出不同的descriptor和其他一些重要的属性之间的优先级关系。
数据描述符 > 实例属性 > 非数据描述符
Descriptor是类属性,也就是说,每个类只有这样一个Descriptor,所以Descriptor适合用来做类级别的事。比如可以用来做为一个Cache。
下次我们要讲Property,而Property是作为实例的Descriptor使用的。
reference:
- 《Expert python programming》
- 《Core python programming》