Перехват операций среза в Python
Я хочу подражать нормальному списку 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]
Это работает для других методов, таких как append
и extend
, только для операций среза.
EDIT: Реальная проблема заключается в том, что я использую Jython, а не Python и забыл об этом. Комментарии по этому вопросу верны. Этот код отлично работает в Python (2.6). Однако код и ответы не работают в Jython.
Ответы
Ответ 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
"setslice" и "delslice" устарели, если вы хотите выполнить перехват, вам нужно работать с объектами среза python, переданными в "setitem" и "delitem". Если вы хотите инцелектировать как срезы, так и обычные обращения, этот код отлично работает в 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)
Ответ 3
Достаточно спекуляции. Давайте начнем использовать факты, не так ли?
Насколько я могу судить, суть в том, что вы должны переопределить оба набора методов.
Если вы хотите реализовать отмену/повтор, вы, вероятно, должны попробовать использовать стопку отмены и множество действий, которые могут выполнять()/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)
Ответ 4
обстоятельства, в которых вызываются __getslice__
и __setslice__
, довольно узкие. В частности, нарезка происходит только тогда, когда вы используете обычный срез, где первый и конечный элементы упоминаются ровно один раз. для любого другого синтаксиса среза или вообще не имеет срезов, вызывается __getitem__
или __setitem__
.