可以定义object.__getattribute__(self, name)
、object.__setattr__(self, name, value)
、object.__delattr__(self, name)
和object.__getattr__(self, name)
方法来自定义对类实例属性访问(x.name 的使用、赋值或删除)
object.__getattribute__(self, name)
方法此方法会无条件地被调用以实现对类实例属性的访问。如果类还定义了
__getattr__()
,则后者不会被调用,除非__getattribute__()
显式地调用它或是引发了 AttributeError。此方法应当返回属性值或是引发一个 AttributeError 异常。
class MyTest:
def __init__(self, name, age):
self.name = name
self.age = age
def __getattribute__(self, item):
"""
对象访问属性存在时触发的魔术方法
:param item: 属性名
:return: 属性值
"""
print("获取属性对象(__getattribute__): ", end='')
return super().__getattribute__(item)
m = MyTest('allen', 18)
print(m.name) # m.name ===> 本质上触发了:m.__getattribute__('name')
获取属性对象(__getattribute__): allen
object.__setattr__(self, name, value)
方法此方法在一个属性被尝试赋值时被调用。这个调用会取代正常机制(即将值保存到实例字典)。 name 为属性名称, value 为要赋给属性的值。
class MyTest:
def __init__(self, name, age):
self.name = name
self.age = age
def __setattr__(self, key, value):
"""
对象设置属性触发的魔术方法
:param key: 属性名
:param value: 属性值
:return:
"""
print(f"设置属性值(__setattr__):{key}:{value}")
super().__setattr__(key, value)
m = MyTest('allen', 18)
设置属性值(__setattr__):name:allen
设置属性值(__setattr__):age:18
object.__delattr__(self, name)
方法类似于 setattr() 但其作用为删除而非赋值。此方法应该仅在 del obj.name 对于该对象有意义时才被实现。
class MyTest:
def __init__(self, name, age):
self.name = name
self.age = age
def __delattr__(self, item):
"""
删除对象属性触发的魔术方法
:param item: 要删除的属性名
:return:
"""
print(f"删除属性(__delattr__):{item}")
super().__delattr__(item)
m = MyTest('allen', 18)
print("删除前,属性字典:", m.__dict__)
del m.name
print("删除后,属性字典:", m.__dict__)
删除前,属性字典: {'name': 'allen', 'age': 18}
删除属性(__delattr__):name
删除后,属性字典: {'age': 18}
object.__getattr__(self, name)
方法当默认属性访问因引发 AttributeError 而失败时被调用 (可能是调用 getattribute() 时由于 name 不是一个实例属性或 self 的类关系树中的属性而引发了 AttributeError;或者是对 name 特性属性调用 get() 时引发了 AttributeError)。此方法应当返回属性值或是引发一个 AttributeError 异常。
请注意如果属性是通过正常机制找到的,getattr() 就不会被调用。(这是在 getattr() 和 setattr() 之间故意设置的不对称性。)这既是出于效率理由也是因为不这样设置的话 getattr() 将无法访问实例的其他属性。要注意至少对于实例变量来说,你不必在实例属性字典中插入任何值(而是通过插入到其他对象)就可以模拟对它的完全控制。
class MyTest:
def __init__(self, name, age):
self.name = name
self.age = age
def __getattribute__(self, item):
"""
对象访问属性存在时触发的魔术方法
:param item: 属性名
:return: 属性值
"""
print("获取属性对象(__getattribute__): ", end='')
return super().__getattribute__(item)
def __getattr__(self, item):
"""
对象获取属性,属性不存在时触发的魔术方法
:param item:
:return:
"""
print("获取属性对象(__getattr__): ", end='')
return
m = MyTest('allen', 18)
print(m.sex) # 属性不存在,先调用__getattribute__,再调用__getattr__,返回None
获取属性对象(__getattribute__): 获取属性对象(__getattr__): None