可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Does Python have a finally
equivalent for its if/else
statements, similar to its try/except/finally
statements? Something that would allow us to simplify this:
if condition1:
do stuff
clean up
elif condition2:
do stuff
clean up
elif condition3:
do stuff
clean up
...
...
to this:
if condition1:
do stuff
elif condition2:
do stuff
elif condition3:
do stuff
...
...
finally:
clean up
Where finally
would only be called only after a condition was met and its 'do stuff' run? Conversely, if no condition was met, the finally
code would not be run.
I hate to spout blasphemy, but the best way I can describe it is there being a GOTO
statement at the end of each block of 'do stuff' that led to finally
.
Essentially, it works as the opposite of an else
statement. While else
is only run if no other conditions are met, this would be ran ONLY IF another condition was met.
回答1:
It can be done totally non-hackily like this:
def function(x,y,z):
if condition1:
blah
elif condition2:
blah2
else:
return False
#finally!
clean up stuff.
In some ways, not as convenient, as you have to use a separate function. However, good practice to not make too long functions anyway. Separating your logic into small easily readable (usually maximum 1 page long) functions makes testing, documenting, and understanding the flow of execution a lot easier.
One thing to be aware of is that the finally
clause will not get run in event of an exception. To do that as well, you need to add try:
stuff in there as well.
回答2:
Your logic is akin to this:
cleanup = True
if condition1:
do stuff
elif condition2:
do stuff
elif condition3:
do stuff
....
else:
cleanup = False
if cleanup:
do the cleanup
Ugly, but it is what you asked
回答3:
The answer of mhlester has repetitive code, an improved version might be as follows:
class NoCleanUp(Exception):
pass
try:
if condition1:
do stuff
elif condition2:
do stuff
else:
raise NoCleanUp
except NoCleanUp:
pass
else:
cleanup
回答4:
you can use try
try:
if-elif-else stuff
finally:
cleanup stuff
the exception is raised but the cleanup is done
回答5:
Another suggestion, which might suit you if the conditions are pre-computed.
if condition1:
do stuff
elif condition2:
do stuff
...
if any([condition1, condition2, ...]):
clean_up
This would be a pain if you were evaluating the conditions as part of your if statements, because in that case you would have to evaluate them a second time for the any
function...unless Python is smarter than I realise.
回答6:
A little late to the party, but see the question has been active recently.
Usually I would make a context manager like this
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
And then you can use it like this
def cleanup():
print "Doing housekeeping"
with CleanUp(cleanup) as manager:
if condition1:
do stuff
elif condition2:
do stuff
else:
manager.cancel()
回答7:
Is this hideous?
for _ in range(1):
if condition1:
do stuff
break
elif condition2:
do stuff
break
else:
finally stuff
How about this?
class NoFinally(Exception):
pass
try:
if condition1:
do stuff
raise NoFinally
elif condition2:
do stuff
raise NoFinally
except NoFinally:
pass
else:
finally
Honestly, I hate both of these
回答8:
Like this:
from .actions import stuff1, stuff2
actions={condition1: stuff1, condition2: stuff2}
for condition in actions:
if condition:
actions[condition]()
cleanup()
break
Caveats are of course that your condition keys have to be unique and hashable. You can get around this by using a different data structure.