__getattribute__
我们根据一个小栗子,来更好的理解 __getattribute__的用法:
-- python2:
class Tree(object): #继承object def __init__(self,name): self.name = name self.cate = 'plant' def __getattribute__(self, item): print 'haha' return object.__getattribute__(self,item) a = Tree('大树') print a.name
结果:
haha
大树
class Tree(): #不继承object def __init__(self,name): self.name = name self.cate = 'plant' def __getattribute__(self, item): print 'haha' return object.__getattribute__(self,item) a = Tree('大树') print a.name
结果:
大树
为什么会出现这个结果呢?
__getattribute__是属性拦截器, 就是当这个类的属性被访问时, 会自动调用类的 __getattribute__方法. 即在上面的代码中, 当我们调用实例对象a的name属性时, 不会直接打印, 而是把属性名name作为实参, 传进__getattribute__方法中, 经过一系列操作后, 再把name的值返回. 并且还能看出, 只有继承object 时, 属性拦截器才会发挥作用, 所以, python中只要定义了继承object的类( python3默认继承object ), 就默认存在属性拦截器. 所以我们可以自己改写 __getattribute__方法来实现相关功能, 比如查看权限, 打印log日志等.
另外, 在使用__getattribute__方法时要注意:
不能在__getattribute__中自调用对象的属性, 会造成死循环.
class Tree(object): def __init__(self, name): self.name = name self.cate = "plant" def __getattribute__(self, *args, **kwargs): if args[0] == 'name': print("log 大树") return "我爱大树" else: return self.call_wind() def call_wind(self): return '刮大风,下大雨' aa = Tree("大树") print(aa.name) print(aa.cate)
结果:
log 大树 我爱大树 Traceback (most recent call last): File "D:/test.py", line 18, in <module> print(aa.cate) File "D:/test.py", line 11, in __getattribute__ return self.call_wind() File "D:/test.py", line 11, in __getattribute__ return self.call_wind() File "D:/test.py", line 11, in __getattribute__ return self.call_wind() [Previous line repeated 995 more times] File "D:/test.py", line 7, in __getattribute__ if args[0] == 'name': RecursionError: maximum recursion depth exceeded in comparison
结果分析: 当执行 aa.cate 时, 先调用__getattribute__方法,经过判断后, 返回 self.call_wind(), 但是当调用 aa的call_wind() 属性时, 又要去调用 __getattribute__方法, 反反复复, 最终超过最大递归限度.
__getattribute__ 和 __getattr__ 的最大差异在于:
1. 无论调用对象的什么属性, 包括不存在的属性, 都会首先调用 __getattribute__方法;
2. 只有调用的对象属性不存在时, 才会调用 __getattr__方法.