欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python __getattribute__、__getattr__、__setattr__详解

程序员文章站 2022-04-09 18:03:13
__getattribute__ 官方文档中描述如下: 该方法可以拦截对对象属性的所有访问企图,当属性被访问时,自动调用该方法(只适用于新式类)。因此常用于实现一些访问某属性时执行一段代码的特性。 需要注意的是,正式由于它拦截对所有属性的访问(包括对__dict__的访问),在使用中要十分小心地避开 ......

__getattribute__

官方文档中描述如下:

python __getattribute__、__getattr__、__setattr__详解

该方法可以拦截对对象属性的所有访问企图,当属性被访问时,自动调用该方法(只适用于新式类)。因此常用于实现一些访问某属性时执行一段代码的特性。

需要注意的是,正式由于它拦截对所有属性的访问(包括对__dict__的访问),在使用中要十分小心地避开无限循环的陷阱。在__getattribute__方法中访问当前实例的属性时,唯一安全的方式是使用基类(超类) 的方法__getattribute__(使用super)。例如:

python __getattribute__、__getattr__、__setattr__详解

通过上图中的代码示例可以看出,一旦实现了__getattribute__方法,所有通过对象访问的属性(包括类属性)都会被拦截,而直接通过类访问类属性则不会。

注意:当访问的属性不存在并重载(覆盖基类对某方法的默认实现)了__getattribute__方法时,该方法不会主动抛出attributeerror异常。上图中捕获的attributeerror异常,是由基类__getattribute__方法实现并抛出。

常见的错误用法示例:

python __getattribute__、__getattr__、__setattr__详解

在实现__getattribute__方法时访问对象自身的属性,程序陷入无限循环直到崩溃。

__getattr__

官方文档描述如下:

python __getattribute__、__getattr__、__setattr__详解

__getattr__方法的自动执行,需要满足两个条件:一是访问对象属性;二是触发attributeerror异常。代码示例如下:

python __getattribute__、__getattr__、__setattr__详解

上图中,调用不存在的job属性首先调用__getattribute__方法(如果该方法未定义,会调用基类的__getattribute__方法),触发attributeerror异常并自动捕获,然后才调用__getattr__方法。

错误用法示例如下:

python __getattribute__、__getattr__、__setattr__详解

重载了__getattribute__方法,却没有主动抛出attributeerror异常的机制,或者抛出一个其它类型的异常,__getattr__方法都不会执行。

__setattr__

python __getattribute__、__getattr__、__setattr__详解

试图给属性赋值时自动调用该方法,例如:

python __getattribute__、__getattr__、__setattr__详解

之所以会执行三次print函数,是因为在__init__方法中,对象a初始化时给属性name和age赋值时,触发了__setattr__方法。使用该方法是同样需要十分小心避免无限循环陷阱。

错误用法示例如下:

python __getattribute__、__getattr__、__setattr__详解

可以看出,在__setattr__方法中,不能直接给属性赋值,而通常的做法是使用__dict__魔法属性。__dict__属性是一个字典,所有的实例属性都存储在这个字典中,而修改__dict__字典中的键值对成员不会触发__setattr__方法,这里应注意与直接修改__dict__的值的区别。

注意:如果定义__setattr__方法的同时定义了__getattribute__方法,那么在修改__dict__字典中的键值对时,由于调用了self.__dict__属性,同样会触发__getattribute__方法,使用时应格外小心。代码示例如下:

python __getattribute__、__getattr__、__setattr__详解

上图示例代码中,每调用一次__setattr__就会调用一次__setattribute__。

注意赋值语句与属性调用的区别:self.__dict__ = {}是赋值语句,不会触发__getattribute__方法,但触发__setattr__方法;self.__dict__[name] = value语句,先调用self.__dict__属性,得到dict对象后再修改其成员。 

以上。

上一篇: learn ES6

下一篇: 博客园-真够意思