Python中拦截切片操作

发布于 2024-07-29 00:52:01 字数 756 浏览 11 评论 0原文

我想模仿一个普通的 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 中都有效。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

栩栩如生 2024-08-05 00:52:01

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

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).
听,心雨的声音 2024-08-05 00:52:01

这已经够猜测了。 让我们开始使用事实吧?
据我所知,底线是您必须重写这两组方法。

如果你想实现撤消/重做,你可能应该尝试使用撤消堆栈和一组可以 do()/undo() 本身的操作。

代码

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)

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)
海夕 2024-08-05 00:52:01

“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)

"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)
后知后觉 2024-08-05 00:52:01

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文