当尝试从布局中删除项目时,我注意到for循环和while循环之间存在差异。下面是一些代码来说明:
test.kv
BoxLayout:
orientation: 'vertical'
spacing: 20
BoxLayout:
orientation: 'vertical'
spacing: 20
id : box
Button:
text: 'BUTTON1'
Button:
text: 'BUTTON2'
Button:
text: 'BUTTON3'
Button:
text: 'BUTTON'
size_hint: None, None
size: dp(100), dp(50)
pos_hint: {'center_x': 0.5, 'center_y': 0.1}
on_release: app.del_button()
带有for循环: main.py
from kivy.app import App
class TestApp(App):
def del_button(self):
children = self.root.ids.box.children
for i in children:
self.root.ids.box.remove_widget(i)
if __name__ == '__main__':
TestApp().run()
在第一种情况下,当我按下“按钮”时,第一个和第三个按钮被移除,但“按钮2”仍然可见。
使用while循环: main.py
from kivy.app import App
class TestApp(App):
def del_button(self):
children = self.root.ids.box.children
i = 0
while i < len(children):
self.root.ids.box.remove_widget(children[i])
if __name__ == '__main__':
TestApp().run()
在第二种情况下,所有按钮都将直接删除。
对于for循环,并非所有元素都是在第一次删除的,而while循环则可以很好地完成工作。为什么会有这种奇怪的行为?
预先感谢您的回答。
答案 0 :(得分:2)
for
语句创建一个iterator
以在其循环中使用。 iterator
是在循环开始时创建的(请参见for loop documentation),因此,如果您在循环开始后更改了列表,则可能不正确。
然而,while
循环不使用iterator
,并且不会因更改列表结构而感到困惑。实际上,您的del_button()
方法的简单实现可以是:
def del_button(self):
children = self.root.ids.box.children
while len(children) > 0:
self.root.ids.box.remove_widget(children[0])
答案 1 :(得分:1)
在for
循环之前,children
包含按钮小部件[Button3,Button2,Button1]的三个存储位置的列表。
在第一次迭代中,i
引用了children
中的第一项,并删除了小部件Button3。
在第二次迭代之前,children
包含一个按钮小部件[Button2,Button1]的两个存储位置的列表。
在第二次迭代中,我引用了children
中的第二项,并删除了小部件Button1。
在第三次迭代之前,children
包含按钮小部件[Button2]的两个存储位置的列表。
由于children
中没有第三项,因此for循环退出。
由于i
(索引)始终保持为0,因此,由于它始终引用列表中的第一项children
,因此成功删除了所有三个按钮小部件。 self.root.ids.box.remove_widget(children[i])
等同于self.root.ids.box.remove_widget(children[0])
for
循环的解决方案是使用reversed(self.root.ids.box.children)
。
def del_button(self):
for child in reversed(self.root.ids.box.children):
self.root.ids.box.remove_widget(child)