16

I have a question regarding error checking in Python. Let's say I have a function that takes a file path as an input:

def myFunction(filepath):
    infile = open(filepath)
    #etc etc...

One possible precondition would be that the file should exist.

There are a few possible ways to check for this precondition, and I'm just wondering what's the best way to do it.

i) Check with an if-statement:

if not os.path.exists(filepath):
    raise IOException('File does not exist: %s' % filepath)

This is the way that I would usually do it, though the same IOException would be raised by Python if the file does not exist, even if I don't raise it.

ii) Use assert to check for the precondition:

assert os.path.exists(filepath), 'File does not exist: %s' % filepath

Using asserts seems to be the "standard" way of checking for pre/postconditions, so I am tempted to use these. However, it is possible that these asserts are turned off when the -o flag is used during execution, which means that this check might potentially be turned off and that seems risky.

iii) Don't handle the precondition at all

This is because if filepath does not exist, there will be an exception generated anyway and the exception message is detailed enough for user to know that the file does not exist


I'm just wondering which of the above is the standard practice that I should use for my codes.

4 Answers 4

16

If all you want to do is raise an exception, use option iii:

def myFunction(filepath):
    with open(filepath) as infile:
        pass

To handle exceptions in a special way, use a try...except block:

def myFunction(filepath):
    try:
        with open(filepath) as infile:
            pass
    except IOError:
        # special handling code here

Under no circumstance is it preferable to check the existence of the file first (option i or ii) because in the time between when the check or assertion occurs and when python tries to open the file, it is possible that the file could be deleted, or altered (such as with a symlink), which can lead to bugs or a security hole.

Also, as of Python 2.6, the best practice when opening files is to use the with open(...) syntax. This guarantees that the file will be closed, even if an exception occurs inside the with-block.

In Python 2.5 you can use the with syntax if you preface your script with

from __future__ import with_statement
Sign up to request clarification or add additional context in comments.

Comments

4

Definitely don't use an assert. Asserts should only fail if the code is wrong. External conditions (such as missing files) shouldn't be checked with asserts.

As others have pointed out, asserts can be turned off.

The formal semantics of assert are:

  1. The condition may or may not be evaluated (so don't rely on side effects of the expression).

  2. If the condition is true, execution continues.

  3. It is undefined what happens if the condition is false.

More on this idea.

Comments

3

The following extends from ~unutbu's example. If the file doesn't exist, or on any other type of IO error, the filename is also passed along in the error message:

path = 'blam'
try:
    with open(path) as f:
        print f.read()
except IOError as exc:
    raise IOError("%s: %s" % (path, exc.strerror))

=> IOError: blam: No such file or directory

Comments

1

I think you should go with a mix of iii) and i). If you know for a fact, that python will throw the exception (i.e. case iii), then let python do it. If there are some other preconditions (e.g. demanded by your business logic) you should throw own exceptions, maybe even derive from Exception.

Using asserts is too fragile imho, because they might be turned off.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.