__getattr__和__setattr__捕捉属性的一个引用
__getattr__方法是拦截属性点号运算。更确切地说,当通过对未定义(不存在)属性名称和实例进行点号运算时,就会用属性名称为字符串调用这个方祛。如果Python可通过其继承树搜索流程找到这个属性,该方法就不会被调用.因为有这种情况,__getattr__可以作为钩子来通过通用的方式响应属性请求。例子如下。
#!/usr/bin/env python # -*- coding:utf-8 -*- class empty: def __getattr__(self, attrname): if attrname == "age": return 40 else: raise ArithmeticError x = empty() print(x.age)
运行结果:
40
如果想使用这个方法,要确定是对属性字典做索引运算,来赋值任何实例的。使用self.__dict__['name'] = x,而不是self,name = x。
#!/usr/bin/env python # -*- coding:utf-8 -*- class accesscontrol: def __setattr__(self, key, value): if key == 'age': self.__dict__[key] = value else: raise AttributeError x = accesscontrol() x.age = 40 print(x.age)
运行结果:
40
模拟实例属性的私有性
下列程序代码把上一个例子通用化了.让每个子类都有自己的私有变量名,这些变量名无法通过其实例进行赋值。
#!/usr/bin/env python # -*- coding:utf-8 -*- class PrivateExc(Exception):pass class Privacy: def __setattr__(self, attrname, value): if attrname in self.privates: raise PrivateExc(attrname,self) else: self.__dict__[attrname] = value class Test1(Privacy): privates = ['age'] class Test2(Privacy): privates = ['name', 'pay'] def __init__(self): self.__dict__['name'] = 'Tom' x = Test1() y = Test2() x.name = 'Bob' print(x.name) # y.name = 'Sue' # <== fails # x.age = 40 # <== fails y.age = 30 print(y.age)
运行结果:
Bob 30