Python-kivy:在删除kivy中的项目时,为什么for循环的行为与while循环不同?

时间:2018-08-25 20:04:29

标签: python kivy

当尝试从布局中删除项目时,我注意到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循环则可以很好地完成工作。为什么会有这种奇怪的行为?

预先感谢您的回答。

2 个答案:

答案 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循环

第一次迭代

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)