Tutorial :Intercept slice operations in Python



Question:

I want to imitate a normal python list, except whenever elements are added or removed via slicing, I want to 'save' the list. Is this possible? This was my attempt but it will never print 'saving'.

class InterceptedList(list):        def addSave(func):          def newfunc(self, *args):              func(self, *args)              print 'saving'          return newfunc        __setslice__ = addSave(list.__setslice__)      __delslice__ = addSave(list.__delslice__)    >>> l = InterceptedList()  >>> l.extend([1,2,3,4])  >>> l  [1, 2, 3, 4]  >>> l[3:] = [5] # note: 'saving' is not printed  >>> l  [1, 2, 3, 5]  

This does work for other methods like append and extend, just not for the slice operations.

EDIT: The real problem is I'm using Jython and not Python and forgot it. The comments on the question are correct. This code does work fine in Python (2.6). However, the code nor the answers work in Jython.


Solution:1

From the Python 3 docs:

__getslice__(), __setslice__() and __delslice__() were killed.   The syntax a[i:j] now translates to a.__getitem__(slice(i, j))   (or __setitem__() or __delitem__(), when used as an assignment   or deletion target, respectively).  


Solution:2

That's enough speculation. Let's start using facts instead shall we? As far as I can tell, the bottom line is that you must override both set of methods.

If you want to implement undo/redo you probably should try using undo stack and set of actions that can do()/undo() themselves.

Code

import profile  import sys    print sys.version    class InterceptedList(list):        def addSave(func):          def newfunc(self, *args):              func(self, *args)              print 'saving'          return newfunc        __setslice__ = addSave(list.__setslice__)      __delslice__ = addSave(list.__delslice__)      class InterceptedList2(list):        def __setitem__(self, key, value):          print 'saving'          list.__setitem__(self, key, value)        def __delitem__(self, key):          print 'saving'          list.__delitem__(self, key)      print("------------Testing setslice------------------")  l = InterceptedList()  l.extend([1,2,3,4])  profile.run("l[3:] = [5]")  profile.run("l[2:6] = [12, 4]")  profile.run("l[-1:] = [42]")  profile.run("l[::2] = [6,6]")    print("-----------Testing setitem--------------------")  l2 = InterceptedList2()  l2.extend([1,2,3,4])  profile.run("l2[3:] = [5]")  profile.run("l2[2:6] = [12,4]")  profile.run("l2[-1:] = [42]")  profile.run("l2[::2] = [6,6]")  

Jython 2.5

C:\Users\wuu-local.pyza\Desktop>c:\jython2.5.0\jython.bat intercept.py  2.5.0 (Release_2_5_0:6476, Jun 16 2009, 13:33:26)  [Java HotSpot(TM) Client VM (Sun Microsystems Inc.)]  ------------Testing setslice------------------  saving           3 function calls in 0.035 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 <string>:0(<module>)          1    0.000    0.000    0.000    0.000 intercept.py:9(newfunc)          1    0.034    0.034    0.035    0.035 profile:0(l[3:] = [5])          0    0.000             0.000          profile:0(profiler)      saving           3 function calls in 0.005 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.001    0.001 <string>:0(<module>)          1    0.001    0.001    0.001    0.001 intercept.py:9(newfunc)          1    0.004    0.004    0.005    0.005 profile:0(l[2:6] = [12, 4])          0    0.000             0.000          profile:0(profiler)      saving           3 function calls in 0.012 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 <string>:0(<module>)          1    0.000    0.000    0.000    0.000 intercept.py:9(newfunc)          1    0.012    0.012    0.012    0.012 profile:0(l[-1:] = [42])          0    0.000             0.000          profile:0(profiler)               2 function calls in 0.004 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 <string>:0(<module>)          1    0.004    0.004    0.004    0.004 profile:0(l[::2] = [6,6])          0    0.000             0.000          profile:0(profiler)      -----------Testing setitem--------------------           2 function calls in 0.004 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 <string>:0(<module>)          1    0.004    0.004    0.004    0.004 profile:0(l2[3:] = [5])          0    0.000             0.000          profile:0(profiler)               2 function calls in 0.006 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 <string>:0(<module>)          1    0.006    0.006    0.006    0.006 profile:0(l2[2:6] = [12,4])          0    0.000             0.000          profile:0(profiler)               2 function calls in 0.004 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 <string>:0(<module>)          1    0.004    0.004    0.004    0.004 profile:0(l2[-1:] = [42])          0    0.000             0.000          profile:0(profiler)      saving           3 function calls in 0.007 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.002    0.002 <string>:0(<module>)          1    0.001    0.001    0.001    0.001 intercept.py:20(__setitem__)          1    0.005    0.005    0.007    0.007 profile:0(l2[::2] = [6,6])          0    0.000             0.000          profile:0(profiler)  

Python 2.6.2

C:\Users\wuu-local.pyza\Desktop>python intercept.py  2.6 (r26:66721, Oct  2 2008, 11:35:03) [MSC v.1500 32 bit (Intel)]  ------------Testing setslice------------------  saving           4 function calls in 0.002 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.002    0.002    0.002    0.002 :0(setprofile)          1    0.000    0.000    0.000    0.000 <string>:1(<module>)          1    0.000    0.000    0.000    0.000 intercept.py:9(newfunc)          1    0.000    0.000    0.002    0.002 profile:0(l[3:] = [5])          0    0.000             0.000          profile:0(profiler)      saving           4 function calls in 0.000 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 :0(setprofile)          1    0.000    0.000    0.000    0.000 <string>:1(<module>)          1    0.000    0.000    0.000    0.000 intercept.py:9(newfunc)          1    0.000    0.000    0.000    0.000 profile:0(l[2:6] = [12, 4])          0    0.000             0.000          profile:0(profiler)      saving           4 function calls in 0.000 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 :0(setprofile)          1    0.000    0.000    0.000    0.000 <string>:1(<module>)          1    0.000    0.000    0.000    0.000 intercept.py:9(newfunc)          1    0.000    0.000    0.000    0.000 profile:0(l[-1:] = [42])          0    0.000             0.000          profile:0(profiler)               3 function calls in 0.000 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 :0(setprofile)          1    0.000    0.000    0.000    0.000 <string>:1(<module>)          1    0.000    0.000    0.000    0.000 profile:0(l[::2] = [6,6])          0    0.000             0.000          profile:0(profiler)      -----------Testing setitem--------------------           3 function calls in 0.000 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 :0(setprofile)          1    0.000    0.000    0.000    0.000 <string>:1(<module>)          1    0.000    0.000    0.000    0.000 profile:0(l2[3:] = [5])          0    0.000             0.000          profile:0(profiler)               3 function calls in 0.000 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 :0(setprofile)          1    0.000    0.000    0.000    0.000 <string>:1(<module>)          1    0.000    0.000    0.000    0.000 profile:0(l2[2:6] = [12,4])          0    0.000             0.000          profile:0(profiler)               3 function calls in 0.000 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 :0(setprofile)          1    0.000    0.000    0.000    0.000 <string>:1(<module>)          1    0.000    0.000    0.000    0.000 profile:0(l2[-1:] = [42])          0    0.000             0.000          profile:0(profiler)      saving           4 function calls in 0.003 CPU seconds       Ordered by: standard name       ncalls  tottime  percall  cumtime  percall filename:lineno(function)          1    0.000    0.000    0.000    0.000 :0(setprofile)          1    0.000    0.000    0.003    0.003 <string>:1(<module>)          1    0.002    0.002    0.002    0.002 intercept.py:20(__setitem__)          1    0.000    0.000    0.003    0.003 profile:0(l2[::2] = [6,6])          0    0.000             0.000          profile:0(profiler)  


Solution:3

"setslice" and "delslice" are deprecated, if you want to do the interception you need to work with python slice objects passed to "setitem" and "delitem". If you want to intecept both slices and ordinary accesses this code works perfectly in python 2.6.2.

class InterceptedList(list):    def addSave(func):      def newfunc(self, *args):          func(self, *args)          print 'saving'      return newfunc    def __setitem__(self, key, value):      print 'saving'      list.__setitem__(self, key, value)    def __delitem__(self, key):      print 'saving'      list.__delitem__(self, key)  


Solution:4

the circumstances where __getslice__ and __setslice__ are called are pretty narrow. Specifically, slicing only occurs when you use a regular slice, where the first and end elements are mentioned exactly once. for any other slice syntax, or no slices at all, __getitem__ or __setitem__ is called.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »