Python 为什么UserList子类返回错误的切片类型?

Python 为什么UserList子类返回错误的切片类型?,python,collections,subclassing,Python,Collections,Subclassing,让我首先说,我明白为什么子类化list不能像您预期的那样工作(因为list是一种基本的内置类型,并且存在性能问题等)。AFAIK collections.UserList应该避免所有这些问题,并使子类化UserList完全按照您的预期工作。比如说, class DumbList(list): pass d1 = DumbList([1,2,3]) d2 = DumbList([4,5]) type(d1 + d2) 返回,但 from collections import UserList

让我首先说,我明白为什么子类化
list
不能像您预期的那样工作(因为
list
是一种基本的内置类型,并且存在性能问题等)。AFAIK collections.UserList应该避免所有这些问题,并使子类化UserList完全按照您的预期工作。比如说,

class DumbList(list):
  pass
d1 = DumbList([1,2,3])
d2 = DumbList([4,5])
type(d1 + d2)
返回
,但

from collections import UserList
class DumbList(UserList):
  pass
d1 = DumbList([1,2,3])
d2 = DumbList([4,5])
type(d1 + d2)
按预期返回
。但是,即使使用
用户列表
而不是
列表
,切片也会返回错误的类型:

class DumbList(UserList):
  pass
d = DumbList([1,2,3])
type(d[:2])
返回
,而不是预期的

两个问题:

  • 为什么会这样
  • 如何使切片返回正确的类型?我能想到的最简单的事情是:


…但似乎这种锅炉板代码应该是不必要的。

在Python2中,普通切片(没有跨步)将由。
UserList
实现早于在语言中添加扩展片段(带stride)之前,从未添加对它们的支持,请参阅

Python3实现只是采用Python2版本,移动到
集合
并删除
\uuuu getslice\uuuu
\uuu setslice\uuuu
,因为Python3不再支持这些

因此,
\uuu getitem\uuu
实现仍然只是:

def __getitem__(self, i): return self.data[i]
假设切片将在其他地方处理

在Python3中,所有切片都是通过传入to
\uuuu getitem\uuuu
来处理的;只需测试该类型,并将结果包装在
type(self)
调用中:

def __getitem__(self, i):
    res = self.data[i]
    return type(self)(res) if isinstance(i, slice) else res

相关:干得好!你刚刚发现为什么我总是不鼓励继承内置的东西!这看起来很简单,但这是在代码中引入bug的好方法。还要注意,要创建一个合适的子类,不仅需要重新实现原始类的每个方法,还需要实现
\uuuu r*\uuuu
变体,以使其在任何情况下都能正常工作!换言之,使用授权总是较少的工作。只有当你真的想拥有一个子类而不是像类那样简单的东西时才使用inheritanche(例如“愚弄”
isinstance
checks)。顺便说一句,我使用的是Python 3.4.2。所以。。。这基本上是一个bug?=)我确实喜欢你的
类型(self)(res)
比我的
类型(self)
@keenanpaper:好吧,你得和Python开发者讨论一下。:-)
def __getitem__(self, i):
    res = self.data[i]
    return type(self)(res) if isinstance(i, slice) else res