美文网首页
__getattr__和__getattribute__和__s

__getattr__和__getattribute__和__s

作者: MononokeHime | 来源:发表于2018-07-04 11:20 被阅读0次

1.类属性和实例属性

class Foo(object):
    a = 10  # 类属性

    @classmethod
    def foo_cls(cls):
        pass

    def __init__(self):
        self.b = 12  # 实例属性

    def mf(self):
        pass


print(dir(Foo))
print(Foo.__dict__)
foo = Foo()
print(dir(foo))
print(foo.__dict__)
foo.a = 100
print(foo.__dict__)

运行结果

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'foo_cls', 'mf']
{'__module__': '__main__', 'a': 10, 'foo_cls': <classmethod object at 0x104bef048>, '__init__': <function Foo.__init__ at 0x104beb620>, 'mf': <function Foo.mf at 0x104beb598>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'foo_cls', 'mf']
{'b': 12}
{'b': 12, 'a': 100}

注意:

  • 类不可以调用实例属性
  • 对象调用属性的时候,先从对象的__dict__中寻找,如果有,直接返回;如果没有,则从类的__dict__中去找,如果有直接返回,如果没有,则报错
  • 每个对象创建都会有自己的__dict__,因此创建多个对象就会占用很大的内存空间,可以使用solt解决

2.__getattr____getattribute__的使用

当我们调用对象属性的时候,其实内部是隐式的调用魔法函数__getattr____getattribute__。执行顺序:

  1. 先执行__getattribute__(self,item)函数。该函数内部定义了属性的查找顺序,从对象.__dict__再到类.__dict__,一旦找到了就直接返回,不会执行__getattr__。一般不用重新定义,否则使用不当会出现循环递归。
  2. 如果__getattribute__没有找到属性,再执行__getattr__(self,item)函数。
class Foo(object):
    a = 10

    def __init__(self):
        self.b = 12

    def __getattr__(self, item):
        print(item)
        return 120
    
    # def __getattribute__(self, item):
    #     print(item)
    #     return 20  # 一旦这么定义,所有的属性值都是20

foo = Foo()
print(foo.a) # 10。首先执行 __getattribute__函数,类.__dict__中包含了b属性,直接返回
print(foo.b)  # 12。首先执行 __getattribute__函数,对象.__dict__中包含了b属性,直接返回
print(foo.m) # m 120。__getattribute__函数没有找到m属性,所以继续调用__getattr__函数

3.循环递归

如果__getattribute__中调用了对象的属性,那么又会去执行__getattribute__魔法方法,这样就陷入了无穷无尽的递归当中。

class Foo(object):
    a = 10

    def __init__(self):
        self.b = 12

    def __getattr__(self, item):
        print(item)
        return 120

    def __getattribute__(self, item):
        print(item)
        return self.b  # 等价于self.__getattribute__(item),陷入循环递归当中

foo = Foo()
print(foo.b)

结果输出

b
b
b
.
.
.
Traceback (most recent call last):
  File "/Users/Liang/Documents/PyProject/demo1.py", line 18, in <module>
    print(foo.b)
  File "/Users/Liang/Documents/PyProject/demo1.py", line 14, in __getattribute__
    return self.b
  File "/Users/Liang/Documents/PyProject/demo1.py", line 14, in __getattribute__
    return self.b
  File "/Users/Liang/Documents/PyProject/demo1.py", line 14, in __getattribute__
    return self.b
  [Previous line repeated 328 more times]
  File "/Users/Liang/Documents/PyProject/demo1.py", line 13, in __getattribute__
    print(item)
RecursionError: maximum recursion depth exceeded while calling a Python object

4.__setattr__的使用

__setattr__方法

会拦截所有属性的的赋值语句。如果定义了这个方法,self.arrt = value 就会变成self.__setattr__("attr", value).这个需要注意。当在__setattr__方法内对属性进行赋值是,不可使用self.attr = value,因为他会再次调用self.__setattr__("attr", value),则会形成无穷递归循环,最后导致堆栈溢出异常。应该通过对属性字典做索引运算来赋值任何实例属性,也就是使用self.__dict__['name'] = value

class Foo(object):

    def __init__(self):
        print('enter init')
        self.m = 20

    def __setattr__(self, key, value):
        print('set',key,value)
        return self.__dict__.setdefault(key,value)


foo = Foo()  # 打印 ‘enter init’和‘set m 20’。是因为self.m=10会调用__setattr__
foo.n = 10  # 打印 ‘set m 10’
print(foo.n) # 10

相关文章

网友评论

      本文标题:__getattr__和__getattribute__和__s

      本文链接:https://www.haomeiwen.com/subject/riceuftx.html