Я запускаю Python 2.7.10.
Мне нужно перехватить изменения в списке. Под "изменением" я подразумеваю все, что изменяет список в неглубоком смысле (список не изменяется, если он состоит из одних и тех же объектов в том же порядке, независимо от состояния этих объектов, в противном случае это так). Мне не нужно определять , как список изменился, только тот, который у него есть. Поэтому я просто проверяю, могу ли я это обнаружить, и пусть базовый метод выполняет свою работу. Это моя тестовая программа:
class List(list):
def __init__(self, data):
list.__init__(self, data)
print '__init__(', data, '):', self
def __getitem__(self, key):
print 'calling __getitem__(', self, ',', key, ')',
r = list.__getitem__(self, key)
print '-->', r
return r
def __setitem__(self, key, data):
print 'before __setitem__:', self
list.__setitem__(self, key, data)
print 'after __setitem__(', key, ',', data, '):', self
def __delitem__(self, key):
print 'before __delitem__:', self
list.__delitem__(self, key)
print 'after __delitem__(', key, '):', self
l = List([0,1,2,3,4,5,6,7]) #1
x = l[5] #2
l[3] = 33 #3
x = l[3:7] #4
del l[3] #5
l[0:4]=[55,66,77,88] #6
l.append(8) #7
Дела № 1, № 2, № 3 и № 5 работают так, как я ожидал; # 4, # 6 и # 7 нет. Программа печатает:
__init__( [0, 1, 2, 3, 4, 5, 6, 7] ): [0, 1, 2, 3, 4, 5, 6, 7]
calling __getitem__( [0, 1, 2, 3, 4, 5, 6, 7] , 5 ) --> 5
before __setitem__: [0, 1, 2, 3, 4, 5, 6, 7]
after __setitem__( 3 , 33 ): [0, 1, 2, 33, 4, 5, 6, 7]
before __delitem__: [0, 1, 2, 33, 4, 5, 6, 7]
after __delitem__( 3 ): [0, 1, 2, 4, 5, 6, 7]
Я не очень удивлен # 7: append
, вероятно, реализуется специальным образом. Но для №4 и №6 я смущен. Документация __getitem__
гласит: "Вызывается для реализации оценки self [key]. Для типов последовательностей принятые ключи должны быть целыми и срезами. (мои мотивы). И для __setitem__
:" То же самое, что и для __getitem__
()", что я подразумеваю, что key
также может быть срезом.
Что не так с моими рассуждениями? Я готов, если необходимо, переопределить каждый метод изменения списка (добавление, расширение, вставка, поп и т.д.), Но что нужно переопределить, чтобы поймать что-то вроде # 6?
Я знаю о существовании __setslice__
и т.д. Но эти методы устарели с 2.0...
Хммм. Я снова прочитал документы для __getslice__
, __setslice__
и т.д., И я нахожу это утверждение о том, что:
"(Тем не менее, встроенные типы в CPython по-прежнему реализуют __getslice__()
. Поэтому вы должны переопределить его в производных классах при реализации slicing.)"
Это объяснение? Является ли это высказыванием "Ну, методы устарели, но для достижения такой же функциональности в 2.7.10, как и в версии 2.0, вам все равно придется их переопределять"? Увы, тогда почему вы их осуждали? Как все будет работать в будущем? Есть ли класс "списка", о котором я не знаю, - что я мог бы продлить и не представлял бы это неудобство? Что мне действительно нужно переопределить, чтобы удостовериться, что я поймаю каждую операцию изменения списка?