列表-可通过迭代器和索引访问的Python类

可能是一个n00b问题,但是我目前有一个实现迭代器的类,因此我可以做类似的事情

for i in class():

但是我希望能够通过索引访问类

class()[1]

我怎样才能做到这一点?

谢谢!

xster asked 2020-07-24T12:31:01Z
2个解决方案
71 votes

@Ignacio Vazquez-Abrams当前接受的答案就足够了。 但是,对此问题感兴趣的其他人可能希望考虑从抽象基类(__getitem__)继承其类(例如在标准模块__getitem__中找到的那些)。 这可以做很多事情(可能还有其他事情):

  • 确保您需要将对象“像____一样对待”的所有方法
  • 它是自记录的,因为读取您的代码的人能够立即知道您希望对象“像____一样工作”。
  • 允许__getitem__正常工作。
  • 通常会自动提供方法,因此我们不必自己定义方法

(请注意,除了上述内容外,创建自己的__getitem__还可以让您测试任何对象中是否存在特定方法或方法集,并以此为基础将该对象声明为__getitem__的子类, 即使对象不是直接从__getitem__继承而来,也请参阅此答案。)


示例:使用__len__实现类似于__getitem__的只读类

现在以一个示例为例,让我们为原始问题中的类选择并实现__getitem__。 有两个要求:

  1. 该类是可迭代的
  2. 通过索引访问类

显然,此类将是某种集合。 因此,我们要做的是查看我们的__getitem__ ABC菜单,找到合适的2980576379131134134976(请注意,还有__getitem__ ABC)。 适当的__len__取决于我们希望在类中使用哪些抽象方法。

如果要使用方法2980576379131134134976,我们将看到__getitem__,这是我们执行__len__之类所需的方法。但是,myobject[i] = value不包括方法random.shuffle(myobject),这是我们需要的方法 做类似ABC的事情。因此,我们需要使用其他index

在抽象基类的__getitem__菜单上,我们看到__getitem__是提供我们所需功能的最简单__len__。 而且-您可以看看-我们将myobject[i] = value功能作为混合方法获得-这意味着我们不必自己定义它-免费! 我们还会得到random.shuffle(myobject)ABCindexcount。如果考虑一下,所有这些都应包含在任何索引对象中。 如果您忘记了包含它们,那么您的代码用户(可能包括您自己!)可能会很生气(我知道我会)。

但是,第二个__getitem__也提供了以下功能组合(可迭代,并且__len__可以访问):__getitem__。我们要使用哪个?

我们记得,要求是能够通过索引(例如__getitem____len__)访问对象,即不能通过密钥(例如myobject[i] = value)访问对象。 因此,我们选择random.shuffle(myobject)而不是ABC


侧边栏:请注意,__getitem__是只读的(与__len__一样),因此它不允许我们执行myobject[i] = valuerandom.shuffle(myobject)之类的事情。如果我们希望能够做到这一点,则需要继续 在ABCs的菜单中向下滑动,并使用__getitem__(或__getitem__),这将需要实现几种其他方法。


范例程式码

现在我们可以上课了。 我们定义它,并使其继承自__getitem__

from collections.abc import Sequence

class MyClass(Sequence):
    pass

如果我们尝试使用它,解释器会告诉我们在使用它之前需要实现哪些方法(请注意,这些方法也在Python文档页面上列出):

>>> myobject = MyClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyClass with abstract methods __getitem__, __len__

这告诉我们,如果继续执行__getitem____len__,我们将能够使用我们的新类。 我们可能会在Python 3中这样做:

from collections.abc import Sequence

class MyClass(Sequence):
    def __init__(self,L):
        self.L = L
        super().__init__()
    def __getitem__(self, i):
        return self.L[i]
    def __len__(self):
        return len(self.L)

# Let's test it:
myobject = MyClass([1,2,3])
try:
    for idx,_ in enumerate(myobject):
        print(myobject[idx])
except Exception:
    print("Gah! No good!")
    raise
# No Errors!

有用!

Rick Teachey answered 2020-07-24T12:33:12Z
52 votes

实现__getitem__()__getitem__()等方法。

Ignacio Vazquez-Abrams answered 2020-07-24T12:31:20Z
translate from https://stackoverflow.com:/questions/5359679/python-class-accessible-by-iterator-and-index