为什么没有在[:]上调用__getitem__和__setitem__

Ani*_*iol 7 python list slice python-2.7 python-internals

我工作的Python 2.7和我试图超载 __getitem__,并__setitem__从继承的类list.

假设我有这个课程:

 class A(list):
    def __getitem__(self, key):
        print "GET!"

   def __setitem__(self, key, value):
        print "SET!"        
Run Code Online (Sandbox Code Playgroud)

用方括号AA.__getitem__应调用.通常情况就是这样,但是当我使用A.__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]
Run Code Online (Sandbox Code Playgroud)

和以下一样[::]:

a[1] = 2 # prints SET!
a[::] = 2  # prints SET!
a[slice(None)] = 2  # prints SET!
a[:] = [2] # changes the list 
Run Code Online (Sandbox Code Playgroud)

MSe*_*ert 9

这是因为在Python 2 [1] [:],以及与1-d切片开始和/或结束(而不是当步骤指定的)像[1:],[:3][1:3]经过__getslice____setslice__如果它们被执行.如果他们没有实施,他们也会去__getitem____setitem__).引用文档:

请注意,__*slice__仅当使用具有单个冒号的单个切片并且切片方法可用时,才会调用这些方法[ ].对于涉及扩展切片表示法的切片操作,或者没有切片方法__getitem__(),__setitem__()或者__delitem__()使用切片对象作为参数调用.

在你的情况下,你从(实现它们)继承它们,所以它绕过你和简单的切片情况.listlist__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!"  
Run Code Online (Sandbox Code Playgroud)

但是,只有在传入一个切片时才会调用它们,并且只有在传递的切片没有步骤时才会调用它们.所以[::]不会去那里,因为它有一个步骤(即使它是隐含的).但也[:,:]不会进入这些因为它被翻译成tuple(slice(None), slice(None))不是一个简单的切片而是切片的元组.__*slice__如果你slice自己传递一个实例,它也不会进入这些方法,这就是为什么[slice(None)]即使看似相当于[:]直接进入__*item__而不是__*slice__.


[1]在Python 3 __*slice__中删除了方法,因此[whatever]索引将转到__*item__方法中.