在类定义中,可以通过传入参数,赋值给self来定义类的属性,当实例化之后就不能更改它的属性了,如果想获取、添加、删除属性怎么办?这就用到这里要讲的4个特殊方法,__setattr__、__getattr__、__getattribute__与__delattr__,它们的功能分别是:
方法 | 功能 |
---|---|
__setattr__ | 设置属性 |
__getattribute__ | 该方法可以拦截对对象属性的所有访问企图,不管该属性存在不存在,当属性被访问时,自动调用该方法(只适用于新式类)。因此常用于实现一些访问某属性时执行一段代码的特性。如果访问属性不存在的时候随后会调用 |
__getattr__ | 调用不存在的属性首先调用__getattribute__方法(如果该方法未定义,会调用基类的__getattribute__方法),触发AttributeError异常并自动捕获,然后才调用__getattr__方法。 |
__delattr__ | 删除属性 |
为了便于说明,我们选择下面的实例:
class Person(): # 默认继承object类
def __init__(self, name):
self.name = name
def __setattr__(self, key, value): # 设置属性
print('in setattr')
object.__setattr__(self, key, value)
def __getattribute__(self, item): # 访问属性必然经过此方法
print("in getattribute")
return object.__getattribute__(item)
# try:
# return super().__getattribute__(item)
# except: # 重载了__getattribute__方法,则object内默认的被覆盖,则需要手动抛出异常
# raise AttributeError # 抛出异常以后立刻进入__getattr__
def __getattr__(self, item): # 访问属性判断
print("in getattr")
try:
return super().__getattribute__(item)
except:
return "Not find attribute: {}".format(item)
def __delattr__(self, item): # 删除属性
print('in delattr',item)
super().__delattr__(item)
person = Person("Murphy")
1. getattribute
print(person.name)
# 输出:
in getattribute
Murphy
对对象属性访问必经过__getattribute__,这里需要注意的是,在返回时必须使用基类(超类) 的方法__getattribute__(使用super,对于简单类使用object),否则会反复调用__getattribute__进入无限循环之中。
2. getattr
print(person.age)
# 输出:
in getattribute
in getattr
Not find attribute: age
当访问不存在的属性时,同样必须经过__getattribute__,所以程序会率先返回in getattribute;
当发现属性不存在时,会抛出AttributeError ,抛出异常以后立刻进入__getattr__程序返回in getattr,并执行后续操作。这里的抛出异常也可以自己定义,详见代码中注释的部分。
3. setattr
person.age = 23
# 输出:
in setattr
设置属性的时候会使用__setattr__方法,如果在使用__init__初始化的时候同样会调用__setattr__方法。
4. delattr
delattr(person,"age")
# 输出:
in delattr age
删除属性时会调用__delattr__方法