如何使自定义对象可迭代?

新手上路,请多包涵

我有一个 list 自定义类对象(示例如下)。

使用: list(itertools.chain.from_iterable(myBigList)) 我想“合并”所有 stations 子列表到一个大列表中。所以我想我需要让我的自定义类成为可迭代的。

这是我的自定义类的示例。

 class direction(object) :
    def __init__(self, id) :
        self.id = id
        self.__stations = list()

    def __iter__(self):
        self.__i = 0                #  iterable current item
        return iter(self.__stations)

    def __next__(self):
        if self.__i<len(self.__stations)-1:
            self.__i += 1
            return self.__stations[self.__i]
        else:
            raise StopIteration

我实施 __iter____next__ 但它似乎不起作用。他们甚至没有被召唤。

知道我做错了什么吗?

注意:使用 Python 3.3

原文由 Matthieu Riegler 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 495
2 个回答

__iter__ 是当您尝试迭代类实例时调用的内容:

 >>> class Foo(object):
...     def __iter__(self):
...         return (x for x in range(4))
...
>>> list(Foo())
[0, 1, 2, 3]

__next__ is what gets called on the object which is returned from __iter__ (on python2.x, it’s next , not __next__ –我通常将它们都命名为别名,以便代码可以与任何一个一起使用……):

 class Bar(object):
    def __init__(self):
        self.idx = 0
        self.data = range(4)
    def __iter__(self):
        return self
    def __next__(self):
        self.idx += 1
        try:
            return self.data[self.idx-1]
        except IndexError:
            self.idx = 0
            raise StopIteration  # Done iterating.
    next = __next__  # python2.x compatibility.

在评论中,有人问你将如何构造可以迭代多次的对象。在这种情况下,我建议采用与 Python 相同的方法,将迭代器从数据容器中分离出来:

 class BarIterator(object):
    def __init__(self, data_sequence):
        self.idx = 0
        self.data = data_sequence
    def __iter__(self):
        return self
    def __next__(self):
        self.idx += 1
        try:
            return self.data[self.idx-1]
        except IndexError:
            self.idx = 0
            raise StopIteration  # Done iterating.

class Bar(object):
    def __init__(self, data_sequence):
        self.data_sequence = data_sequence
    def __iter__(self):
        return BarIterator(self.data_sequence)

原文由 mgilson 发布,翻译遵循 CC BY-SA 4.0 许可协议

只需实施 __iter__ 就足够了。

 class direction(object) :
    def __init__(self, id) :
        self.id = id
        self.__stations = list()

    def __iter__(self):
        #return iter(self.__stations[1:]) #uncomment this if you wanted to skip the first element.
        return iter(self.__stations)

a = direction(1)
a._direction__stations= range(5)

b = direction(1)
b._direction__stations = range(10)

import itertools
print list(itertools.chain.from_iterable([a,b]))
print list(itertools.chain.from_iterable([range(5),range(10)]))

输出:

 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

在这里 查看为什么它是 _direction__stations

__spam 形式的任何标识符(至少两个前导下划线,最多一个尾随下划线)在文本上替换为 名 _spam,其中类名是当前类名,前导下划线被去除。

原文由 M4rtini 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题