Python If/Elif/Else, For and Lists



我试图在列表上迭代elif语句,最后用其他语句来迭代列表。这是我的代码:

    if clickPoint is None:
        print(clickPoint)
    for each in meal_objects:
        if inside(clickPoint, each._button):
            each._button.setFill('green')
            break
    for each in build_meal_objects:
        if inside(clickPoint, each._button):
            each._button.setFill('green')
            break
    for each in ingredient_objects:
        if inside(clickPoint, each._button):
            each._button.setFill('green')
            break
    else:
        print(clickPoint)

feal_objects,build_meal_objects和ingredient_objects是列表。

问题在于,由于许多原因,此代码是可怕的。如果未满足第一个条件,即使循环条件之一已经运行,每个循环也将运行,并且最终的语句也将运行。确实,如果满足了任何for循环中的任何IF语句,则其余的IF块不应执行。

代码实际上应该更像是这样的伪代码:

    if clickPoint is None:
        print(clickPoint)
    elif for each in meal_objects:
        if inside(clickPoint, each._button):
            each._button.setFill('green')
            break
    elif for each in build_meal_objects:
        if inside(clickPoint, each._button):
            each._button.setFill('green')
            break
    elif for each in ingredient_objects:
        if inside(clickPoint, each._button):
            each._button.setFill('green')
            break
    else:
        print(clickPoint)

我觉得我可能会忽略一些非常简单的东西,所以如果是这样,请原谅我,或者这是一个不好的问题。谢谢!

可能是最简单的(也是最灵活的方式(是将它们放置在功能中并强制return,例如:

def f(clickPoint, *lists):
    if clickPoint is None:
        # or raise an exception instead as seems more an exception than natural
        return (None, None)
    for lst in lists:
        for item in lst:
            if inside(clickPoint, item._button):
                item._button.setFill('green')
                return (lst, item)
    return (None, None)

然后称其为:

lst, item = f(clickPoint, meal_objects, build_meal_objects, ingredient_objects)

这意味着只有所有列表的第一个元素都会有一个填充集,并且它返回对列表的引用和设置的项目,如果您想进行打印,您可以稍后检查。

eg:

if (lst, item) == (None, None):
    # handle that nothing was set?
else:
    # you know which button (`item`) in which list (`lst`) had its fill changed 

我想如果您真的有必要,可以使用Python具有的for/else语法,但这要求您有效地将序列链接到单个for上以发行break ON,例如:

for lst, item in ((lst, item) for lst in (meal_objects, build_meal_objects, ingredient_objects) for item in lst):
    if inside(clickPoint, item._button):
        item._button.setFill('green')
        break
else: # this only enters if `break` was NOT issued in the for-loop
    print('nothing set')

好的,这将需要一些解释。看看下面的内容。

for x in range(5):
    for y in range(5):
        print (x*y)
        if x*y==3:
            break
    else:
        continue  # executed if the loop finished normally (no break)
    break         # executed if 'continue' was skipped (break)

上面的程序只是打印值,直到找到3

输出:

0
0
0
0
0
0
1
2
3

如果最后一个continueelse不存在怎么办?

for x in range(5):
    for y in range(5):
        print (x*y)
        if x*y==3:
            break

输出:

0
0
0
0
0
0
1
2
3
0
2
4
6
8
0
3
0
4
8
12
16

看到它在找到3后甚至不会停止,这是因为break仅导致退出内部环。因此,第一个代码可用于退出嵌套循环。甚至是一个非常深的嵌套环。

那么如何将其应用于您的代码中?看看这个!

my_objects = {0: meal_objects, 1: build_meal_objects, 2: ingredient_objects}
flag2=True
flag1=True
if clickPoint is None:
        print(clickPoint)
        flag2=False
if flag2:
    for i in range(3):
        temp_obj = my_objects[i]
        for each in temp_obj:
            if inside(clickPoint, each._button):
                each._button.setFill('green')
                flag1=False
                break
        else:
            continue
        break
if flag1 and flag2:
    print(clickPoint)

使用标志变量。现在,在上述代码中首先设置flag1=Trueflag2=True。第一个if块将执行,如果无clickPoint,则将其打印。和 flag2设置为 False

我为什么这样做?确保在下一个if语句中失败。因此,您的for循环均未执行。

下一部分如果INCASE clickPoint不是None。执行了下一个if,请注意,这是我进行了很小的更改!

my_objects = {0: meal_objects, 1: build_meal_objects, 2: ingredient_objects}

创建对象的dict,并使用range(your_dict_size)一个一个一个一个。 Note 这样,您可以添加越来越多的对象。

记得我解释了有关退出嵌套环的原因吗?这正是发生的事情。当您获得想要的的那一刻,它就是控制退出,并且不再运行循环。

和set flag1 to False

注意:两个 flag 变量的原因是因为确保您的else零件(这是最后一个if(如果前两个if S失败,则始终执行。

我认为这是您要做的:

if clickPoint is None:
    print(clickPoint)
else:
    called = False
    for each in meal_objects:
        if inside(clickPoint, each._button):
            each._button.setFill('green')
            called = True
            break
    if not called:
        for each in build_meal_objects:
            if inside(clickPoint, each._button):
                each._button.setFill('green')
                called = True
                break
        if not called:
            for each in ingredient_objects:
                if inside(clickPoint, each._button):
                    each._button.setFill('green')
                    called = True
                    break
            if not called:
                print(clickPoint)

这确保只有一个for循环调用each._button.setFill('green')。如果他们都没有称呼它,则打印语句运行。

似乎您可能会很好地使用itertools.chain将for循环凝结成一个块。这样,您就可以循环浏览列表中的所有项目,然后立即停止到第一个是"内部"。

from itertools import chain
if clickPoint is None:
    print(clickPoint)
for each in chain(meal_objects, build_meal_objects, ingredient_objects):
    if inside(clickPoint, each._button):
        each._button.setFill('green')
        break
else:
    print(clickPoint)

最新更新