【问题标题】:Intercept slice operations in Python在 Python 中拦截切片操作
【发布时间】:2010-11-13 02:28:07
【问题描述】:

我想模仿一个普通的 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,却忘了它。问题上的cmets是正确的。这段代码在 Python (2.6) 中运行良好。但是,代码和答案都可以在 Jython 中使用。

【问题讨论】:

  • 我只是将您的代码复制并粘贴到 python 2.5.1 中,它按预期打印出“保存”。
  • 它在这里工作。 Windows 上的 Python 2.6.2。
  • 使用 2.5.2。在 extend() 操作期间打印“保存”,但在切片分配期间不打印。
  • 可能是因为 setslice 已被弃用 tinyurl.com/kr3gxn
  • 您使用的是什么版本的 jython?

标签: python methods jython slice intercept


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    猜想就够了。让我们开始使用事实吧? 据我所知,底线是您必须覆盖这两组方法。

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

    代码

    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】:

      "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__ 和 __getslice__ 仍然存在并且根本不调用 setitem/getitem 则不正确。
      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多