20
votes

Firstly, I'm not sure if my approach is proper, so I'm open to a variety of suggestions.

If try/except statements are frequently repeated in code, are there any good ways to shorten them or avoid fully writing them out?

try:
    # Do similar thing
    os.remove('/my/file')
except OSError, e:
    # Same exception handing
    pass

try:
    # Do similar thing
    os.chmod('/other/file', 0700)
except OSError, e:
    #Same exception handling
    pass

For example, for one line actions you could define a exception handling wrapper and then pass a lambda function:

def may_exist(func):
    "Work with file which you are not sure if exists."""
    try:
        func()
    except OSError, e:
        # Same exception handling
        pass

may_exist(lambda: os.remove('/my/file'))
may_exist(lambda: os.chmod('/other/file', 0700))

Does this 'solution' just make things less clear? Should I just fully write out all the try/except statements?

4
possible duplicate of Python: try-except as an Expression? - agf
Me and @kindall just answered this question very nicely yesterday. - agf
@agf: That question seems partially related, thanks for linking. However Ned Batchelder's answer seems to have the advantage that there is no need to create a function out of the block of code for which exceptions need to be caught. - sutre

4 Answers

26
votes

The best way to abstract exception handling is with a context manager:

from contextlib import contextmanager
@contextmanager
def common_handling():
    try:
        yield
    finally:
        # whatever your common handling is

then:

with common_handling():
    os.remove('/my/file')

with common_handling():
    os.chmod('/other/file', 0700)

This has the advantage that you can put full statements, and more than one of them, in each common_handling block.

Keep in mind though, your need to use the same handling over and over again feels a lot like over-handling exceptions. Are you sure you need to do this much?

4
votes

It would probably be cleaner to make may_exist a decorator:

from functools import wraps
def may_exist(func):
   @wraps(func):
   def wrapper(*args, **kwds):
       try:
           return func(*args, **kwds)
       except OSError:
           pass
   return wrapper

Then you can either do:

may_exist(os.remove)('/my/file')
may_exist(os.chmod)('/other/file', 0700)

for a one-off call, or:

remove_if_exists = may_exist(os.remove)
...
remove_if_exists('somefile')

if you use it a lot.

2
votes

I think your generic solution is ok, but I wouldn't use those lambdas at the bottom. I'd recommend passing the function and arguments like this

def may_exist(func, *args):
    "Work with file which you are not sure if exists."""
    try:
        func(args)
    except OSError, e:
        # Same exception handling
        pass

may_exist(os.remove, '/my/file')
may_exist(os.chmod, '/other/file', '0700')
1
votes

Would something like this work:

def may_exist(func, *func_args):
    try:
        func(*func_args)
    except OSError as e:
        pass