在Python中拦截切片操作

时间:2009-07-22 17:18:31

标签: python methods jython slice intercept

我想模仿一个普通的python列表,除非通过切片添加或删除元素,我想“保存”列表。这可能吗?这是我的尝试,但它永远不会打印“保存”。

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]

这适用于appendextend等其他方法,而不适用于切片操作。

编辑:真正的问题是我使用的是Jython而不是Python而忘了它。对这个问题的评论是正确的。这段代码在Python(2.6)中运行良好。但是,代码和答案都适用于Jython。

4 个答案:

答案 0 :(得分:5)

来自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).

答案 1 :(得分:5)

“setslice”和“delslice”已弃用,如果你想进行拦截,你需要处理传递给“setitem”和“delitem”的python切片对象。如果你想要截断两个切片和普通访问,这个代码在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)

答案 2 :(得分:5)

这是足够的推测。让我们开始使用事实而不是吗? 据我所知,底线是您必须覆盖这两组方法。

如果要实现撤消/重做,您可能应该尝试使用撤消堆栈和可以执行()/撤消()操作的操作集。

代码

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)

答案 3 :(得分:4)

调用__getslice____setslice__的情况非常狭窄。具体而言,切片仅在使用常规切片时发生,其中第一个和最终元素仅提及一次。对于任何其他切片语法,或根本没有切片,将调用__getitem____setitem__