1. __getattr__ 和 __getattribute__区别
__getattr__只在没有找到目标属性时调用。很适合作为属性缺失时的缺省回调函数。
__getattribute__在查看对象的实际属性之前调用,需要注意避免无限递归。

一个代码示例来展示两个方法的使用, 创建一个自定义字典, 可以使用 obj.attr 的语法来访问字典内的数据。 如 obj = {"a": "b"} , obj.a 返回 b。 增加一个size属性,返回字典数据个数。
In [1]: from collections import UserDict
...:
...: class DotDict(UserDict):
...: def __init__(self, *args, **kwargs):
...: super().__init__(*args, **kwargs)
...: self.size = len(self)
...:
...: def __getattribute__(self, name: str):
...: return super().__getattribute__(name.lower())
...:
...: def __getattr__(self, name):
...: return self[name]
In [2]: mydict = DotDict(key='value', foo='aloha')
In [3]: mydict.size
Out[3]: 2
In [4]: mydict.SIZE
Out[4]: 2
从以上代码可以看到, 创建一个字典 mydict 之后, mydict.size = 2. 每次使用 . 语法获取对象的属性时, __getattribute__ 方法会将属性名称转为小写, 所以mydict.SIZE == mydict.size 返回 2.
In [5]: mydict.foo
Out[5]: 'aloha'
当使用 mydict.foo 获取属性 foo 的值时, 找不到属性 foo , 此时会调用 __getattr__ , 返回mydict['foo'] 的值, 返回 'aloha'.
2. __setattr__和__delattr__
__setattr__(self, name, value) - 与__getattr__ 不同的 是 , __setattr__ 是一种封装解决方案。它允许你在属性不存在时也可以定义分配给属性的行为。
__delattr__(self, name) - 与 __setattr__ 完全相同,只是是用于删除属性而不是设置。
注意: 使用这两个方法同样要注意避免无限递归。
def __setattr__(self ,name ,value):
self.name = value
如上面代码,__setattr__ 中的 self.name 会再次调用 __setattr__自身,递归将永远持续下去,导致程序崩溃
给DotDict 增加一个函数
class DotDict(UserDict):
...
def __setattr__(self, name, value):
self.__dict__[name] = value
In [6]: mydict.mo = 8989
In [7]: mydict.mo
Out[7]: 8989
可以在 目标对象 没有属性 mo 的时候,对属性进行赋值。
105



被折叠的 条评论
为什么被折叠?



