开发者

How to build an undo storage with limit?

I want build a data structure to store limited undo buffer, take store 6 dict data for example with below pseudocode:

rawdict1 = {1}
buffer = [{1}]

rawdict1 = {2}
buffer = [{2}{1}]      # {1} stored on the postion

rawdict1 = {3}
buffer = [{3}{2}{1}]      
...
rawdict1 = {5}
buffer = [{5}{4}{3}{2}{1}]      # max length limited to 5

rawdict1 = {6}
buffer = [{6}{5}{4}{3}{2}]      # {1} has been deleted because exceed the limit

when I want to restore the rawdict1 later, I can use something looks like:

rawdict1 = buffer[5]                 # restore the 5th dict.

My question is, can existing buildin data type or st开发者_JAVA技巧andard library type can be used for such a purpose?

And is it possible such a structure can store multi-types in one structure instance, say, if I want to store dict and self-defined class in one go?

Thanks!

Rgs,

KC


Perhaps use something like this:

import collections

class UndoBuffer(object):
    def __init__(self,value,max_length=5):
        self.max_length=max_length
        self._buffer=collections.deque([value],max_length)
    @property
    def data(self):
        return self._buffer[-1]
    @data.setter
    def data(self,value):
        self._buffer.append(value)
    def restore(self,index):
        self.data=self._buffer[index]

Make an UndoBuffer object

rawdict=UndoBuffer('{1}')      

Setting the data attribute automatically stores the value in _buffer:

print(rawdict._buffer)
# deque(['{1}'], maxlen=5)
print(rawdict.data)
# {1}

Changing the value of rawdict.data appends the value to rawdict._buffer:

rawdict.data = '{2}'
print(rawdict._buffer)
# deque(['{1}', '{2}'], maxlen=5)

Buf if you access rawdict.data you just get the most recent value:

print(rawdict.data)
# {2}

Change the value a few more times. '{1}' gets dropped when the buffer is filled to its maximum length:

rawdict.data = '{3}'
rawdict.data = '{4}'
rawdict.data = '{5}'
print(rawdict._buffer)
# deque(['{1}', '{2}', '{3}', '{4}', '{5}'], maxlen=5)
rawdict.data = '{6}'
print(rawdict._buffer)
# deque(['{2}', '{3}', '{4}', '{5}', '{6}'], maxlen=5)

Restoring the value from rawdict._buffer:

rawdict.restore(0)   # set rawdict.data to rawdict._buffer[0]
print(rawdict.data)
# {2}
print(rawdict._buffer)
# deque(['{3}', '{4}', '{5}', '{6}', '{2}'], maxlen=5)


You cannot do it on a barename (such as rawdict1) because there is no way for you to intercept assignments to a barename and make them do sometime "on the side" such as saving the previous value. It's easy to do on a decorated name, e.g.:

undoable.rawdict1 = {1}

and the like, by making undoable an instance of a class with an appropriate __setitem__ which appends the previous value (if any) to a list, and pops the 0th item if the list is getting too long. But that would not suffice for other "undoable" actions besides assignment, such as undoable.rawdict1.update(whatever) -- you sure you don't need that?


You can quickly subclass the list to only allow limited storage.

class LimitedStack(list):
 def __init__(self,limit=6):
    list.__init__(self)
    self.limit = limit

 def append(self,obj):
    if len(self) == self.limit:
        list.pop(self,0)
    list.append(self,obj)

Python lists do not have to be of a certain type like the generic lists in C#. They will store any object you append to them.


The collections module, as of python 2.6, contains the "deque" collection. It behaves as you need:

>>> import collections
>>> buffer = collections.deque([],6)
>>> buffer.extend(range(6))
>>> buffer
deque([0, 1, 2, 3, 4, 5], maxlen=6)
>>> buffer.append(6)
>>> buffer
deque([1, 2, 3, 4, 5, 6], maxlen=6)
>>> buffer[-1]
6


Rockford Lhotka's CSLA.NET framework contains an Undo architecture. Perhaps you could study it and figure out what he did, or even use it out of the box.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜