为什么当我使用 [:] 时,我的子类的 __getitem__ 和 __setitem__ 没有被调用?

Why are my subclass's __getitem__ and __setitem__ not called when I use [:]?

我正在开发 Python 2.7,我正在尝试从继承 list 的 class 重载 __getitem____setitem__

假设我有这个 class A:

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

   def __setitem__(self, key, value):
        print "SET!"        

加上方括号,应该调用A.__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]

__setitem__相同:

a[1] = 2 # prints SET!
a[::] = 2  # prints SET!
a[slice(None)] = 2  # prints SET!
a[:] = [2] # changes the list 

那是因为在 Python 2 [1] [:] 以及具有 start[=61= 的一维切片中] and/or end(但不是在指定 step 时)像 [1:][:3][1:3] 如果实施,则通过 __getslice__ and __setslice__。如果未实施,它们也会转到 __getitem____setitem__)。引用文档:

Notice that these methods [__*slice__] are only invoked when a single slice with a single colon is used, and the slice method is available. For slice operations involving extended slice notation, or in absence of the slice methods, __getitem__(), __setitem__() or __delitem__() is called with a slice object as argument.

在你的情况下,你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__ 方法。