我有一个看起来像这样的课程
Class myClass:
def __init__(self, key, value):
self.key = key
self.value = value
其中key
是一个字符串,而value
始终是myClass的元素列表,可能为空。
我想定义我自己的iter方法,为value.key
中的每个value
返回values
。我试过了
def __iter__(self):
return self
def __next__(self):
try:
self.value.next().key
except:
raise StopIteration
但它永远循环着。我究竟做错了什么? 另外,如果我想要兼容Python 2/3,我应该添加方法
def next(self):
return self.__next__()
答案 0 :(得分:3)
您没有理由实施__next__
。您可以使用__iter__
返回一个可以执行您想要的生成器。
class Pair(object):
def __init__(self, key, value):
self.key = key
self.value = value
def __iter__(self):
return (v.key for v in self.value)
# alternative iter function, that allows more complicated logic
def __iter__(self):
for v in self.value:
yield v.key
p = Pair("parent", [Pair("child0", "value0"), Pair("child1", "value1")])
assert list(p) == ["child0", "child1"]
这种做法与python2和python3兼容,因为返回的生成器在python2中具有所需的next
函数,在python3中具有__next__
。
答案 1 :(得分:2)
您需要在列表self.value
上提取并保留迭代器 - 您不能只在列表上调用next
,在这样的列表上需要一个迭代器
因此,您需要一个辅助迭代器类:
class myClassIter(object):
def __init__(self, theiter):
self.theiter = theiter
def __next__(self):
return next(self.theiter).key
next = __next__
我也使Py 2/3与object
基础兼容并具有适当的别名。
在这里,我假设列表中的每个项目都有key
属性(因此唯一的预期异常是StopIteration
,您可以传播它)。如果不是这种情况,并且您希望在没有attribite的情况下遇到项目时停止迭代,则需要try
/ except
,但保持紧张! - 良好异常处理的关键设计方面。即,如果这些确实是你的规格:
def __next__(self):
try: return next(self.theiter).key
except AttributeError: raise StopIteration
不要抓住所有例外 - 只有您特别期望的例外情况!
现在,在myClass
中,您需要:
def __iter__(self):
return myClassIter(iter(self.value))
这意味着myClass
是可迭代的,而非迭代器,因此您可以在myClass
上正确拥有多个循环实例:
mc = myClass(somekey, funkylist)
for ka in mc:
for kb in mc:
whatever(ka, kb)
如果mc
本身就是一个迭代器,那么内部循环会耗尽它,因此嵌套循环的语义会完全不同。
如果你确实想要这样完全不同的语义(即你想要 mc
本身就是一个迭代器,而不仅仅是一个迭代器)那么你必须省去辅助类(但仍然需要将self.value
上的迭代器存储为myClass
的实例属性 - 这将是一个奇怪的,令人不舒服的安排,但 (几乎不可能)它可能确实是你的应用程序需要的安排......