2017-06-24 4 views
0

Ich versuche, elif Anweisungen über Listen mit einer else-Anweisung am Ende zu iterieren. Hier ist mein Code:Python If/Elif/Else, Für und Listen

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) 

meal_objects, build_meal_objects und ingredient_objects sind Listen.

Das Problem ist, dass dieser Code aus vielen Gründen schrecklich ist. Wenn die erste Bedingung nicht erfüllt ist, wird jede for-Schleife ausgeführt, auch wenn eine der for-Schleifen-Bedingungen bereits ausgeführt wurde, und die letzte else-Anweisung wird ebenfalls ausgeführt. Wenn eine der if-Anweisungen in einer der for-Schleifen erfüllt ist, sollte der Rest des if-Blocks nicht ausgeführt werden.

Der Code sollte wirklich etwas mehr wie diese Pseudo-Code sein:

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) 

Ich fühle mich wie ich etwas wirklich einfach, mit Blick könnte so verzeiht mir, wenn dies der Fall ist oder wenn es sich um eine schlecht geschriebene Frage. Vielen Dank!

+0

Sie können kein 'elif for' haben. Sie können eine Variable verwenden, um zu verfolgen, ob eine der Schleifen ausgeführt wurde, und dann nur die nächste Schleife ausführen, falls dies der Fall ist. – anonymoose

+0

Mit "ran" meinst du es 'each._button.setFill (" grün ")'? – anonymoose

+1

Wickeln Sie sie in eine Funktion und anstelle von "brechen" verwenden Sie eine "Rückkehr" ist eine Möglichkeit. –

Antwort

0

Ich denke, das ist, was Sie zu tun versuchen:

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) 

Dies dass für Schleifen ruft each._button.setFill('green') nur eine der sicher macht. Wenn keiner von ihnen es aufruft, wird die print-Anweisung ausgeführt.

1

wahrscheinlich einfachste (und flexibelste Weg) ist sie in Funktion zu setzen und eine return Gewalt, zB:

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) 

Dann rufen Sie es wie:

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

Das bedeutet, dass nur Das erste Element aller Listen enthält eine Füllmenge und gibt einen Verweis auf die Liste und das Element zurück, das Sie später überprüfen können, wenn Sie den Druck ausführen möchten.

zB:

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

Ich nehme an, wenn Sie wirklich ein Bedürfnis haben, können Sie nutzen die for/else Syntax machen, den Python hat aber das erfordert, dass Sie effektiv an der Kette die Sequenzen zu einem einzelnen for der zur Ausgabe von break auf, zum Beispiel:

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') 
1

Ok, das wird eine Erklärung brauchen. Schau dir das unten an.

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) 

Das obige Programm druckt nur Werte bis es eine 3 findet.

Ausgabe:

0 
0 
0 
0 
0 
0 
1 
2 
3 

Was passiert, wenn der letzte continue und else nicht anwesend waren?

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

Ausgang:

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

Sie dafür, nicht zu stoppen, selbst nachdem ein 3 zu finden, ist, weil die break nur die inneren Schleife auszutreten verursacht. Der erste Code kann also zum Verlassen einer verschachtelten Schleife verwendet werden. Sogar eine sehr tief verschachtelte Schleife.

So wie dies in Ihrem Code beantragen? Schau dir das an!

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) 

Verwenden Flag-Variablen. Stellen Sie nun im obigen Code zuerst flag1=True und flag2=True ein. Der erste if Block wird ausgeführt, und wenn clickPoint None ist, dann wird es gedruckt. Und flag2 wird False sein.

Warum ich das getan? Um sicherzustellen, dass es in der nächsten if Anweisung fehlschlägt. Dadurch wird keine Ihrer for Schleifen ausgeführt.

Der nächste Teil, wenn clickPoint incase nicht None. Die nächste if ist ausgeführt und notieren Sie hier ist, wo ich eine kleine Änderung vorgenommen habe!

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

eine dict Ihrer Objekte erstellen und eins nach dem anderen mit range(your_dict_size) bekommen. HINWEIS diese Weise können Sie noch mehr und mehr Objekte hinzufügen können.

Remember Ich erklärte über das Verlassen von verschachtelten Schleifen? Genau das passiert. In dem Moment, wenn Sie bekommen, was Sie wollten das ist es Control Exits und keine mehr für Schleifen ausgeführt werden.

und setzen flag1 zu False

HINWEIS: Der Grund für zwei Flag Variablen, weil Ihr else Teil, um sicherzustellen, (Hier ist es die letzte if) ausführt, immer wenn die ersten beiden if s Scheitern.

0

Scheint so, als wäre es gut gewesen, itertools.chain zu verwenden, um die for-Schleifen in einem Block zu verdichten. Auf diese Weise können Sie alle Elemente in Ihren Listen durchlaufen und anhalten, sobald Sie zum ersten "innerhalb" kommen.

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)