类的内置方法__getattribute__、__getattr__、__setattr__

__getattr__:若访问属性不存在时则会调用该魔法方法。

首先理解__getattr__的用法,看代码:

  

class Test(object):
    def __init__(self,name):
        self.name = name
        
    def __getattr__(self, item):
        print(item,"Not Found")


if __name__ == '__main__':
    test = Test('小明')

    print(test.getattr)
getattr Not Found
None
由结果上看,test = Test('小明')对类进行实例化,print(test.getattr)打印了类的实例属性(注:不是访问__getattr__方法),结果首先输出getattr Not Found,可见首先访问__getattr__方法,之后打印输出为None(属性不存在),假如未定义__getattr__方法时在查找不存在的属性时则会爆出AttributeError,可见__getattr__是进行错误异常处理的处理方法,可用来对错误异常处理方面进行自定制。

__setattr__:若对一个实例的属性进行赋值时则会自动调用该方法。

接下来看代码:
class Test(object):
    def __init__(self,name):
        self.name = name

    def __getattr__(self, item):
        print(item,"Not Found")

    def __setattr__(self, key, value):
        print(key,'已被赋值为',value)
        self.__dict__[key] = value


if __name__ == '__main__':
    test = Test('小明')

    test.name = '小张'

    print(test.name)
name 已被赋值为 小明
name 已被赋值为 小张
小张
test = Test('小明')对类进行实例化,并且初始化self.name = name,为一次赋值操作,所以会调用__setattr__,输出为name 已被赋值为小明。再看test.name = 小张',再次给实例属性name重新赋值,再次调用__setattr__。
总结:
对一个属性进行赋值会调用__setattr__方法。



拓展:
class A:
    def __init__(self):
        self.age = 6
        self.gender = 'male'


class Test(A):
    def __init__(self,name):
        self.name = name

    def __getattr__(self, item):
        # print(super(Test,self).__init__())
        super(Test,self).__init__()
        print(item,"Not Found")

    def __setattr__(self, key, value):
        print(key,'已被赋值为',value)
        self.__dict__[key] = value


if __name__ == '__main__':
    test = Test('小明')
    

    print(test.age)
    print(test.__dict__)
    print(test.age)
 
name 已被赋值为 小明
age 已被赋值为 6
gender 已被赋值为 male
age Not Found
None
{'name': '小明', 'age': 6, 'gender': 'male'}
6

当访问Test的age属性时是没找到的,所以会执行子类的__getattr__方法,但是此例中在__getattr__中调用超类的__init__方法,并对age和gender进行初始化。由结果可以看出,在子类调用父类的方法并对属性赋值时,还是会调用子类的__setattr__方法。由最后输出的字典也可以看出,父类的age和gender已经被添加到子类的__dict__中,并且以后子类也存在age和gender属性。

总结:1、子类中调用父类方法,若对属性进行初始化或赋值等操作,则会调用子类__setattr__方法,同理若在父类中找不到该属性值则会调用__getattr__。

   2、调用__setattr__方法时,会把key和value当作参数传进,届时可以把item添加进子类属性字典,以便后续操作可以访问。

__getattibute__:

  • 1  调用属性会触发该功能,属性存在则会返回相应的值;

  • 2 如果属性不存在则会抛出异常AttributeError,所以可以自定义异常信息

  • 3 存在__getattr__,若有异常出现则会传递给__getattr__用来接收,执行操作

class Test(object):
    def __getattribute__(self, item):
        return super(Test, self).__getattribute__(item)


if __name__ == '__main__':
    test = Test()
    print(test.age)
Traceback (most recent call last):
  File "XXX", line 220, in <module>
    print(test.age)
  File "XXX", line 215, in __getattribute__
    return super(Test, self).__getattribute__(item)
AttributeError: 'Test' object has no attribute 'age'

由结果可知若访问属性不存在时发出AttributeError错误。

class Test(object):
    def __getattribute__(self, item):
     print('首先访问我!')
return super(Test, self).__getattribute__(item) def __getattr__(self, item): print(item,"Not Found") if __name__ == '__main__': test = Test() print(test.age)
首先访问我!
age Not Found None

再次编写代码可知,当代码添加入__getattr__方法时,代码不会报错,且首先访问__getattribute__。

结论:当__getattribute____getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError

拓展:
class Test(object):
    def __init__(self,name):
        self.name = name


    def __getattribute__(self, item):
        print('首先访问我')
        # print(self.__dict__)      #在访问__dict__时同时首先访问__getattribute__引起无       限递归

        return super(Test, self).__getattribute__(item)
        # return self.__dict__(item)
    def __getattr__(self, item):
        print(item,"Not Found")


if __name__ == '__main__':
    test = Test("小明")
    print(test.name)        
 

因为getattribute在访问属性的时候一直会被调用,自定义的getattribute方法里面同时需要返回相应的属性,通过self.__dict__取值会继续向下调用getattribute,造成循环调用。

这里通过调用绑定的super对象来获取对应的属性,对新式类来说其实和object.__getattribute__(self, item)一样的道理:

默认情况下自定义的类会从object继承getattribute方法,对于属性的查找是完全能用的
getattribute的实现感觉还是挺抽象化的,只需要绑定相应的实例对象和要查找的属性名称就行

 


猜你喜欢

转载自www.cnblogs.com/yiyilife/p/11751048.html