How to append a modified list into a list?

Peter Otten __peter__ at web.de
Sat Nov 19 04:40:06 EST 2016


jfong at ms4.hinet.net wrote:

> I have a working list 'tbl' and recording list 'm'. I want to append 'tbl'
> into 'm' each time when the 'tbl' was modified. I will record the change
> by append it through the function 'apl'.
> 
> For example:
> 
>>>>tbl=[0,0]
>>>>m=[]
> 
>>>>tbl[0]=1
>>>>apl(tbl)
>>>>m
> [[1,0]]
> 
>>>>tbl[1]=2
>>>>apl(tbl)
>>>>m
> [[1,0], [1,2]]
> 
> How to define this function properly?
> 
> Obviously the most intuitive way doesn't work.
> def apl0(tbl):
>     m.append(tbl)
> 
> and introducing a local variable will not help either.
> def apl1(tbl):
>     w=tbl
>     m.append(w)
> 
> I figure out a workable way, but looks ugly.
> def apl2(tbl):
>     w=[]
>     w[:]=tbl
>     m.append(w)
> 
> I know those binding tricks between names and objects. Just wondering if
> there is an elegant way of doing this:-)
> 
> --Jach

And now for something completely different ;)

What if you only record the changes to the list? For a long list that would 
save space at the expense of calculation time. For example:

$ cat list_history.py
import collections
from itertools import islice

class List(collections.Sequence):
    def __init__(self, items):
        self._items = list(items)
        self._history = []
    def __setitem__(self, index, value):
        if isinstance(index, slice):
            value = list(value)
            old = self._items[index]
            if len(old) != len(value):
                raise ValueError("size changes not supported")
        else:
            old = self._items[index]
        self._history.append((index, old))
        self._items[index] = value
    def __getitem__(self, index):
        return self._items[index]
    def __len__(self):
        return len(self._items)
    def __repr__(self):
        return repr(self._items)
    def historic_state(self, n):
        items = self._items[:]
        for index, value in islice(reversed(self._history), n):
            items[index] = value
        return items
    def history_len(self):
        return len(self._history) + 1

if __name__ == "__main__":
    items = List("abcdefghijk")
    print(items)
    # apply some changes
    items[3] = "foo"
    items[7] = "bar"
    items[3] = 42
    items[3:6] = "xyz"
    items[5:7] = (1, 2)
    print(items)
    # let's go back in time
    for i in range(items.history_len()):
        print("#{}: {}".format(i, items.historic_state(i)))
$ python3 list_history.py 
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
['a', 'b', 'c', 'x', 'y', 1, 2, 'bar', 'i', 'j', 'k']
#0: ['a', 'b', 'c', 'x', 'y', 1, 2, 'bar', 'i', 'j', 'k']
#1: ['a', 'b', 'c', 'x', 'y', 'z', 'g', 'bar', 'i', 'j', 'k']
#2: ['a', 'b', 'c', 42, 'e', 'f', 'g', 'bar', 'i', 'j', 'k']
#3: ['a', 'b', 'c', 'foo', 'e', 'f', 'g', 'bar', 'i', 'j', 'k']
#4: ['a', 'b', 'c', 'foo', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
#5: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']





More information about the Python-list mailing list