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

Posted

技术标签:

【中文标题】为啥当我使用 [:] 时我的子类的 __getitem__ 和 __setitem__ 没有被调用?【英文标题】:Why are my subclass's __getitem__ and __setitem__ not called when I use [:]?为什么当我使用 [:] 时我的子类的 __getitem__ 和 __setitem__ 没有被调用? 【发布时间】:2018-12-20 10:09:18 【问题描述】:

我正在使用 Python 2.7,我正在尝试从继承 list 的类中重载 __getitem____setitem__

假设我有这门课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 

【问题讨论】:

【参考方案1】:

这是因为在 Python 2 [1][:] 以及带有 start 和/或 end 的一维切片(但是不是在指定 step 时),如 [1:][:3][1:3] 如果已实现,则通过 __getslice____setslice__。如果它们没有被实施,它们也将转到__getitem____setitem__)。引用文档:

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

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

【讨论】:

感谢您的回答,但是我不明白[::] 的情况。在键上我收到slice(None) 而不是tuple,同样的情况也发生在直接给出slice a[slice(None)] [::] 隐式包含一个步骤(即使它等于默认步骤),因此它不能转到__*slice__

以上是关于为啥当我使用 [:] 时我的子类的 __getitem__ 和 __setitem__ 没有被调用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当我使用 QImage::scaled() 时我的内存消耗很大?

为啥当我使用箭头函数 onClick 时我的变量未定义?

为啥当我使用“require”时我的变量未定义? [复制]

为啥切换语言环境时我的会话没有加载?

为啥当我按下返回按钮时我的程序崩溃

为啥当我滚动我的 tabelview 单元格时我的 imageview 正在缩小?