1

I have a set of slightly different operations I want to perform on a bunch of different files, some of which may or may not exist at any given time. In all cases, if a file doesn't exist (returning FileNotFoundError), I want it to just log that that particular file doesn't exist, then move on, i.e. identical exception handling for all FileNotFoundError cases.

The tricky part is that what I want to do with each set of file is slightly different. So I can't simply do:

for f in [f1, f2, f3, f4]: try: do_the_thing(f) except FileNotFoundError: print(f'{f} not found, moving on!') 

Instead I want something like:

try: for f in [f_list_1]: do_thing_A(f) for f in [f_list_2]: do_thing_B(f) for f in [f_list_3]: do_thing_C(f) except FileNotFoundError: print(f'{f} not found, moving on!') 

But where each for block is tried regardless of success / failure of previous block.

Obviously I could use a whole lot of separate try-except sets:

for f in [f_list_1]: try: do_thing_A(f) except FileNotFoundError: print(f'{f} not found, moving on!') for f in [f_list_2]: try: do_thing_B(f) except FileNotFoundError: print(f'{f} not found, moving on!') for f in [f_list_3]: try: do_thing_C(f) except FileNotFoundError: print(f'{f} not found, moving on!') 

But is there a more elegant or Pythonic way to do this, given that it's the same exception handling in each case?

5
  • 1
    What do you do inside the do_the_thing_* methods? Because your exception usage is always effectively ignoring it, so to me it feels like you can go for os.path.isfile() or os.path.exists() in an if condition. This question seems to have a lot of such approaches. If you are immediately opening the file inside those methods, maybe consider putting the try-except inside that method? Commented Jan 28, 2022 at 15:10
  • Is the use of exceptions fundamental to this task or could you use os.path.isfile()? Commented Jan 28, 2022 at 15:10
  • Use of exceptions is not fundamental - it is essentially ignoring it, yes, at most just flagging for reference. To clarify, @shriakhilc are you suggesting basically putting the try-except inside the various methods, having it try one of the various approaches to check for file existence as the first step and encapsulating the entire rest of the method in the try block? Various methods are just data cleaning and processing - first step is opening the file, last step is re-saving it - so I think something like that would work, but could you give an example? Commented Jan 28, 2022 at 15:18
  • Correction, I suppose it'd be more like encapsulating the rest of the method with if file_exists: (using one of the various os methods), and maybe else: report_file_missing? Commented Jan 28, 2022 at 15:23
  • 1
    IMHO codereview would be more suitable for this question. codereview.stackexchange.com Commented Jan 28, 2022 at 15:48

1 Answer 1

2

I think I would start with something like this that wraps your functions.

def do_thing_A(f): print(f"do_thing_A({f})") def do_thing_B(f): print(f"do_thing_B({f})") def do_by_thing(fn, file_path): try: fn(file_path) except FileNotFoundError: print(f'{file_path} not found, moving on!') tasks = [ (do_thing_A, ["hello", "word"]), #(function, list_of_paths) (do_thing_B, ["foo", "bar"]), ] for fn, file_list in tasks: for file_path in file_list: do_by_thing(fn, file_path) 

Having done so though I think this begs the question of decorators. Maybe something like:

import os def if_file_exists(fn): def _inner(f): if not os.path.isfile(f): print(f'{f} not found, moving on!') return fn(f) return _inner @if_file_exists def do_thing_A(f): print(f"do_thing_A({f})") @if_file_exists def do_thing_B(f): print(f"do_thing_B({f})") tasks = [ (do_thing_A, ["./results.csv", "word"]), #(function, list_of_paths) (do_thing_B, ["./sample.txt", "bar"]), ] for fn, file_list in tasks: for file_path in file_list: fn(file_path) 

Of course, either option could be altered to use exceptions or os.path.isfile(). I just did one each way.

If you decided that wrappers and decorators was overkill, then you could also just simply do:

def do_thing_A(f): print(f"do_thing_A({f})") def do_thing_B(f): print(f"do_thing_B({f})") tasks = [ (do_thing_A, ["hello", "word"]), #(function, list_of_paths) (do_thing_B, ["foo", "bar"]), ] for fn, file_list in tasks: for file_path in file_list: try: fn(file_path) except FileNotFoundError: print(f'{file_path} not found, moving on!') 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.