Почему getitem и setitem не вызваны [:]
Я работаю на Python 2.7 и я пытаюсь перегрузить __getitem__ и __setitem__ из класса, который наследует list.
допустим, у меня есть этот класс:
class A(list):
def __getitem__(self, key):
print "GET!"
def __setitem__(self, key, value):
print "SET!"
в квадратные скобки __getitem__ или __setitem__ должен быть вызван. Обычно это так, но когда я использую [:] от родительского класса вызывается. Почему? И почему [::] работы?
a = A([1])
a[1] # prints GET!
a["1"] # prints GET!
a[::] # prints GET!
a[slice(None)] # prints GET!
a[:] # returns the list [1]
и __setitem__:
a[1] = 2 # prints SET!
a[::] = 2 # prints SET!
a[slice(None)] = 2 # prints SET!
a[:] = [2] # changes the list
1 ответов
это потому, что в Python 2 [1][:] а также 1-d ломтики с старт и/или конец (но не шаг указывается) like [1:], [:3] или [1:3] пройти __getslice__ и __setslice__ если они реализуются. Если они не будут реализованы, они также перейдут в __getitem__ и __setitem__). Цитата из документов:
обратите внимание, что эти методы [
__*slice__] являются вызывается только при использовании одного среза с одной двоеточием и метод среза доступен. Для операций среза, включающих расширенную нотацию среза, или при отсутствии методов среза,__getitem__(),__setitem__()или__delitem__()вызывается с объектом slice в качестве аргумента.
в вашем случае вы наследование из них list (list реализует их), поэтому он обходит свой __getitem__ и __setitem__ в простых ситуациях ломтик.
в качестве примера, вы может переопределить __*slice__ методы проверки того, что [:] вызов действительно идет туда:
class A(list):
def __getitem__(self, key):
print "GET!"
def __setitem__(self, key, value):
print "SET!"
def __getslice__(self, i, j):
print "GETSLICE!"
def __setslice__(self, i, j, seq):
print "SETSLICE!"
однако они вызываются только тогда, когда передается только один срез и только если переданный срез не имеет шага. Так что [::] не пойдет туда, потому что у него есть шаг (даже если он неявный). Но также [:,:] не пошел бы в них, потому что он переведен на tuple(slice(None), slice(None)) который является не простым ломтиком, а кортежем ломтиков. Он также не входит в эти __*slice__ методы Если вы проходите в slice пример себя, вот почему [slice(None)] хотя, казалось бы, эквивалентно [:] непосредственно переходит в __*item__ вместо __*slice__.
[1] в Python 3 __*slice__ методы были удалены, поэтому там [whatever] индексирование перейдет в __*item__ методы.