为什么未在[:]上调用__getitem__和__setitem__?

时间:2018-07-12 08:52:48

标签: python python-2.7 list slice python-internals

我正在使用Python 2.7,并且试图从继承AppData/Local/Microsoft/TypeScript/2.9/node_modules/@types的类中重载__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__

1 个答案:

答案 0 :(得分:8)

那是因为在Python 2中 [1] [:]以及带有 start 和/或 end 的一维切片(但如果指定了 step ,则不会),例如[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!"  

但是,只有在仅传递一个切片并且仅在传递的切片没有步进的情况下才调用这些方法。因此[::]不会走到那里,因为它有一个台阶(即使它是隐式的)。但是[:,:]也不会涉及到这些内容,因为它被转换为tuple(slice(None), slice(None)),它不是一个简单的切片,而是一个切片的元组。如果您自己传入__*slice__实例,也不会进入这些slice方法中,这就是[slice(None)]的原因,尽管它似乎等效于[:]却直接进入了{{1 }},而不是__*item__


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