另一种方法是将__getattr__ 和__setattr__ 一起覆盖,这样可以避免在类实例对象中对同一属性有两个对象引用(一个OR 到value1 在myobj.mydict['var1'] 中,另一个OR 到@ 987654325@myobj.__dict__['var1']):
class MyClass():
def __init__(self):
self.__dict__['_mydict'] = {'var1': 'value1', 'var2': 'value2'}
#Note: using the @property (descriptor) is optional. I think it makes
#things more convenient.
@property
def mydict(self):
return self._mydict
#NOTE: __getattr__ won't get called if att is found in self.__dict__ first!
def __getattr__(self,att):
if att in self.mydict: # or without using @property: if att in self._mydict:
return self.mydict[att] # return self._mydict[att]
else:
raise AttributeError("'{n}' object has no attribute '{a}'".format(n = type(self).__name__, a = att))
def __setattr__(self,att,val):
super().__setattr__(att, val)
if att in self.mydict:
self.mydict[att] = val # or without using @property: self._mydict[att] = val
self.__delattr__(att) # remove duplicate copy of object reference to att
请注意,这样做意味着您不能向mydict 添加更多键值对,除非您直接调用该属性,例如:
myobj = MyClass()
myobj.x = 1
myobj.mydict #note that result does not contain an entry for 'x'
myobj.mydict['x'] = 2
myobj.mydict #now it does
另请注意,getting 和 deleting mydict 成员将被任何现有的同名属性覆盖(不仅如此,您还不能删除mydict 成员完全,除非您也覆盖__delattr__ 以启用此行为):
#continuing the above code session
assert myobj.x == 1 #myobj.x is coming from self.x, not from self._mydict['x']
myobj.var1 = 'a new value'
myobj.var1 #results in 'a new value' as expected, but where is it coming from?
assert myobj.mydict['var1'] == 'a new value' #Ah: it's coming from self._mydict as expected
assert myobj.__dict__['var1'] #ERROR, as expected
del myobj.x
assert myobj.x == 2 #now myobj.x is coming from self._mydict['x'], self.x having been deleted
del myobj.var1 #raises AttributeError; attributes in mydict can't be deleted (unless you also override __delattr__
如果你想改变这种行为,你必须覆盖__getattribute__(编辑:正如下面的 bruno desthuilliers 所说,这通常不是一个好主意)。