飘逸的python - __get__ vs __getattr__ vs __getattribute__以及属性的搜索策略

差别:

__getattribute__:是无条件被调用.对不论什么对象的属性訪问时,都会隐式的调用__getattribute__方法,比方调用t.__dict__,事实上运行了t.__getattribute__("__dict__")函数.所以假设我们在重载__getattribute__中又调用__dict__的话,会无限递归,用object大神来避免,即object.__getattribute__(self, name).

__getattr__:仅仅有__getattribute__找不到的时候,才会调用__getattr__.

__get__:是descriptor.

如果我们有个类A,当中a是A的实例

a.x时发生了什么?

属性的lookup顺序例如以下:

  1. 假设重载了__getattribute__,则调用.
  2. a.__dict__, 实例中是不同意有descriptor的,所以不会遇到descriptor
  3. A.__dict__, 也即a.__class__.__dict__ .假设遇到了descriptor,优先调用descriptor.
  4. 沿着继承链搜索父类.搜索a.__class__.__bases__中的全部__dict__. 假设有多重继承且是菱形继承的情况,按MRO(Method Resolution Order)顺序搜索.

假设以上都搜不到,则抛AttributeError异常.

ps.从上面能够看到,dot(.)操作是昂贵的,非常多的隐式调用,特别注重性能的话,在高频的循环内,能够考虑绑定给一个暂时局部变量.

以下给个代码片段大家自己去把玩探索.

class C(object):
    def __setattr__(self, name, value):
        print "__setattr__ called:", name, value
        object.__setattr__(self, name, value)

    def __getattr__(self, name):
        print "__getattr__ called:", name

    def __getattribute__(self, name):
        print "__getattribute__ called:",name
        return object.__getattribute__(self, name)

c = C()
c.x = "foo"
print c.__dict__['x']
print c.x
时间: 2024-08-29 22:33:02

飘逸的python - __get__ vs __getattr__ vs __getattribute__以及属性的搜索策略的相关文章

python中__get__ vs __getattr__ vs __getattribute__以及属性的搜索策略

其中,__getattribute__是无条件被调用. 对任何对象的属性访问时,都会隐式的调用__getattribute__方法,比如调用t.__dict__,其实执行了t.__getattribute__("__dict__")函数.所以如果我们在重载__getattribute__中又调用__dict__的话,会无限递归,用object大神来避免,即object.__getattribute__(self, name). 只有__getattribute__找不到的时候,才会调用

【7.2】__getattr__、__getattribute__魔法函数

1 #!/user/bin/env python 2 # -*- coding:utf-8 -*- 3 # __getattr__.__getattribute__ 4 # __getattr__ 就是在查找不到属性的时候调用 5 # __getattribute__ 无条件进入__getattribute__ 6 from datetime import date 7 8 9 class User: 10 def __init__(self, name, birthday, info={}):

Python的__getattr__和__getattribute__

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

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 # 使用实例直接

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-魔法函数__getattr__()与__getattribute__()的区别

如果某个类定义了 __getattribute__() 方法,在 每次引用属性或方法名称时 Python 都调用它(特殊方法名称除外,因为那样将会导致讨厌的无限循环). 如果某个类定义了 __getattr__() 方法,Python 将只有在查找不到属性时才会调用它.如果实例 x 定义了属性 color, x.color 将 不会 调用x.__getattr__('color'):而只会返回 x.color 已定义好的值 1 class User: 2 def __init__(self, n

飘逸的python - __new__、__init__、__call__傻傻分不清

__new__: 对象的创建,是一个静态方法.第一个參数是cls.(想想也是,不可能是self,对象还没创建,哪来的self) __init__ : 对象的初始化, 是一个实例方法,第一个參数是self. __call__ : 对象可call.注意不是类,是对象. 先有创建,才有初始化.即先__new__,而后__init__. 上面说的不好理解,看样例. 对于__new__ class Bar(object): pass class Foo(object): def __new__(cls,

【python初级】010-构造方法,属性和迭代器

构造方法,属性和迭代器 目录: -------------构造方法 1.构造方法的基本使用 2.重写一般方法和特殊的构造方法 3.绑定的超类构造方法 4.调用为绑定的超类来构造方法 5.使用super函数 6.成员访问 7.基本的序列和映射规则 8.子类化列表,字典和字符串 -------------属性 -------------迭代器 一:构造方法 在python的心版本中,会有一些特性(比如属性和super函数)不会再老式的类上起作用,为了确保使用的类是新型的,应该把赋值语句metacla

python类内init外声明的属性与init内声明的对象属性的访问和操作区别

python类内init外声明的属性与init内声明的对象属性的访问和操作区别(面试题) 1.在ipython中输入以下代码,其输出会是什么? In [1]: class ClassOut: ...: out_mem = 'out_mem' ...: print out_mem ...: def __init__(self): ...: inner_mem = 'inner_mem' ...: self.inner_mem = 'self.inner_mem' ...: self._inner_