可能是一个n00b问题,但我目前有一个实现迭代器的类,所以我可以做类似的事情
for i in class():
但我希望能够通过索引访问该类,以及
class()[1]
我该怎么做?
谢谢!
答案 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
。有两个要求:
显然,这门课程将成为某种集合。我们要做的是查看我们的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__
,index
和count
。如果您考虑它,那么应包含在任何索引对象中的所有内容。如果您忘记包含它们,您的代码的用户(包括,可能是您自己!)可能会非常恼火(我知道我会)。
但是,还有第二个ABC
也提供了这种功能组合(可迭代,[]
可访问):Sequence
。我们想要使用哪一个?
我们记得要求是能够通过索引(例如list
或tuple
)访问对象,即不 按键(如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!
答案 1 :(得分:50)
实施__iter__()
和__getitem__()
等方法。