Python类可以通过迭代器和索引访问

时间:2011-03-19 02:41:43

标签: python list iterator

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

for i in class():

但我希望能够通过索引访问该类,以及

class()[1]

我该怎么做?

谢谢!

2 个答案:

答案 0 :(得分:67)

来自@Ignacio Vazquez-Abrams的当前accepted answer就足够了。但是,对此问题感兴趣的其他人可能会考虑从abstract base class (ABC)继承他们的类(例如standard module collections.abc中的那些)。这做了很多事情(there are probably others as well):

  • 确保您需要处理对象的所有方法,例如____"
  • 它是自我记录的,因为读取您的代码的人能够立即知道您打算将您的对象视为____"。
  • 允许isinstance(myobject,SomeABC)正常工作。
  • 经常自动提供方法,所以我们不必自己定义

(请注意,除了上述内容之外,创建自己的ABC 可以让您测试任何对象中是否存在特定方法或方法集,并且在此基础上声明该对象是ABC 的子类,即使该对象不直接从ABC继承 。{{ 3}})


示例:使用list

实现一个只读的ABC

现在举个例子,让我们为原始问题中的班级选择并实施ABC。有两个要求:

  1. 该类是可迭代的
  2. 按索引访问该课程
  3. 显然,这门课程将成为某种集合。我们要做的是查看我们的See this answer for more information.以找到合适的ABC(请注意,还有menu of collection ABC's)。适当的ABC取决于我们希望在课堂上使用哪些抽象方法。

    如果我们想要使用方法__iter__(),我们会看到numeric ABCs是我们所追求的,这是我们为for o in myobject:这样的事情所需要的。但是,Iterable不包含方法__getitem__(),这是我们执行myobject[i]之类的操作所需的方法。因此,我们需要使用不同的ABC

    在摘要基类的collections.abc菜单上,我们看到Iterable是最简单的ABC,可提供我们所需的功能。并且 - 你会看到 - 我们得到Iterable功能作为mixin方法 - 这意味着我们不必自己定义 - 免费!我们还会获得__contains____reversed__indexcount。如果您考虑它,那么包含在任何索引对象中的所有内容。如果您忘记包含它们,您的代码的用户(包括,可能是您自己!)可能会非常恼火(我知道我会)。

    但是,还有第二个ABC也提供了这种功能组合(可迭代,[]可访问):Sequence。我们想要使用哪一个?

    我们记得要求是能够通过索引(例如listtuple)访问对象,即 按键(如dict)。因此,我们选择Sequence而不是Mapping


    补充工具栏:请注意Sequence是只读的(Mapping也是如此)非常重要,因此不允许我们执行myobject[i] = value之类的操作或random.shuffle(myobject)。如果我们希望能够执行此类操作,我们需要继续ABC的菜单并使用Mapping(或MutableSequence),这将需要实施其他几种方法


    示例代码

    现在我们可以上课了。我们定义它,并让它继承自Sequence

    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!
    

    MutableMapping

答案 1 :(得分:50)

实施__iter__()__getitem__()等方法。