访问类属性的先前值

时间:2016-10-20 06:26:46

标签: python

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'

1 个答案:

答案 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