首页 > 解决方案 > 如何使类对象可迭代

问题描述

我有以下点类:

import math

class Point:
    """Two-Dimensional Point(x, y)"""
    def __init__(self, x=0, y=0):
        # Initialize the Point instance
        self.x = x
        self.y = y

   # def __iter__(self):
 #       return iter(int(self.x))
 #       return iter(int(self.y))
        return self

    @property
    def magnitude(self):
        # """Return the magnitude of vector from (0,0) to self."""
        return math.sqrt(self.x ** 2 + self.y ** 2)


    def distance(self, self2):
         return math.sqrt((self2.x - self.x) ** 2 + (self2.y - self.y) ** 2)

    def __str__(self):
        return 'Point at ({}, {})'.format(self.x, self.y)

    def __repr__(self):
        return "Point(x={},y={})".format(self.x, self.y)

我想让“点”可迭代,以便可以进行以下操作:

point = Point(2, 3)
x, y = point
print(x)
    2
print(y)
    3

如果您看到我的注释代码,那是我尝试的,但它说 TypeError:iter() 返回了“Point”类型的非迭代器。关于如何正确执行此操作的任何想法?

标签: pythonpython-3.x

解决方案


tl;博士:

def __iter__(self):
    yield self.x
    yield self.y

要使某些东西可迭代,您需要您的__iter__方法返回一个迭代器。

你不能只是return self, 除非self已经是一个迭代器(这意味着它有一个__next__方法)。但是你不想points成为一个迭代器,你希望它可以一遍又一遍地迭代。

return iter(int(self.x))那你不能return iter(int(self.y)),有两个原因。首先,在你之后return,你的功能就完成了;之后发生的任何代码都不会运行。其次,您不能iter调用int. (此外,没有理由调用int. int


您可以通过从 each 中创建一个可迭代对象来解决最后一组问题int,例如单元素列表,迭代该可迭代对象,然后使用yield from而不是委托给它return。在函数中使用yieldoryield from使其成为生成器函数,生成函数创建的生成器是迭代器:

yield from iter([self.x])
yield from iter([self.y])

……但这有点愚蠢。一旦我们知道我们想要一个生成器,我们就可以只yield使用我们想要迭代的值。因此顶部的代码。


或者,您可以为这两个元素显式创建一个单元素可迭代对象并将它们链接在一起并返回:

def __iter__(self):
    return itertools.chain(iter([self.x]), iter([self.y]))

但这也很愚蠢。在单元素列表上链接两个迭代器与仅迭代一个双元素列表相同:

def __iter__(self):
    return iter([self.x, self.y])

最后,与其依赖生成器、列表迭代器chain或 Python 附带的其他迭代器类型,您始终可以显式编写一个:

class PointIterator:
    def __init__(self, point):
        self.values = [point.x, point.y]
    def __next__(self):
        try:
            return self.values.pop(0)
        except IndexError:
            raise StopIteration
    def __iter__(self):
        return self

class Point:
    # ... other code
    def __iter__(self):
        return PointIterator(self)

推荐阅读