【发布时间】:2021-10-03 09:09:26
【问题描述】:
我正在尝试创建一个行为类似于字典的类,除非任何时候调用其方法之一或访问其属性之一时都会记录该事实。 我将通过展示我所做的幼稚实现来阐明我的意思(重复代码被省略号替换):
class logdict(dict):
def __init__(self, *args, **kwargs):
self._log = [
{'name': '__init__',
'args': tuple(map(repr, args)),
'kwargs': dict((key, repr(kwargs[key])) for key in kwargs)
}
]
return super().__init__(*args, **kwargs)
def __getitem__(self, key):
self._log.append({
'name': '__getitem__',
'args': (repr(key),),
'kwargs': {}
})
return super().__getitem__(key)
def __setitem__(self, key, value):
...
def __delitem__(self, key):
...
def __getattribute__(self, name):
if name == '_log': #avoiding infinite recursion
return super().__getattribute__(name)
...
def __contains__(self, key):
...
def logrepr(self):
log = ''
for logitem in self._log: #this is just formatting, nothing interesting here
log += '{fun}({rargs}{optsep}{rkwargs})\n'.format(
fun = logitem['name'],
rargs = ', '.join(logitem['args']),
optsep = ', ' if len(logitem['kwargs'])>0 else '',
rkwargs = ', '.join('{} = {}'.format(key, logitem['kwargs'][key])
for key in logitem['kwargs'])
)
return log
在这里,至少对于我重载的方法,我正在保存正在调用的方法及其参数的 repr(如果我只是保存了参数,我可能会看到最新的“版本”可变对象而不是旧对象)。 这个实现有点工作:
d = logdict()
d['1'] = 3
d['1'] += .5
print('1' in d)
print('log:')
print(d.logrepr())
产生:
True
log:
__init__()
__setitem__('1', 3)
__getitem__('1')
__setitem__('1', 3.5)
__contains__('1')
__getattribute__('logrepr')
但是它相当笨重,我不确定我是否涵盖了所有可能的方法。 有没有更有效的方法来做到这一点,理想情况下可以推广到任何给定的类(并且包装和记录所有 dunder 方法,而不仅仅是可见的方法)?
注意:这不是this question 的重复,因为其中的问题是如何避免无限递归,而不是如何自动化/简化编写派生类的过程。
【问题讨论】:
标签: python python-3.x oop metaprogramming