zoukankan      html  css  js  c++  java
  • 检查一个实例的状态变化

    使用情景:

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

    解决方案:

      一个有效的解决方案是创建一个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方法能够敏锐反映出任何细微的改变。

  • 相关阅读:
    redis发布订阅
    redis学习笔记(面试题)
    redis安全 (error) NOAUTH Authentication required
    HDU3001 Travelling —— 状压DP(三进制)
    POJ3616 Milking Time —— DP
    POJ3186 Treats for the Cows —— DP
    HDU1074 Doing Homework —— 状压DP
    POJ1661 Help Jimmy —— DP
    HDU1260 Tickets —— DP
    HDU1176 免费馅饼 —— DP
  • 原文地址:https://www.cnblogs.com/kirago/p/4839025.html
Copyright © 2011-2022 走看看