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