参加校招的时候被面试官问到了,没能答上,主要是混淆了__getattribute__和__getattr__两个魔法方法。因此这里笔记一下。
首先我们看看如何访问一个对象的属性:
class A(object):
def __init__(self):
self.name = "Bob"
self.age = 18
self.gender = "male"
if __name__ == "__main__":
a = A()
print(a.name)
print(a.age)
print(a.gender)
# 输出:
#Bob
#18
#male
如果我们想改变访问属性的逻辑,如执行a.age
语句并非返回18,而是返回问年龄是不礼貌的行为。这里就可以用__getattribute__方法拦截属性,实现我们想要实现的逻辑。
class A(object):
def __init__(self):
self.name = "Bob"
self.age = 18
self.gender = "male"
def __getattribute__(self, attr):
# 拦截age属性
if attr == "age":
return "问年龄是不礼貌的行为"
# 非age属性执行默认操作
else:
return object.__getattribute__(self, attr)
if __name__ == "__main__":
a = A()
print(a.age)
print(a.name)
print(a.gender)
# 输出:
#问年龄是不礼貌的行为
#Bob
#male
事实上,在实例化的对象进行.
操作的时候(形如:a.xxx/a.xxx()
),都会自动去调用__getattribute__方法。但是,如果某个属性在__getattribute__方法中未能找到,此时会调用__getattr__方法。
如我们访问对象a中不存在的属性,会得到异常。比方执行print(a.NAME)
语句,运行结果如下:AttributeError: 'A' object has no attribute 'NAME'
但我就想无论是a.NAME
,a.Name
,还是a.NaME
等等,即n a m e
(包含大小写)四个元素组成的属性,访问结果都同a.name
一样,可以做如下处理:
class A(object):
def __init__(self):
self.name = "Bob"
self.age = 18
self.gender = "male"
def __getattr__(self, attr):
return eval("self."+attr.lower()) #即:再次去执行__getattribute__方法
if __name__ == "__main__":
a = A()
print("a.name -> {}".format(a.name))
print("a.NAME -> {}".format(a.NAME))
print("a.Name -> {}".format(a.Name))
print("a.NaME -> {}".format(a.NaME))
# 输出:
#a.name -> Bob
#a.NAME -> Bob
#a.Name -> Bob
#a.NaME -> Bob
总结:
1.__getattribute__
方法优先级比__getattr__
高
2.只有在__getattribute__
方法中找不到对应的属性时,才会调用__getattr__
3.如果是对不存在的属性做处理,尽量把逻辑写在__getattr__
方法中
4.如果非得重写__getattribute__
方法,需要注意两点:第一是避免.
操作带来的死循环;第二是不要遗忘父类的__getattribute__
方法在子类中起的作用
还不快抢沙发