2014-02-06 12 views
12

Hat Python einen finally äquivalenten für seine if/else-Anweisungen, ähnlich wie seine try/except/finally-Anweisungen? Etwas, das uns dies zu vereinfachen, würde es ermöglichen:'Endlich' Entsprechung für If/Elif-Anweisungen in Python

if condition1: 
     do stuff 
     clean up 
elif condition2: 
     do stuff 
     clean up 
elif condition3: 
     do stuff 
     clean up 
... 
... 

dazu:

if condition1: 
     do stuff 
elif condition2: 
     do stuff 
elif condition3: 
     do stuff 
... 
... 
finally: 
     clean up 

Wo finally nur nur aufgerufen werden würde, nachdem eine Bedingung erfüllt wurde und seine ‚tun Sachen‘ laufen? Umgekehrt, wenn keine Bedingung erfüllt wurde, würde der Code finally nicht ausgeführt werden.

Ich hasse es, Blasphemie auszustoßen, aber der beste Weg, um es zu beschreiben, ist eine GOTO Aussage am Ende jedes Blocks von 'do stuff', die zu finally führte.

Im Wesentlichen funktioniert es als das Gegenteil einer Aussage. Während else nur ausgeführt wird, wenn keine anderen Bedingungen erfüllt sind, würde dies NUR ausgeführt werden, wenn eine andere Bedingung erfüllt wäre.

+0

Nicht wirklich nutzen. Es klingt, als könnten Sie Ihre Logik vereinfachen. –

+0

Nein ... es gibt kein 'finally' für' if/else' –

+0

Addendum: Das if kann einige Return-Anweisungen enthalten, die nach ihnen bereinigt werden müssen. – Nemo

Antwort

11

fragte es völlig nicht getan werden kann, - wie folgt:

def function(x,y,z): 
    if condition1: 
     blah 
    elif condition2: 
     blah2 
    else: 
     return False 

    #finally! 
    clean up stuff. 

In gewisser Hinsicht nicht so praktisch, da Sie eine separate Funktion verwenden müssen. Allerdings gute Praxis, um nicht zu lange Funktionen sowieso zu machen. Wenn Sie Ihre Logik in kleine, leicht lesbare (normalerweise maximal 1 Seite) Funktionen aufteilen, wird das Testen, Dokumentieren und Verstehen des Ausführungsablaufs viel einfacher.

Eine Sache zu beachten ist, dass die finally-Klausel im Ausnahmefall nicht ausgeführt wird. Um das auch zu tun, müssen Sie try: Sachen dort auch hinzufügen.

+2

Die 'finally'-Klausel wird nicht ausgeführt, wenn' else: return False 'ist getroffen. – RolfBly

+5

Ja - darum geht es bei der Frage ... – Daniel

0

Ist das scheußlich?

for _ in range(1): 
    if condition1: 
     do stuff 
     break 
    elif condition2: 
     do stuff 
     break 
else: 
    finally stuff 

Wie wäre es damit?

class NoFinally(Exception): 
    pass 

try: 
    if condition1: 
     do stuff 
     raise NoFinally 
    elif condition2: 
     do stuff 
     raise NoFinally 
except NoFinally: 
    pass 
else: 
    finally 

Ehrlich gesagt, ich hasse diese beiden

+1

Ja, sie sind beide ziemlich funktional, aber auch ziemlich hässlich. Ich habe das Gefühl, dass es einen besseren Weg geben muss! – nobillygreen

+0

Beide haben immer noch das Problem des wiederholten Cleanup-Codes; in diesem Fall brechen oder erhöhen. – DylanYoung

+0

Diese beiden tun das Gegenteil des gewünschten Verhaltens (die Ausführung des "finally" -Codes, wenn einer der if-Zweige erfüllt ist). – Kundor

3

Ihre Logik verwandt ist dies:

cleanup = True 
if condition1: 
    do stuff 
elif condition2: 
    do stuff 
elif condition3: 
    do stuff 
.... 
else: 
    cleanup = False 

if cleanup: 
    do the cleanup 

hässlich, aber es ist das, was Sie

+0

Sehen Sie, ich hatte genau das in meinem eigenen Code, und ich stimme zu, es ist sehr hässlich. Ich war überrascht, als ich sah, dass es wirklich keinen guten Weg gibt, dies zu verschönern. – nobillygreen

+1

Es ist, aber vielleicht sollten Sie die Logik Ihres Programms überdenken, denn 'if/elif/else' soll einfach nicht dieser Art von Konstrukt folgen. –

1

Ein anderer Vorschlag, der Ihnen passen könnte, wenn die Bedingungen vorberechnet sind.

if condition1: 
    do stuff 
elif condition2: 
    do stuff 
... 
if any([condition1, condition2, ...]): 
    clean_up 

Dies wäre ein Schmerz, wenn Sie die Bedingungen als Teil Ihrer wenn Rechnung wurden, weil in diesem Fall würden Sie sie ein zweites Mal für die any Funktion zu bewerten haben ... es sei denn, Python ist intelligenter als Ich merke.

0

So:

def stuff1: 
    pass 

def stuff2: 
    pass 

actions={condition1:stuff1, condition2:stuff2} 

action = actions.get(condition, None) 
if action: 
    action() 
    cleanup() 

Caveats sind natürlich die Ihr Zustand Schlüssel eindeutig sein. Sie können dies umgehen, indem Sie eine priorisierte Hierarchie von Aktionen erstellen.

+0

Auch das ist ein gutes Python Modell für Schaltanweisungen – DylanYoung

1

Die Antwort von mhlester repetitiven Code hat, könnte eine verbesserte Version wie folgt:

class NoCleanUp(Exception): 
    pass 

try: 
    if condition1: 
     do stuff 
    elif condition2: 
     do stuff 
    else: 
     raise NoCleanUp 
except NoCleanUp: 
    pass 
else: 
    cleanup 
0

Ein wenig spät, um die Partei, sondern sehen die Frage wurde vor kurzem aktiv.

Normalerweise würde ich einen Kontext-Manager wie diese

class CleanUp(object): 

    class Cancel(Exception): 
     pass 

    def __init__(self, f_cleanup): 
     self.f_cleanup = f_cleanup 

    def __enter__(self): 
     return self 

    def __exit__(self, exception_type, exception_value, traceback): 

     cancelled = exception_type and issubclass(exception_type, self.__class__.Cancel) 

     if not cancelled: 
      self.f_cleanup() 

     return not exception_type or cancelled 

    def cancel(self): 
     raise self.__class__.Cancel 

machen Und Sie können es dann wie dies

def cleanup(): 
    print "Doing housekeeping" 


with CleanUp(cleanup) as manager: 
    if condition1: 
     do stuff 
    elif condition2: 
     do stuff 
    else: 
     manager.cancel()