python - 如何创建一个可以像数组一样使用的 Python 类数组对象?
问题描述
如何创建实例可以用 [] 索引的类型,就像列表一样。
我可以像这样使用这个对象
我的_obj[***]
解决方案
我想你是在问如何创建一个序列类型——一个实例可以用 索引的类型[]
,就像一个列表一样。
这样做的关键是实现一个或多个特殊方法,如文档中的模拟容器类型中所述。
特别是,被调用的特殊方法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__
and __len__
,它将免费为我们提供__contains__
、__iter__
、__reversed__
、index
和count
的实现:
class Letters(collections.abc.Sequence):
def __getitem__(self, index):
return string.ascii_lowercase[index]
def __len__(self):
return 26
现在,所有适用于、list
和tuple
的东西: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)
,而不是列表,但这Letters
没有任何意义,所以我只返回了一个列表。)
如果你想要一个可变序列,比如一个列表而不是一个元组,你可以在其中修改值,或者添加和删除它们,还有更多的方法可以实现,但没有太大的不同。
有关更完整的示例,请参阅Create a new sequence is easy。
推荐阅读
- mocking - 如何在测试用例中伪造 sys.stdout.istty 而不会与 pytest 标准输出捕获冲突?
- mysql - MYSQL - 由于子查询,结果正常吗?
- python - 我是否在推理模型中正确应用了 seq2seq 中的嵌入层?
- asp.net - ASP.NET MVC - 显示/隐藏基于微软活动目录服务角色的网页链接
- excel - 条目不应大于特定的修复编号
- python - Python 3 Tkinter 闪屏
- windows - 是否有命令检查 PDF 中有多少页?
- mysql - 在 node.js 项目中实现数据库查询以读取和写入 MySQL 副本的正确方法?
- c# - 在不使用代码隐藏的情况下,使用 WPF MVVM 呈现用户控件列表的正确方法是什么?
- rabbitmq - 使用 Celery 执行器将 Airflow 作为集群运行时的问题