• 检查一个实例的状态变化


    使用情景:

      一个实例在上次“保存”操作之后又被修改了,需要检查它的状态变化以便有选择的保存此实例。

    解决方案:

      一个有效的解决方案是创建一个mixin类,这个类可以从多个类继承并能对一个实例的状态进行快照操作,这样就可以用此实例的当前状态和上次的快照做比较了,来判断是否被修改过了。

     1 import copy
     2 class ChangeCheckerMixin:
     3     containerItems = {dict: dict.iteritems, list: enumerate}
     4     immutable = False
     5     def snapshot(self):
     6                 '''创建self状态的快照',就像浅拷贝,但只对容器的类型进行递归。。''
     7         if self.immutable:
     8             return
     9         self._snapshot = self._copy_container(self.__dict__)
    10     def makeImmutable(self):
    11                 '''实例状态无法被修改 设置.immutable'''
    12         self.immutable = True
    13         try:
    14             del sekf._snapshot
    15         except AttributeError:
    16             pass
    17     def _copy_container(self, container):
    18                 '''对容器类型拷贝'''
    19         new_container = copy.copy(container)
    20         for k, v in self.containerItems[type(new_container)](new_container):
    21             if type(v) in self.containerItems:
    22                 new_container[k] = self._copy_container(v)
    23             elif hasattr(v, 'snapshot'):
    24                 v.snapshot()
    25         return new_container
    26     def isChanged(self):
    27         if self.immutable:
    28             return False
    29         snap = self.__dict__.pop('_snapshot', None)
    30         if snap is None:
    31             return True
    32         try:
    33             return self._checkContainer(self.__dict__, snap)
    34         finally:
    35             self._snapshot = snap
    36     def _checkContainer(self, container, snapshot):
    37         if len(container) != len(snapshot):
    38             return True
    39         for k, v in self.containerItems[type(container)](container):
    40             try:
    41                 ov = snapshot[k]
    42             except LookUpError:
    43                 return True
    44             if self._checkItem(v, ov):
    45                 return True
    46         return False
    47     def _checkItem(self, newitem, olditem):
    48                 '''比较新旧元素,如果它们是容器类型,递归调用self._checkContainer'''
    49         if type(newitem) != type(olditem):
    50             return True
    51         if type(newitem) in self.containerItems:
    52             return self._checkContainer(newitem, olditem)
    53         if newitem is olditem:
    54             method_isChanged = getattr(newitem, 'isChanged', None)
    55             if method_isChanged is None:
    56                 return False
    57             return method_isChanged
    58         return newitem != olditem
    59         
    60         
    61 if __name__ == '__main__':
    62     class eg(ChangeCheckerMixin):
    63         def __init__(self, *arg, **kwargs):
    64             self.L = list(*arg, **kwargs)
    65         def __str__(self):
    66             return 'eg(%s)' % str(self.L)
    67         def __getattr__(self, a):
    68             return getattr(self.L, a)
    69     X = eg('ciao')
    70     print 'x =',X,'is changed =', X.isChanged()
    71     X.snapshot()
    72     print 'x =',X,'is changed =', X.isChanged()
    73     X.append('x')
    74     print 'x =',X,'is changed =', X.isChanged()                

    最后输入结果如下图:

      

    在eg类中只是从ChangeCheckerMixin派生,因为不需要其他基类。即使从list派生也没什么用处,因为状态检查功能只能被用于那些保存在实例的字典里的状态。所以必须将一个list对象放在实例的字典中,并根据情况将某些任务委托给它,(上述示例中通过__getattr__委托了所有的非特殊方法),这样就可以看到isChanged方法能够敏锐反映出任何细微的改变。

  • 相关阅读:
    java后端
    2017-12-11
    二叉树与分治法整理
    javaweb
    安装docker
    爬虫
    lintcode
    DEEPlearning
    剑指offer_by牛客网
    DFS
  • 原文地址:https://www.cnblogs.com/kirago/p/4839025.html
Copyright © 2020-2023  润新知