-1

Related to this question; Is it really that bad to catch a general exception?

My question is what are the issues (if any) with catching a general exception in order to try something else on failure.

The case I am looking at is like so (in python, but that shouldn't be relevant);

def my_function(some_input):
    """ Process some_input. some_input may be a single object, 
        or a list-like iterable of the same.
        More likely to be a list. """
    try:
        # process as for a list
        photos = []
        for dog in some_input:
            photos.append(walk(dog))
        multiphotolabels(photos)
    except:
        # I guess it was just one item after all
        dog = some_input
        photos = walk(dog)
    return photos

Suppose it is reasonable to assume that treating a single dog as a list will throw some exception, but it's tricky to know exactly what.

Ignore issues with malicious input, this program was not designed on any level to be robust to that. Is this likely to cause problems?

Clumsy cat
  • 289
  • 1
  • 12
  • What if `some_input` is an iterable other than a list (degenerate case: a string)? Also you should almost never use a bare `except:`; `except TypeError:` would catch a failure to iterate over a non-iterable. – jonrsharpe Aug 15 '19 at 12:36
  • 2
    If the function is called in a loop then it will also ignore `KeyboardInterrupt`, so you couldn't terminate it manually with ctrl + C – roganjosh Aug 15 '19 at 12:40
  • @jonrsharpe dog itself is an iterable, so when a dog is passed, the itteration won't fail, but the first walk call will. If a string was passed as input I would expect both the try an the except to fail (as walk won't work on a string). The function would raise an error from inside the except block if it got a string, which is fine because a string is not appropriate input. – Clumsy cat Aug 15 '19 at 12:40
  • @roganjosh that is a very good point. Maybe that is the basis of an answer? – Clumsy cat Aug 15 '19 at 12:41
  • @Clumsycat then maybe try it the other way around; you can't walk a list. – jonrsharpe Aug 15 '19 at 12:43
  • 1
    `except Exception` will remove that issue. This question could be a dupe in a number of ways but I think the main thrust would be that it indicates that you don't have a grip on the code flow. I'm guilty of doing just the same thing. – roganjosh Aug 15 '19 at 12:43
  • @jonrsharpe, yes, exchanging the try and except blocks wouldn't change the question though. – Clumsy cat Aug 15 '19 at 12:44
  • 1
    Ignoring the 'as `e`' part: https://stackoverflow.com/questions/18982610/difference-between-except-and-except-exception-as-e-in-python. `except Exception` skips 3 exceptions – roganjosh Aug 15 '19 at 12:51
  • @roganjosh wow, I would never have guessed. Thank you for explaining. – Clumsy cat Aug 15 '19 at 12:55

1 Answers1

1

I think you need to try to separate the exceptions and handle them separately. A simple except Exception is too broad. I have implemented a little example with your example code:

class WalkError(Exception):
    pass


class MultiphotolabelsError(Exception):
    pass


def my_function(some_input):
    """ Process some_input. some_input may be a single object,
        or a list-like iterable of the same.
        More likely to be a list. """
    dog = None  # It is needed because dog variable could be undeclared.
    photos = []
    try:
        for dog in some_input:
            photos.append(walk(dog))
        multiphotolabels(photos)
    except (WalkError, MultiphotolabelsError) as err:
        # I guess it was just one item after all
        print("Exception: {}".format(err))
        photos = walk(dog)
    except Exception as unexpected_err:
        print("Unexpected error. Error: {}".format(unexpected_err))
    return photos


def walk(input_param):
    if all(isinstance(item, str) for item in input_param):
        return input_param
    raise WalkError("Not all elem of list are string")


def multiphotolabels(input_param):
    if len(input_param) > 1:
        return
    raise MultiphotolabelsError("Len of input is not greather than 1.")


print(my_function(["a", "b", "c"]))
print(my_function(["a", "b", "c", 5]))
print(my_function(["a"]))

As you can see I have handled separately the expected exceptions (WalkError, MultiphotolabelsError) and the unexpected other errors are handler separately (except Exception as unexpected_err)

Output of the script:

>>> python3 test.py 
['a', 'b', 'c']
Unexpected error. Error: 'int' object is not iterable
['a', 'b', 'c']
Exception: Len of input is not greather than 1.
a

NOTE:

You implementation not really safety because the walk function can generate recursive Exception as you can see below:

Code:

print(my_function(["a", "b", "c", [8]]))

Output:

>>> python3 time.py 
Exception: Not all elem of list are string
Traceback (most recent call last):
  File "timeout.py", line 17, in my_function
    photos.append(walk(dog))
  File "timeout.py", line 31, in walk
    raise WalkError("Not all elem of list are string")
__main__.WalkError: Not all elem of list are string

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "timeout.py", line 39, in <module>
    print(my_function(["a", "b", "c", [8]]))
  File "timeout.py", line 22, in my_function
    photos = walk(dog)
  File "timeout.py", line 31, in walk
    raise WalkError("Not all elem of list are string")
__main__.WalkError: Not all elem of list are string

I hope my answer can help you!

milanbalazs
  • 4,811
  • 4
  • 23
  • 45
  • I don't follow how this answers the OP. I'm not critiquing the code itself, but I don't see how it relates to the question. – roganjosh Aug 15 '19 at 13:59
  • apologies there is an error in my code, the except block should contain dog=some_input. – Clumsy cat Aug 15 '19 at 14:04
  • Also, to be honest @roganjosh is right, the question is not about what I should have done, it's asking what the problems are with the way I'm doing it. I upvote anyway for the suggestion that the components where the error is expected throw custom errors. – Clumsy cat Aug 15 '19 at 14:09
  • Thanks for your opinion. Perhaps my answer is too detailed but I think it contains the answer for the question. But I will pay more attention to answer only the question! :) Thanks again! – milanbalazs Aug 15 '19 at 14:26