__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__方法.

 

 

posted @ 2019-11-05 09:33  yara-ning  阅读(532)  评论(0编辑  收藏  举报