from collections import defaultdict
class History:
def __init__(self):
self.__dict__ = defaultdict()
def __getattr__(self,name):
if name[0] not in self.__dict__:
raise NameError
return self.__dict__[name]
def __getitem__(self,index):
pass
def __setattr__(self,name,value):
if name[0] in self.__dict__:
self.__dict__[name]= value
elif name[0] not in self.__dict__:
if '_prev' in name:
raise NameError
else:
self.__dict__[name]= value
if __name__ == '__main__':
# Put in simple tests for History before allowing driver to run
print()
import driver
driver.default_file_name = 'bsc2.txt'
# driver.default_show_traceback = True
# driver.default_show_exception = True
# driver.default_show_exception_message = True
driver.driver()
编写__getattr__
方法以允许具有任意数量(一个或多个)_prev
后缀的属性的名称返回正确的(前一个,上一个到上一个,等等提示:{{1方法)值。如果str.count
中的某个数字(一个或多个)未显示为后缀的一部分,或者第一个_prev
后缀之前的名称不是该类的属性,请引发_prev
带有描述问题/值的适当字符串的异常。如果_prev后缀的数量太大(之前的值不是很多),则此方法应返回值NameError
。
我正在研究None
方法。列出了正确的结果:
__getattr__(self,name)
但是我没有返回最后有'_prev'的值,导致以下错误:
e-->x.a-->3
^-->x.q__prev-->NameError # a new test
e-->x.a_prev-->2
e-->x.a_prev_prev-->1
e-->x.a_prev_prev_prev-->None
^-->x.c_prev_prev-->NameError
有人可以告诉我如何解决它吗? (函数 17 *Error: x.a_prev raised exception KeyError: 'a_prev'
18 *Error: x.a_prev_prev raised exception KeyError: 'a_prev_prev'
19 *Error: x.a_prev_prev_prev raised exception KeyError: 'a_prev_prev_prev'
)
答案 0 :(得分:0)
如果我理解你想要做什么,你想(必须?)写一个提供所有属性历史的类。
要实现此目的,您需要保留所有先前值的备份。您可以使用第二个字典(我称之为我的history
)并在覆盖它们之前将旧值移动到那里。如果要访问历史记录,请计算找到的"_prev"
个后缀的数量,并为该属性的历史记录列表编制索引。
class History:
def __init__(self):
self.history = dict()
def __getattr__(self, name):
# how many steps to go back
offset = name.count("_prev")
# keep only the attribute name. There most certainly is a better way to do this.
attr_name = name.split("_prev")[0]
if attr_name not in self.__dict__:
raise NameError
elif (attr_name not in self.history) and (offset > 0):
# return None for values that do not have a history yet
return None
else:
if offset > len(self.history[attr_name]):
# return None for all queries running out of the history
# like a_prev_prev_prev for only two set values
return None
else:
# return the 'historic' value.
# subtract one for the active value
return self.history[attr_name][offset-1]
def _save_old_value(self, name):
if name in self.history:
# attribute is already in the history
# prepend the activ value it to the history list
self.history[name].insert(0, self.__dict__[name])
else:
# attribute is not in the history
# create new list in the history dict
self.history[name] = [self.__dict__[name]]
def __setattr__(self, name, value):
if name in self.__dict__:
# the attribute has already been set so you need to backup the value
self._save_old_value(name)
self.__dict__[name] = value
elif name not in self.__dict__:
# the attribute is new
if '_prev' in name:
# prevent attribute names with _prev suffix so
# that the user can not destroy the history
raise NameError
else:
# everything is fine, add the value
self.__dict__[name] = value
对我来说,这个问题已经解决了。希望这涵盖了所有边缘情况:
h = History()
h.a = 1
h.a = 2
h.a = 3
h.a = 4
h.b = 17
h.a
4
h.a_prev
3
h.a_prev_prev
2
h.a_prev_prev_prev
1
h.a_prev_prev_prev_prev
None
h.b
17
h.b_prev
None
h.x
NameError
h.x_prev
NameError