
全新采用了新式类, 摒弃了旧式类, 身为新式类的一项特性有着极为奇妙的功效。查阅一些博客以及文章之时, 察觉到欲要透彻领会和的差异, 事实上得领会中属性的查找次序、描述器()、、、等相关知识。首要的是要明确指出, 要是存在一个类, 其仅仅定义了方法那么这种类就被称作non - data非资料描述器, 要是这个类既把某个东西和另一个东西都定义了, 那么它就被称作data资料描述器, 具体的情况能够在我的那里看到, 这便于理解。接下来进行实例属性查找顺序的介绍。假定t T(), t.at的查找顺序是像下面这样的:。1、如果是自动产生的属性返回否则进行第2步2、要是“at”在T或者它的父类以及祖先类里面出现了表示“at”是类属性, 不是仅属于t的实例属性, 而且at是一个data, 那么就优先调用它的方法。倘若是非data或者不存在该属性情况, 那就进行第2步。3、找寻一下实例t之中是不是存在at属性, 要是有的话就予以返回, 要是没有的话那就进入到第3步。4、查找t的父类之中, 是否存在at属性还要查找t的祖先类之中以及别处, 是否存在at属性要是没有at属性, 那么就执行第4步要是有at属性, 那么就执行如下步骤:4.1处的at属于一个non - data , 去调用它的方法 , 要是并非如此那就去执行3.2。 4.2 返回at5、如果实例t的父类中有方法则调用该方法没有则抛出。需留意, 每当类或者实例对属性进行调用之际, 都会被毫无条件地在最起初的时候予以调用。下面的代码篇幅稍长, 烦请耐心去查看。class Descriptor: # 定义描述器的类 def __get__(self, instance, owner): # get方法用于返回实例的a属性 print(3 get called,, instance is, instance, ,owner is, owner) return instance.a def __set__(self, instance, value): # set方法用于修改实例的a属性 print(4 set called,, instance is, instance, ,value is, value) instance.a value**2 def __getattribute__(self, item): print(5 Des getattribute called, item is %s % item) class NotDescriptor: # 定义non-data descriptor def __get__(self, instance, owner): print(6 get called,, instance is, instance, ,owner is, owner) return instance.a - 100 class T: desc Descriptor() # 类属性一个资料描述器 data descriptor Not_Desc NotDescriptor() # 类属性一个非资料描述器 non-data descriptor def __init__(self): self.a 123 self.not_desc instance not_desc def func(self): return T func def __getattribute__(self, item): print(1 getattribute called, item is , item) return object.__getattribute__(self, item) def __getattr__(self, item): print(2 getattr called, item is, item) raise AttributeError(NO such attr %s % item)下面的这些测试, 全都运用上方的那代码, 每一回的输出操作, 都已进行过重置, 目的是防止出现混淆。1 getattribute called, item is func T func # 实例的函数 1 getattribute called, item is a 123 # 实例的属性 4 set called, instance is __main__.T object at 0x000001E55B630240 ,value is 2 # set方法前不调用getattribute。instance是拥有该描述器类的一个实例。value是要设置的值。 1 getattribute called, item is desc 3 get called, instance is __main__.T object at 0x000001E55B630240 ,owner is # get方法前还是优先调用getattributeinstance是拥有该描述器对象的一个实例。owner是拥有者本身 1 getattribute called, item is a t.a 4 # 2**2 4可以看到, 在调用实例的属性以及方法的时候, 都会毫无条件地率先调用方法, 然而set方法是不会被调用的。此外, 代码借助描述器的get方法以及set方法, 实际上已然达成了类似于的运用情况。当然了, 装饰器实在是基于描述器而得以实现的, 要是对装饰器并不明白的话, 是能够去查看我的。下面继续使用上方代码验证、非描述器的执行顺序。t T() print(t.not_desc) --------结果如下------ 1 getattribute called, item is not_desc instance not_desc回想前面所提及的属性查找顺序, 在类当中被找到了, 然而并非如此, 所以执行第二步, 于实例的里面发现了该属性, 进而返回。t T() print(t.Not_Desc) --------结果如下------ 1 getattribute called, item is Not_Desc 6 get called, instance is __main__.T object at 0x0000017F70A006A0 ,owner is # 这里是NonDataDescriptor中的get方法 1 getattribute called, item is a 23 # a的初始值为123 由get方法返回的是123-10023依据我们先前提及的顺序, 属性于类之中被找到, 然而并非data , 且未在实例的dict里找到, 于是进展到了4.1步骤, 发觉它是一个non-data , 随后便执行了其中的get方法。t T() print(t.bbbbbb) # T类中没有定义该属性 ------结果如下---------- 1 getattribute called, item is bbbbbb 2 getattr called, item is bbbbbb Traceback (most recent call last): File C:/省略/.py, line 40, in print(t.bbbbbb) File C:C:/省略/.py.py, line 36, in __getattr__ raise AttributeError(NO such attr %s % item) AttributeError: NO such attr bbbbbb可见, 当我们去访问一个并未被定义的属性之时, 依旧会率先进行调用, 依据属性查找的原则, 在实例之中以及类里面都没能找到这个属性, 于是便会执行。到了此地, 我们也就知晓了其属性的查找顺序, 以及执行顺序。当回过头去看时, 在调用类以及实例的属性之际会进行无条件调用, 所以能够将其用于权限鉴别这样的操作, 还能用于日志记录等方面进而在属性未被找到的情形下会予以执行, 所以能够借助它来开展一些兜底的操作, 由此可见。另外, 要留意重写期间的循环陷阱, 返回语句得写成.( ) , 别运用 self.xxx , 不然 self 等同于再次指向自身, 进而会无条件展开调用, 由此踏入无限循环。最后的我们查看类和实例的属性看看又什么不同t T() print(t.__dict__) print(T.__dict__) ------结果如下-------- 1 getattribute called, item is __dict__ {a: 123, not_desc: instance not_desc} {__module__: __main__, desc: __main__.Descriptor object at 0x0000021FD20C0128, Not_Desc: __main__.NotDescriptor object at 0x0000021FD20C0160, __init__: , func: , __getattribute__: , __getattr__: , __dict__: , __weakref__: , __doc__: None}由此能够看出, 实例t具备的仅仅是在init里所定义的那些属性, 然而, 类T当中才存在着诸如描述器以及非描述器之类的属性。