在自定义 class 中实施 __next__
Implementing __next__ in a custom class
我有一个 class 看起来像这样
Class myClass:
def __init__(self, key, value):
self.key = key
self.value = value
其中 key
是一个字符串,value
始终是 myClass 的元素列表,可能为空。
我想为 values
中的每个 value
定义我自己的迭代器方法 returns value.key
。我试过了
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__()
您需要提取并保留列表 self.value
上的 迭代器 -- 您不能只调用列表上的 next
,您需要一个这样一个列表上的迭代器。
所以,你需要一个辅助迭代器class:
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
,您可以传播它)。如果不是这种情况,并且您想在没有属性的情况下遇到项目时停止迭代,则需要 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
是一个 iterable,而不是 iterator,所以你可以有多个在 myClass
实例上循环:
mc = myClass(somekey, funkylist)
for ka in mc:
for kb in mc:
whatever(ka, kb)
如果 mc
本身就是一个迭代器,内部循环将耗尽它,因此嵌套循环的语义将完全不同。
如果你确实想要这种完全不同的语义(即你想要 mc
本身就是一个迭代器,而不仅仅是一个可迭代的)那么你必须放弃auxiliary class(但仍需要将迭代器存储在 self.value
上作为 myClass
的实例属性)——这将是一种奇怪、不舒服的安排,但它 是(勉强)可能这确实是您的应用程序需要的安排...
您没有理由实施 __next__
。您可以使用 __iter__
到 return 生成器,它将执行您想要的操作。
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 兼容,因为 returned 生成器将在 python2 中具有所需的 next
函数, __next__
在 python3.
我有一个 class 看起来像这样
Class myClass:
def __init__(self, key, value):
self.key = key
self.value = value
其中 key
是一个字符串,value
始终是 myClass 的元素列表,可能为空。
我想为 values
中的每个 value
定义我自己的迭代器方法 returns value.key
。我试过了
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__()
您需要提取并保留列表 self.value
上的 迭代器 -- 您不能只调用列表上的 next
,您需要一个这样一个列表上的迭代器。
所以,你需要一个辅助迭代器class:
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
,您可以传播它)。如果不是这种情况,并且您想在没有属性的情况下遇到项目时停止迭代,则需要 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
是一个 iterable,而不是 iterator,所以你可以有多个在 myClass
实例上循环:
mc = myClass(somekey, funkylist)
for ka in mc:
for kb in mc:
whatever(ka, kb)
如果 mc
本身就是一个迭代器,内部循环将耗尽它,因此嵌套循环的语义将完全不同。
如果你确实想要这种完全不同的语义(即你想要 mc
本身就是一个迭代器,而不仅仅是一个可迭代的)那么你必须放弃auxiliary class(但仍需要将迭代器存储在 self.value
上作为 myClass
的实例属性)——这将是一种奇怪、不舒服的安排,但它 是(勉强)可能这确实是您的应用程序需要的安排...
您没有理由实施 __next__
。您可以使用 __iter__
到 return 生成器,它将执行您想要的操作。
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 兼容,因为 returned 生成器将在 python2 中具有所需的 next
函数, __next__
在 python3.