8

Is there a neat way to have multiply commands in the try block so that it basically tries every single line without stopping as soon as one command yields an error?

Basically I want to replace this:

try:
   command1
except:
   pass
try:
   command2
except:
   pass
try:
   command3
except:
   pass

with this:

try all lines:
  command1
  command2
  command3
except:
  pass

Defining a list so I could loop through the commands seems to be a bad solution

user4911943
  • 137
  • 1
  • 1
  • 5
  • You can create a separate function to call each command separately and handle exception handling in it. – Tanveer Alam Jun 15 '15 at 17:25
  • 1
    Same question with answers here: http://stackoverflow.com/questions/13874666/how-to-write-multiple-try-statements-in-one-block-in-python – Plug4 Jun 15 '15 at 17:27
  • 1
    @Plug4 Not a duplicate; that question only wants the subsequent commands to execute if the previous one in the chain fails. The asker wants to execute subsequent commands regardless of whether the previous ones succeed or fail. – Colonel Thirty Two Jun 15 '15 at 17:34
  • @ColonelThirtyTwo my bad! It is different. good point – Plug4 Jun 15 '15 at 17:35
  • 2
    Making a list of the functions to execute and looping through them is an *ok* solution... Perhaps the reason it seems bad is because it's somewhat of an anti-pattern to just throw out exceptions from an entire block of code. What if `command2` needs the result of `command1`, and `command1` throws an exception? Perhaps you can describe in more detail what it is that these commands do so that we can comment on whether or not the wholesale ignoring of exceptions makes sense here. – jme Jun 15 '15 at 17:41

5 Answers5

8

I'd say this is a design smell. Silencing errors is usually a bad idea, especially if you're silencing a lot of them. But I'll give you the benefit of the doubt.

You can define a simple function that contains the try/except block:

def silence_errors(func, *args, **kwargs):
    try:
        func(*args, **kwargs)
    except:
        pass # I recommend that you at least log the error however


silence_errors(command1) # Note: you want to pass in the function here,
silence_errors(command2) # not its results, so just use the name.
silence_errors(command3)

This works and looks fairly clean, but you need to constantly repeat silence_errors everywhere.

The list solution doesn't have any repetition, but looks a bit worse and you can't pass in parameters easily. However, you can read the command list from other places in the program, which may be beneficial depending on what you're doing.

COMMANDS = [
    command1,
    command2,
    command3,
]

for cmd in COMMANDS:
    try:
        cmd()
    except:
        pass
Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
-1

I use a different way, with a new variable:

continue_execution = True
try:
    command1
    continue_execution = False
except:
    pass
if continue_execution:
    try:
        command2
    except:
        command3

to add more commands you just have to add more expressions like this:

try:
    commandn
    continue_execution = False
except:
    pass
-2

Actually, your second choice is exactly hat you want. As soon as any command raises an exception, it will through to the except, and includes the information of which exception and at what line it occurred. You can, if you want, catch different exceptions and do different things with

try:
  command1
  command2
except ExceptionONe:
  pass
except Exception2:
  pass
except:
  pass   # this gets anything else.
Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • 8
    If `command1` throws, `command2` won't execute. OP wants `command2` to execute even if `command1` throws. Same with Linuxios's answer. – Colonel Thirty Two Jun 15 '15 at 17:31
  • Then you probably want to use the function approach in the answer above. You could make it a little slicker by defining a decorator, but even that's not much better. – Charlie Martin Jun 15 '15 at 18:37
  • It is not a good idea to put two or more expressions in one try clause. When debugging, this makes it very hard for someone to determine which expression was the one that raised the exception. – Utkonos Jul 06 '22 at 22:30
  • @Utkonos until you look at the stack trace, which will give you the exact line number from which the exception was thrown. Now, here's a quiz question: if command1 throws an exception, why do you think you can proceed to command2? – Charlie Martin Jul 07 '22 at 16:52
  • @CharlieMartin Hard disagree. Multiple statements in a try clause is an anti-pattern and bad form. The information is available in a stack trace, but a stack trace is not always available. The best practice is to understand which exceptions can be raised and of those exceptions, which ones you will want to handle. If the statements in the try clause all fit the same set of exceptions, then they can remain in the same try clause. However, you should always aim for one statement in one try clause. Don't promote bad code practices because it's possible. – Utkonos Jul 08 '22 at 17:17
  • This is stated in PEP8: "for all try/except clauses, limit the try clause to the absolute minimum amount of code necessary. Again, this avoids masking bugs." https://peps.python.org/pep-0008/#programming-recommendations – Utkonos Jul 08 '22 at 17:24
-2

You can except multiple errors within the same except statement.For example:

   try:        
    cmd1
    cmd2
    cmd3    
   except:
      pass

Or you could make a function and pass the error and the cmd through

def try_except(cmd):
    try:
        cmd
    except:
        pass
Tristan Vigil
  • 213
  • 1
  • 12
  • It is not a good idea to put two or more expressions in one try clause. When debugging, this makes it very hard for someone to determine which expression was the one that raised the exception. – Utkonos Jul 06 '22 at 22:30
-2

Actually I think he wants the following in a nicer way:

try:
   command1
except:
   try:
      command2
   except:
      try:
         command3
      except:
         pass