【问题标题】:Python iterable protocolPython 可迭代协议
【发布时间】:2018-12-18 16:05:21
【问题描述】:

我以 4 种方式制作了一个可迭代的 Squares 对象。经典的类,生成器风格,只是为了好玩,闭包风格和改进的(?)闭包风格。

class Squares:
    def __init__(self, n):
        self.n = n

    def __iter__(self):
        return self.SquaresIterator(self.n)

    class SquaresIterator:
        def __init__(self, n):
            self.n = n
            self.i = 0

        def __iter__(self):
            return self

        def __next__(self):
            if self.i >= self.n:
                raise StopIteration

            result = self.i ** 2
            self.i += 1
            return result

按预期工作

sq_class = Squares(5)
list(sq_class)
[0, 1, 4, 9, 16]
# calling again will create a new iterator
list(sq_class)
[0, 1, 4, 9, 16]

发电机

def squares(n):
    for i in range(n):
        yield i ** 2

sq_gen = squares(5)
list(sq_gen)
[0, 1, 4, 9, 16]
# calling again will return empty [] is OK, generator exhausted.
list(sq_gen)
[]

关闭

def Squares(n):
    def inner():
        return squares_gen(n)

    def squares_gen(n):
        for i in range(n):
            yield i ** 2

    return inner

sq_closure = Squares(5)
list(sq_closure())
[0, 1, 4, 9, 16]
# calling again the inner will create a new generator so it is not exhausted
list(sq_closure())
[0, 1, 4, 9, 16]

改进(?)关闭

def Squares(n):
    def inner():
        return squares_gen(n)

    def squares_gen(n):
        for i in range(n):
            yield i ** 2

    inner.__iter__ = lambda : squares_gen(n)
    return inner

sq_closure = Squares(5)
list(sq_closure)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-beb02e61ccfb> in <module>
----> 1 for i in sq:
      2     print(i)

TypeError: 'function' object is not iterable

我想尝试将__iter__ 函数附加到内部函数对象并返回一个生成器,然后我可以离开 ()-s,我可以将返回的内部函数用作可迭代对象。 可迭代协议的确切定义是什么?看来,只有__iter__ 函数的存在是不够的。

【问题讨论】:

  • Magicmethods 只有在它们是类属性时才会被调用——你不能将它们设置为实例属性(你可以但是它们不会被调用 )。
  • 感谢 bruno 的回答 +1。
  • 您错过了最简单的方法,即使用内置工具生成无限序列:squares = map(lambda x: x*x, itertools.count())squares = (x*x for x in itertools.count())。使用islice 获取序列的有限前缀:list(itertools.islice(squares, 5)) == [0,1,4,9,16]

标签: python python-3.x


【解决方案1】:

“可迭代协议的确切定义”is in the documentation

可迭代: 一个能够一次返回其成员的对象。可迭代对象的示例包括您使用 __iter__() 方法或使用实现序列语义的 __getitem__() 方法定义的任何类的 (...) 对象。

但是:__magicmethods__only invoked when defined on the class - 你不能在每个实例的基础上覆盖它们(你可以,但它们不会被调用)。

【讨论】:

    猜你喜欢
    • 2021-02-17
    • 2018-01-05
    • 1970-01-01
    • 2017-02-21
    • 2019-08-15
    • 1970-01-01
    • 1970-01-01
    • 2020-12-11
    相关资源
    最近更新 更多