如何让我的类与Python的"in"关键字兼容?

6 投票
4 回答
3964 浏览
提问于 2025-04-16 08:23

我现在大约学习Python已经5个小时了,感觉它的功能挺强大的。我目前在尝试写一个Stream类,下面是我的代码:

class Stream:

    """A Basic class implementing the stream abstraction. """

    def __init__(self,data,funct):
        self.current = data
        self._f = funct

    def stream_first(self):
        """Returns the first element of the stream"""
        return self.current

    def stream_pop(self):
        """Removes and returns the first element of the stream. """
        temp = self.current
        self.current = self._f(self.current)
        return temp

在这个方面我取得了一些小成功,于是我想继续做一个BoundedStream类,它的行为基本上和无界的Stream一样,只是到了一定的点就没有元素了。现在我有个问题,既然任何这样的Bounded Stream都有有限的元素,那我应该可以遍历这些元素。如果我用一个明确的列表,我可以使用Python的in关键字和for循环来干净利落地做到这一点。我希望在我自己的类中也能保持这种干净的写法。有没有什么方法可以实现,或者其他语言特性可以让我做到这一点?如果有任何建议或者帮助,我会非常感激!

-大卫

附言:

想知道的人可以了解一下,我想做一个Bounded Stream的原因是我试了内置的range函数,但Python说我想查看的范围太大了。所以我转向Streams是为了更有效地使用内存。

4 个回答

2

作为对@Kos回答的补充,Python 数据模型里有更多的功能,可以让你模拟其他类型的数据。这其中包括了__contains____iter__方法的相关文档。

4

我试过使用内置的范围函数,但Python说我想查看的范围太大了。

可以试试 xrange。这个方法只需要很少的内存,因为它并不会真的创建一个数字列表,而是创建一个看起来像数字列表的对象。换句话说,你想做的事情其实已经可以实现了。

>>> 5 in range(10**9)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError
>>> 5 in xrange(10**9)
True

注意事项

  • 在Python 3中,这根本不是问题——xrange已经被移除了,range现在的功能和Python 2.x中的xrange是一样的。
  • xrange确实可以让你创建非常大的范围,但也不是无限大的,还是有个上限的。
14

如果你想用 for x in object 这种方式来遍历对象,你需要提供一个 __iter__ 方法,这个方法会返回一个新的迭代器。

迭代器是一个对象,它有一个方法 next()(在Python 2中)或者 __next__(在Python 3中),这个方法要么返回下一个元素,要么在没有更多元素时抛出 StopIteration 异常。(迭代器还应该有一个 __iter__ 方法,返回它自己。)

小贴士:你不需要自己编写迭代器;在一个类中实现 __iter__ 的最简单方法是把它做成一个生成器函数,或者从中返回一个生成器表达式(所有生成器都是迭代器)。你也可以直接返回从其他对象获得的迭代器;这里可以用到内置的 iter 函数。


如果你想测试 if x in object,你需要提供一个 __contains__ 方法。

进一步阅读:Python 数据模型 - 模拟容器类型

撰写回答