成都 直播 网站建设,wordpress与oss,如何做自已网站,苏州网站建设点一点起步
python的提供一系列和属性访问有关的特殊方法#xff1a;__get__, __getattr__, __getattribute__, __getitem__ 。本文阐述它们的区别和用法。
属性的访问机制
一般情况下#xff0c;属性访问的默认行为是从对象的字典中获取#xff0c;并当获取不到时会沿着一定的查找…起步
python的提供一系列和属性访问有关的特殊方法__get__, __getattr__, __getattribute__, __getitem__ 。本文阐述它们的区别和用法。
属性的访问机制
一般情况下属性访问的默认行为是从对象的字典中获取并当获取不到时会沿着一定的查找链进行查找。例如 a.x 的查找链就是从 a.__dict__[x] 然后是 type(a).__dict__[x] 再通过 type(a) 的基类开始查找。
若查找链都获取不到属性则抛出 AttributeError 异常。
__getattr__ 方法
这个方法是当对象的属性不存在是调用。如果通过正常的机制能找到对象属性的话不会调用 __getattr__ 方法。
class A:
a 1
def __getattr__(self, item):
print(__getattr__ call)
return item
t A()
print(t.a)
print(t.b)
# output
1
__getattr__ call
b
__getattribute__ 方法
这个方法会被无条件调用。不管属性存不存在。如果类中还定义了 __getattr__ 则不会调用 __getattr__() 方法除非在 __getattribute__ 方法中显示调用__getattr__() 或者抛出了 AttributeError 。
class A:
a 1
def __getattribute__(self, item):
print(__getattribute__ call)
raise AttributeError
def __getattr__(self, item):
print(__getattr__ call)
return item
t A()
print(t.a)
print(t.b)
所以一般情况下为了保留 __getattr__ 的作用__getattribute__() 方法中一般返回父类的同名方法
def __getattribute__(self, item):
return object.__getattribute__(self, item)
使用基类的方法来获取属性能避免在方法中出现无限递归的情况。
__get__ 方法
这个方法比较简单说明它与前面的关系不大。
如果一个类中定义了 __get__(), __set__() 或 __delete__() 中的任何方法。则这个类的对象称为描述符。
class Descri(object):
def __get__(self, obj, typeNone):
print(call get)
def __set__(self, obj, value):
print(call set)
class A(object):
x Descri()
a A()
a.__dict__[x] 1 # 不会调用 __get__
a.x # 调用 __get__
如果查找的属性是在描述符对象中则这个描述符会覆盖上文说的属性访问机制体现在查找链的不同而这个行文也会因为调用的不同而稍有不一样
如果调用是对象实例(题目中的调用方式)a.x 则转换为调用 。type(a).__dict__[x].__get__(a, type(a))
如果调用的是类属性, A.x 则转换为A.__dict__[x].__get__(None, A)
其他情况见文末参考资料的文档
__getitem__ 方法
这个调用也属于无条件调用这点与 __getattribute__ 一致。区别在于 __getitem__ 让类实例允许 [] 运算可以这样理解
__getattribute__ 适用于所有 . 运算符
__getitem__ 适用于所有 [] 运算符。
class A(object):
a 1
def __getitem__(self, item):
print(__getitem__ call)
return item
t A()
print(t[a])
print(t[b])
如果仅仅想要对象能够通过 [] 获取对象属性可以简单的
def __getitem(self, item):
return object.__getattribute__(self, item)
总结
当这几个方法同时出现可能就会扰乱你了。我在网上看到一份示例还不错稍微改了下
class C(object):
a abc
def __getattribute__(self, *args, **kwargs):
print(__getattribute__() is called)
return object.__getattribute__(self, *args, **kwargs)
# return haha
def __getattr__(self, name):
print(__getattr__() is called )
return name from getattr
def __get__(self, instance, owner):
print(__get__() is called, instance, owner)
return self
def __getitem__(self, item):
print(__getitem__ call)
return object.__getattribute__(self, item)
def foo(self, x):
print(x)
class C2(object):
d C()
if __name__ __main__:
c C()
c2 C2()
print(c.a)
print(c.zzzzzzzz)
c2.d
print(c2.d.a)
print(c[a])
可以结合输出慢慢理解这里还没涉及继承关系呢。总之每个以 __ get 为前缀的方法都是获取对象内部数据的钩子名称不一样用途也存在较大的差异只有在实践中理解它们才能真正掌握它们的用法。
参考