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

xst*_*ter 43 python iterator list

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

for i in class():
Run Code Online (Sandbox Code Playgroud)

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

class()[1]
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

谢谢!

Ric*_*ica 72

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

  • 确保您需要将对象"像____"视为一切所需的所有方法
  • 它是自我记录的,因为有人阅读你的代码能够立即知道你希望你的对象"像____一样行事".
  • 允许collections.abc正常工作.
  • 经常自动提供方法,所以我们不必自己定义它们

(注意,除了上述内容之外,创建自己的ABC可以允许您测试任何对象中是否存在特定方法或方法集,并基于此将该对象声明为ABC的子类,即使对象不直接从ABC继承.请参阅此答案以获取更多信息.)

现在作为一个例子,让我们在原始问题中为类选择并实现一个ABC.有两个要求:

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

显然,这个课程将成为某种集合.那么我们要做的就是查看我们isinstance(myobject,SomeABC)ABC 菜单以找到合适的ABC(请注意,还有数字ABC).适当的ABC取决于我们希望在课堂上使用哪些抽象方法.

我们看到ABC如果我们想要使用方法ABC,那就是我们所追求的,这就是我们为了做某些事情所需要的ABC.但是,一个list不包括方法ABC,这是我们需要做的事情ABC.所以我们需要使用不同的ABC.

collection抽象基类的菜单上,我们看到a ABC是提供我们所需功能的最简单的ABC.并且 - 你会看到 - 我们将numeric功能作为mixin方法 - 这意味着我们不必自己定义 - 免费!我们还可以得到ABC,Iterable,__iter__(),和for o in myobject:.如果您考虑一下,那么任何索引对象都应该包含所有内容.如果您忘记包含它们,您的代码的用户(包括,可能是您自己!)可能会非常恼火(我知道我会).

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

我们记得要求是能够通过索引(如a myobject[i]或a ABC)访问对象,即不能通过 (如a collections.abc)访问对象.因此,我们选择Sequence而不是ABC.

重要的是要注意a Iterable是只读的(因为是a __contains__),所以它不允许我们做类似的事情__reversed__,或者index.如果我们希望能够做到这样的事情,我们需要继续沿着ABC的菜单并使用count(或a ABC).

现在我们能够上课了.我们定义它,并让它继承[].

from collections.abc import Sequence

class MyClass(Sequence):
    pass
Run Code Online (Sandbox Code Playgroud)

如果我们尝试使用它,解释器将告诉我们在使用之前我们需要实现哪些方法(请注意,这些方法也列在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__
Run Code Online (Sandbox Code Playgroud)

这就告诉我们,如果我们继续贯彻Mappinglist,我们就可以使用我们的新类.我们可能会在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!
Run Code Online (Sandbox Code Playgroud)

有用!

  • 你会发现Internetz上的一些Pythonist似乎不喜欢将抽象类和方法作为语言的一部分包含在内(为了总结/模仿他们的推理,Python应该是"非Java!").然而,它们似乎非常有用,所以我很高兴他们在那里. (3认同)

Ign*_*ams 53

实现两者__iter__()__getitem__()其他方法.

  • 您能否提供一个如何实施这些的示例? (4认同)