python - 迭代期间的运行时错误?
问题描述
列表和集合之间的区别之一是列表可以在迭代期间更改——我们可以在循环中附加到它等等。但是,如果我们尝试在 for 循环期间添加到集合,则会引发运行时错误. 但是,Python 如何检测到 set.add() 正在循环中使用,然后引发运行时错误?如果我尝试重新创建我的伪列表类并在我的类的附加函数中引发运行时错误,我是否只是重载 __iter__ 以防止任何附加?
例如:
a_set = {1,2,3,4}
a_list = [1,2,3,4]
for i in a_list:
a_list.append(5)
这导致无限循环
for j in a_set:
a_set.add(5)
这会导致运行时错误。
它们都有 __iter__ 函数,所以在我的伪列表类中,我应该如何重载 __iter__ 以便它会像集合一样引发运行时错误?
解决方案
这一切都在您的可迭代类返回的迭代器中。请注意,对于一个集合,它实际上是__next__
引发错误的方法,并且不一定在 for 循环中,尽管 for 循环隐式调用__iter__
一个可迭代对象,然后调用__next__
生成的迭代器并将其分配给循环变量,并且在每次迭代开始时继续这样做,直到StopIteration
引发 a(这是迭代器协议)。所以,请注意:
In [2]: s = {1,2,3}
In [3]: it = iter(s)
In [4]: next(it)
Out[4]: 1
In [5]: s.add(1)
In [6]: next(it)
Out[6]: 2
In [7]: s.add(99)
In [8]: next(it)
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-58-2cdb14c0d4d6> in <module>()
----> 1 next(it)
RuntimeError: Set changed size during iteration
正如错误所暗示的,当集合改变大小时,就会调用错误。我们可以通过以下方式实现这一点:
In [11]: class MyListIterator:
...: def __init__(self, origin):
...: self.origin = origin
...: self.original_size = len(origin)
...: self.i = 0
...: def __iter__(self):
...: return self
...: def __next__(self):
...: if len(self.origin) != self.original_size:
...: raise RuntimeError("MyList changed size during iteration!")
...: elif self.i == self.original_size:
...: raise StopIteration
...: x = self.origin.data[self.i]
...: self.i += 1
...: return x
...:
...: class MyList:
...: def __init__(self):
...: self.data = [1,2,3]
...: def __iter__(self):
...: return MyListIterator(self)
...: def __len__(self):
...: return len(self.data)
...: def append(self, item):
...: self.data.append(item)
...:
现在:
In [12]: mylist = MyList()
In [13]: for x in mylist:
...: print(x)
...:
1
2
3
In [14]: for x in mylist:
...: mylist.append(3)
...: print(x)
...:
1
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-14-3bd26e0c08b9> in <module>()
----> 1 for x in mylist:
2 mylist.append(3)
3 print(x)
4
<ipython-input-14-f69ab7d03470> in __next__(self)
8 def __next__(self):
9 if len(self.origin) != self.original_size:
---> 10 raise RuntimeError("MyList changed size during iteration!")
11 elif self.i == self.original_size:
12 raise StopIteration
RuntimeError: MyList changed size during iteration!
请注意,您可以1
在引发错误之前看到已打印,这是因为直到__next__
在第二次迭代之前(或在第二次迭代开始时,但是您想考虑)才被 for 循环隐式调用它),错误被提出。
推荐阅读
- jquery - react bootstrap tabs 默认显示所有选项卡而不是目标选项卡
- android - 如何在 Jetpack Compose 中传递条件参数?
- javascript - 我在制作 loginPage 时从控制台收到错误,但我不知道出了什么问题(React.js)
- c# - 将 DateTime 参数设置为仅日期
- python-3.x - 将类变量传递给方法
- sql - gorm 属于不返回关系
- javascript - 随机化存储在 list.js 中的多个对象
- php - 将 MYSQL 时间戳转换为 unix
- python - 使用 etree.ElementTree 从 xml 中提取数据的问题
- azure-devops - 阶段无限期等待“在部署队列中等待”状态