10

我想模仿一个普通的 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]

这确实适用于其他方法,例如appendand extend,但不适用于切片操作。

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

4

4 回答 4

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)
于 2009-07-23T08:28:12.073 回答
5

来自Python 3 文档

__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).
于 2009-07-22T17:42:44.010 回答
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)
于 2009-07-22T17:44:57.110 回答
4

__getslice__调用和的情况__setslice__非常狭窄。具体来说,切片仅在您使用常规切片时发生,其中第一个和结束元素只被提及一次。对于任何其他切片语法,或者根本没有切片,__getitem__或者__setitem__被调用。

于 2009-07-22T18:41:17.013 回答