【问题标题】:Clean up on for loop break清理 for 循环中断
【发布时间】:2020-07-17 19:21:21
【问题描述】:

你能在 python 中创建一个迭代器,在 for 循环退出时运行清理代码吗?比如:

from random import randint

class Iterable:
    def __iter__(self):
        return self
    def __next__(self):
        return randint(1, 10)
    def __iterclose__(self):
        print("Clean up code")

for x in Iterable():
    if x < 5:
        break

# Prints "Clean up code"

【问题讨论】:

  • 您混合了两个不同的概念 Iterables 和 Iterators。 Itterable 的 __iter__ 应该返回一个 Iterator 对象。而迭代器的__iter__ 应该返回self
  • 我知道我可以使用上下文管理器,但最好不用!
  • @Jack 好吧,你不能总是得到你想要的。所以答案是否定的。注意,你已经定义了一个iterator,注意只是一个iterable。
  • @TomKarzes 嗯?
  • 当完成迭代时,你应该引发StopIteration异常,此时你应该已经知道你必须执行清理,否则这个迭代器将永远运行。

标签: python python-3.x for-loop iterator iterable


【解决方案1】:

我认为为了从可迭代协议中受益,您应该让您的 Iterable 获得对停止条件的控制权。这个怎么样:


from random import randint


class Iterable:

    def __init__(self, max):
        self.i = 0
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        self.i += 1
        if self.i > self.max:
            self.cleanup()
            raise StopIteration
        return randint(1, 10)

    def cleanup(self):
        print("Clean up code")


for x in Iterable(5):
    print(x)

【讨论】:

  • 无限迭代器没有任何问题或异常。
  • 可能是这样。但是考虑到手头的任务:如果应该由迭代器完成,您将如何调用清理步骤?
【解决方案2】:

正如我在评论中所说:

当完成迭代时,你应该引发StopIteration异常,此时你应该已经知道你必须执行清理,否则这个迭代器将永远运行。

iterator 和 iterable 也是不同的东西,来自 fluent python book:

迭代器

任何实现 next 无参数方法的对象 返回系列中的下一个项目或在出现时引发 StopIteration 没有更多的项目。 Python 迭代器也实现了 iter 方法 所以它们也是可迭代的

地点:

iterable iter 内置函数可以从中获取的任何对象 一个迭代器。实现 iter 方法的对象返回一个 迭代器是可迭代的。

所以迭代器应该知道它什么时候结束,希望这段代码能把事情弄清楚:

from random import randint

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

  def __iter__(self):
    return self

  def __next__(self):
    if self.i < self.n:
      self.i += 1
      return randint(1, 10)
    else:
      print("doing cleanup")
      #do the clean up you want
      raise StopIteration()

class MyIterable:
    def __init__(self, n):
      self.n = n
    def __iter__(self):
        return MyIterator(self.n)

for x in MyIterable(5):
  print(x)

输出:

4
9
7
5
1
doing cleanup

注意:这里最好用生成器函数或表达式来做,但这会让事情更容易区分。

【讨论】:

  • "所以迭代器应该知道什么时候结束" 无限迭代器(不知道什么时候结束)并没有错或不正常
  • @juanpa.arrivillaga 当然,事实上标准库有无限的迭代器,但大多数情况下你会知道它什么时候结束。
猜你喜欢
  • 2018-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多