python中__getattr__和__getattribute__区别

  重载__getattr__方法对类及其实例未定义的属性有效。如果访问的属性存在,就不会调用__getattr__方法。这个属性的存在,包括类属性和实例属性

class ClassA:

    x = ‘a‘

    def __init__(self):
        self.y = ‘b‘

    def __getattr__(self, item):
        return ‘__getattr__‘

if __name__ == ‘__main__‘:
    a = ClassA()

    print(a.x)# 输出结果 a
    # 使用实例直接访问实例存在的属性时,不会调用__getattr__方法

    print(a.y) # 输出结果 b
    # 使用实例直接访问实例不存在的属性时,会调用__getattr__方法

    print(a.z) # 输出结果 __getattr__

  __getattribute__仅在新式类中可用,重载__getattrbute__方法对类实例的每个属性访问都有效,无论属性存不存在都会先调用__getattribute__方法

class ClassA:

    x = ‘a‘

    def __init__(self):
        self.y = ‘b‘

    def __getattribute__(self, item):
        return ‘__getattribute__‘

if __name__ == ‘__main__‘:
    a = ClassA()

    # 使用实例直接访问存在的类属性时,会调用__getattribute__方法
    print(a.x)     # 输出结果 __getattribute__

    # 使用实例直接访问实例存在的实例属性时,会调用__getattribute__方法
      print(a.y) # 输出结果 __getattribute__

    # 使用实例直接访问实例不存在的实例属性时,也会调用__getattribute__方法
    print(a.z) # 输出结果 __getattribute__

当同时定义__getattribute__和__getattr__时,__getattr__方法不会再被调用,除非显示调用__getattr__方法或引发AttributeError异常。

class ClassA:

    def __getattr__(self, item):
        print(‘__getattr__‘) 

    def __getattribute__(self, item):
        print(‘__getatttribute__‘)

if __name__ == ‘__main__‘:
    a = ClassA()
    a.x

运行结果
__getatttribute__

由于__getattr__只针对未定义属性的调用,所以它可以在自己的代码中自由地获取其他属性,

而__getattribute__针对所有的属性运行,因此要十分注意避免在访问其他属性时,再次调用自身的递归循环。死循环!!

当在__getattribute__代码块中,再次执行属性的获取操作时,会再次触发__getattribute__方法的调用,代码将会陷入无限递归,直到Python递归深度限制(重载__setter__  __setattr__方法也会有这个问题)。

示例代码(无限递归):

class ClassA:

    x = ‘a‘

    def __getattribute__(self, item):
        print(‘__getattribute__‘)
        return self.item    #再次出现属性的获取操作,会再次触发__getattribute__的调用
                 #相当于return self.__getattribute__(item) 

if __name__ == ‘__main__‘:
    a = ClassA()
    a.x

运行结果,达到最大递归深度
ecursionError: maximum recursion depth exceeded

也没办法通过从__dict__取值的方式来避免无限递归

class ClassA:

    x = ‘a‘

    def __getattribute__(self, name):
        return self.__dict__[name]  #__dict__魔法方法可以查看对象的属性,返回一个字典,键代表属性名  ,这样再次出现属性获取的操作,会再次触发__getattribute__

if __name__ == ‘__main__‘:
    a = ClassA()

    a.x    # 无限递归

为了避免无限递归,应该把获取属性的方法 __getattribute__指向一个更高的超类,例如object(因为__getattribute__只在新式类中可用,而新式类所有的类都显式或隐式地继承自object,所以对于新式类来说,object是所有新式类的超类)。利用super()方法

class ClassA:

    x = ‘a‘    #类属性

    def __getattribute__(self, item):
        print(‘__getattribute__‘)
        return super().__getattribute__(self, item)

if __name__ == ‘__main__‘:
    a = ClassA()
    print(a.x)        #输出__getattribute__                  a

调用__getattr__详细过程如下:
 obj.attribute

  1. 首先会在对象的实例属性中寻找,找不到执行第二步
  2. 来到对象所在的类中查找类属性,如果还找不到执行第三步
  3. 来到对象的继承链上寻找,如果还找不到执行第四步
  4. 调用obj.__getattr__方法,如果用户没有定义或者还是找不到,抛出AttributeError异常,属性查找失败
class MyClass:

    def __init__(self, x):
        self.x = x
>>> obj = MyClass(1)
>>> obj.y

AttributeError: ‘MyClass‘ object has no attribute ‘a‘

如上代码,没有定义__getattr__魔法方法,又找不到属性,就会抛出异常

调用__getattrIbute__方法

当我们调用对象的属性时,首先会调用__getattribute__魔法方法。无论对象存不存在;当__getattribute__查找失败,就会去调用__getattr__方法。

obj.x
obj.__getattribute__(x)
这两个代码其实是等价的

使用__getattribute__魔法方法时,要返回父类的方法,(super函数)不然很难写对!!会导致无限递归!

另外,内置的bif   getattr和hasattr也会触发这个魔法方法__getattribute__!!

其他细节需要注意

_getattribute__的查找顺序

class MyClass:

    x = 999              #类属性x

    def __init__(self, x):    #形参x
        self.x = x         #实例属性x

    def __getattribute__(self, item):

        print(‘正在获取属性{}‘.format(item))
        return super(MyClass, self).__getattribute__(item)

>>> obj = MyClass(2) >>> print(obj.x) 正在获取属性x 2 >>> del obj.x     #删除了实例属性x

>>> print(obj.x)   #此时访问的是类属性 正在获取属性 999

上面代码中,定义了一个类属性x和一个实例属性x,这两个属性同名

根据Python语法规则,当对象获取属性x的时候,首先会在实例属性中寻找,如果找不到才回去类属性中查找

这便是__getattribute__的查找顺序。通常该方法在框架中可能会用到,一般情况下无需使用

另外的

__setattr__(self, name, value)

定义当一个属性被设置时的行为

__delattr__(self, name)

定义当一个属性被删除时的行为

原文地址:https://www.cnblogs.com/hemengjita/p/12288429.html

时间: 2024-08-26 17:22:48

python中__getattr__和__getattribute__区别的相关文章

python中is和==的区别

Python中  is 和 == 的区别的笔记 在 Python 中一切都是对象,毫无例外整数也是对象,对象之间比较是否相等可以用==,也可以用is.==和is操作的区别是: is比较的是两个对象的id值是否相等,也就是比较俩对象是否为同一个实例对象,是否指向同一个内存地址. ==比较的是两个对象的内容是否相等,默认会调用对象的__eq__()方法. 清楚is和==的区别之后,对此也许你有可能会遇到下面的这些困惑,于是就有了这样一篇文章,试图把Python中一些隐晦的东西趴出来,希望对你有一定的

python 中__getattr__ 以及 __setattr__

python 中__getattr__ 以及 __setattr__ 下面是mydict.py: #!/usr/bin/env python class Dict(dict): def __init__(self, **kw): super(Dict, self).__init__(**kw) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(r"'Dict' objec

python中==和is的区别

Python中的对象包含三要素:id.type.value, 其中id用来唯一标识一个对象,type标识对象的类型,value是对象的值.is判断的是a对象是否就是b对象,是通过id来判断的:==判断的是a对象的值是否和b对象的值相等,是通过value来判断的.如下代码或许可以帮助我们理解.>>> a = 1>>> b = 1.0>>> a is bFalse>>> a == bTrue>>> id(a)127770

转载Python中__getattr__ __getattribute__ __get__解释

来源:http://www.myexception.cn/perl-python/620096.html python中__get__,__getattr__,__getattribute__的区别 __get__,__getattr__和__getattribute都是访问属性的方法,但不太相同. object.__getattr__(self, name) 当一般位置找不到attribute的时候,会调用getattr,返回一个值或AttributeError异常. object.__get

Python中classmethod与staticmethod区别

classmethod:类方法staticmethod:静态方法 在python中,静态方法和类方法都是可以通过类对象和类对象实例访问.但是区别是: @classmethod 是一个函数修饰符,它表示接下来的是一个类方法,而对于平常我们见到的则叫做实例方法. 类方法的第一个参数cls,而实例方法的第一个参数是self,表示该类的一个实例. 普通对象方法至少需要一个self参数,代表类对象实例 类方法有类变量cls传入,从而可以用cls做一些相关的处理.并且有子类继承时,调用该类方法时,传入的类变

Python的__getattr__和__getattribute__

__getattr____getattr__在当前主流的Python版本中都可用,重载__getattr__方法对类及其实例未定义的属性有效.也就属性是说,如果访问的属性存在,就不会调用__getattr__方法.这个属性的存在,包括类属性和实例属性. __getattribute____getattribute__仅在新式类中可用,重载__getattrbute__方法对类实例的每个属性访问都有效. 另外,当同时定义__getattribute__和__getattr__时,__getattr

python __setattr__, __getattr__, __delattr__,__getattribute__

参考资料 __setattr__.__getattr__和__delattr__以及__getattribute__可以拦截对对象属性的访问: >>> s = Something() >>> s.age = 3 set 'age' = 3 >>> s.age 3 注意到,s.age并没有调用__getattr__,是因为__getattr__方法只在属性没有找到的时候调用. 虽然相比于Property,实现优点复杂(可能效率更低?),但是足够灵活,功能

Python中__repr__和__str__区别

如下: Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) Type "help", "copyright", "credits" or "license" for >>> class Test(object): ... def __init__(self, value='hello, world!'): ... self.data = value ...

Python中__repr__和__str__区别(转)

class Test(object): def __init__(self, value='hello, world!'): self.data = value >>> t = Test() >>> t <__main__.Test at 0x7fa91c307190> >>> print t <__main__.Test object at 0x7fa91c307190> # 看到了么?上面打印类对象并不是很友好,显示的是对象