如何创建可以像数组一样使用的Python类数组对象?

时间:2018-08-23 02:56:49

标签: python python-3.x

如何创建一个类型,其实例可以用[]进行索引,就像列表一样。

我可以像

一样使用此对象
  

my_obj [***]

1 个答案:

答案 0 :(得分:1)

我认为您是在问如何创建序列类型-一种可以使用[]对其实例进行索引的类型,就像一个列表一样。


执行此操作的关键是实现一种或多种特殊方法,如文档Emulating container types中所述。

特别是,为my_obj[1]调用的特殊方法是__getitem__

对于一个简单的例子,让我们创建一个类似于所有小写英文字母的列表的东西:

class Letters:
    def __getitem__(self, index):
        return string.ascii_lowercase[index]

现在:

>>> letters = Letters()
>>> letters[2]
'c'
>>> letters[-2]
'y'
>>> letters[3:6]
'def'

但是,这实际上并不是一个完整的序列。例如:

>>> len(letters)
TypeError: object of type 'Letters' has no len()
>>> reversed(letters)
TypeError: object of type 'Letters' has no len()
>>> isinstance(letters, collections.abc.Sequence)
False

如果您想实现一个完整的序列,则collections.abc模块非常有用,因为它提供的所有抽象基类也都是mixin类,可以为您填充大多数实现。例如,如果我们继承Sequence,则只需定义__getitem____len__,它将为我们提供__contains____iter__,{{ 1}},__reversed__index是免费的:

count

现在,在class Letters(collections.abc.Sequence): def __getitem__(self, index): return string.ascii_lowercase[index] def __len__(self): return 26 listtuple上运行的所有内容都在range上运行:

Letters

我还作弊了一点,创建了一个序列,该序列仅委托给另一个序列(>>> letters = Letters() >>> len(letters) 26 >>> reversed(letters) <generator object Sequence.__reversed__ at 0x15f949f68> >>> print(*reversed(letters)) z y x w v u t s r q p o n m l k j i h g f e d c b a >>> letters.index('s') 10 >>> isinstance(letters, collections.abc.Sequence) True )来完成所有工作。实际上,您通常可以这样做,但有时却不能。而且当您不能这样做时,通常必须处理负索引并自己切片,这看起来有点难看:

ascii_lowercase

(您通常希望分片返回def __getitem__(self, index): if isinstance(index, slice): return [self[i] for i in index.indices(len(self))] if index < 0: index += len(self) return string.ascii_lowercase[index] 的另一个实例,而不是列表,但是对于type(self)来说没有任何意义,所以我只返回了一个列表。)


如果您想要一个 mutable 序列,例如一个与元组相对的列表,您可以在其中修改值,也可以添加和删除它们,那么还有更多方法可以实现,但是什么也没有完全不同。


有关更完整的示例,请参见Creating a new sequence is easy