我正在开发一个代码库,其设计严重依赖于属性访问。 我想跟踪特定实例的属性访问。 我在想这样的事情会起作用:
class MyDict(dict):
def get(self, key, default=None):
print('get: %r' % key)
return dict.get(self, key, default)
def update(self, *args, **kwargs):
print('update: %r %r' % (args, kwargs))
dict.update(self, *args, **kwargs)
def __getitem__(self, key):
print('getitem: %r' % key)
return dict.__getitem__(self, key)
def __setitem__(self, key, value):
print('setitem: %r %r' % (key, value))
dict.__setitem__(self, key, value)
class Bar:
def __init__(self):
self.__dict__ = MyDict()
b = Bar()
b.baz = 'boz' # 1. should print setitem but doesn't
setattr(b, 'foo', 'fum') # 2. same as above
getattr(b, 'foo') # 3. should print getitem but doesn't
b.foo # 4. same as above
b.__dict__['fix'] = 'fox' # 5. successfully prints setitem message
b.__dict__['fix'] # 6. successfully prints getitem message
print(b.__dict__) # Shows {'baz': 'boz', 'foo': 'fum', 'fix': 'fox'}, as expected
有人可以解释为什么上述 1、2、3 和 4 不能按预期工作吗?为什么 5 和 6 有效?
我认为属性访问(通过 b.foo、getattr 和 setattr)通过 getitem 和 setitem 对底层字典进行操作,但事实似乎并非如此。
谢谢@Sraw。我已经意识到我不需要覆盖dict,我需要覆盖setattr和getattr。这有效:
class Bar:
def __setattr__(self, name, value):
print('setattr: %r %r' % (name, value))
super().__setattr__(name, value)
b = Bar()
b.baz = 'boz'
setattr(b, 'foo', 'fum')
正如预期的那样,输出为:
setattr: 'baz' 'boz'
setattr: 'foo' 'fum'