Почему 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__ методы.