一、 类实例属性的获取与设置
1. __getattribute__
程序每次访问对象属性时,Python系统都会调用这个特殊的方法,即使属性字典里面已经有了该属性,也依然会触发__getattribute__。
__getattribute__方法下应该避免使用self.attr访问属性,否则会出现无限递归。如要要访问实例属性,应该直接通过super()来做。
2. __getattr__
如果某类定义了__getattr__,同时系统在该类对象的实例字典中又找不到待查询的属性,系统就会调用这个方法,这种行为非常适合无结构数据的按需访问。除非__getattribute__调用它或者出现AttributeError错误,否则__getattr__方法不会被调用。
3. __setattr__ 和 __delattr__
只要对实例属性赋值,无论是直接赋值,还是通过内置的setattr赋值,都会触发__setattr__方法。__setattr__下还有self.attr的赋值操作就会出现无限递归的调用__setattr__的情况。一般情况都还是继承。__setattr__ 和 __delattr__破解无限递归的方法有两种:
(1)我们去调用系统写好的基类,系统的总是最安全的!super()可以帮你找到所有函数的父类
def __setattr__(self,name,value):
super().__setattr__(name,value)
(2)我们要用到一个对象的特殊属性:__dict__它的作用是以字典的属性显示出当前对象的所有属性以及对应的值!比如:{'b': 1}
def __setattr__(self,name,value):
self.__dict__[name] = value
举例如下:
class B(object):
def __init__(self):
self.name = 'tom'
# 同时有__getattribute__和__getattr__时,会先调用前者。
# 只有该属性不存在或出现异常时才会调用后者
def __getattribute__(self, name):
print('Called __getattribute__(%s)' % name)
# # _getattribute__方法下应该避免使用self.attr访问属性,否则会出现无限递归。
# return self.__dict__['name'] #导致无限递归,不能这样用!
return super().__getattribute__(name)
def __getattr__(self, name):
print('Called __getattr__(%s)' % name)
class C:
def __setattr__(self, name, value):
print('Called __setattr__(%s, %r)' % (name, value))
# _setattr__下还有self.attr的赋值操作就会出现无限递归的调用__setattr__的情况。一般情况都还是继承
# 不过对于__setattr__,是能使用 self.__dict__[name] = value
super().__setattr__(name, value)
b=B()
print(b.name)
print(b.fuck)
>>> b = B()
>>> b.a
Called __getattribute__(a)
Called __getattr__(a)
c = C()
c.a = 1
print(c.a)
setattr(c,'d',2)
print(c.__dict__)
二、 为实例添加“.”运算和“[]”运算符支持
转载自
这也是“_ getattribute_”与“_ getitem_”的最大差异,示例如下:
1. “_ getattribute_”只适用于所有的“.”运算符;
2. “_ getitem_”只适用于所有的“[]”运算符;
class Employee(object):
def __init__(self, username, age):
self.username = username
self.age = age
def __getattribute__(self, attr):
return super(Employee, self).__getattribute__(attr)
def __getitem__(self, attr):
return super(Employee, self).__getattribute__(attr)
em = Employee('yiifaa', 32)
print em.username
# 现在支持“[]”运算符
print em['username']
通过实现“_ getitem_”回调接口,现在Employee可以支持“[]”运算符。