correct way to catch exception with Python 'with' statement

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Nov 28 02:46:59 EST 2016


On Monday 28 November 2016 17:09, Ganesh Pal wrote:

> Dear Python friends,
> 
> Any suggestion on how to add exception and make the below program look
> better  ,  I am using Python 2.7 and Linux
> 
> ------------------------------------------------------------
> --------------------------------
> 
> def create_files_append():
>     """  """
>     try:
>         os.makedirs(QA_TEST_DIR)
>     except:
>         raise OSError("Can't create directory (%s)!" % (QA_TEST_DIR))
> 
>     # Create few files and write something
>     for i in range(1000):
>         with open(os.path.join(QA_TEST_DIR,"filename%d" %i),'w') as f:
>              f.write("hello")
> 
>     # Append the files
>     for i in range(1000):
>         with open(os.path.join(QA_TEST_DIR,"filename%d" %i),'w') as f:
>              f.write("hello")
> 
>     return True


There is no need to return True. The function either succeeds, or it raises an 
exception, so there is no need to return any value at all.

There is no need to catch the exception if you're not going to do anything with 
it. os.makedirs already raises OSError if there is a problem creating the 
directories, so all you are doing is catching a sensible, useful error message 
that tells you WHY it failed with a useless, generic error message that tells 
you nothing.

py> os.makedirs('/root/xyz')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/os.py", line 157, in makedirs
    mkdir(name, mode)
OSError: [Errno 13] Permission denied: '/root/xyz'


Permission denied is *much* more useful than "cannot create directory".

Your comment says "append the files", but you're not appending to the files, 
you are overwriting them. So your code is better written like this:


def create_files_append():
    """Docstring"""
    os.makedirs(QA_TEST_DIR)
    # Create few files and write something
    for i in range(1000):
        with open(os.path.join(QA_TEST_DIR,"filename%d" %i),'w') as f:
            f.write("hello")


If you really want to create the file, close the file, then append to it, you 
can do this:

def create_files_append():
    """Docstring"""
    os.makedirs(QA_TEST_DIR)
    # Create few files and write something
    for i in range(1000):
        with open(os.path.join(QA_TEST_DIR,"filename%d" %i),'w') as f:
            f.write("hello")
    # Append to the files
    for i in range(1000):
        with open(os.path.join(QA_TEST_DIR,"filename%d" %i),'a') as f:
            f.write("hello")


but that's a waste of time, this is better:

def create_files_append():
    """Docstring"""
    os.makedirs(QA_TEST_DIR)
    # Create few files and write something
    for i in range(1000):
        with open(os.path.join(QA_TEST_DIR,"filename%d" %i),'w') as f:
            f.write("hellohello")


If you want to skip any files that can't be opened:

def create_files_append():
    """Docstring"""
    os.makedirs(QA_TEST_DIR)
    # Create few files and write something
    for i in range(1000):
        try:
            with open(os.path.join(QA_TEST_DIR,"filename%d" %i),'w') as f:
                f.write("hellohello")
        except (OSError, IOError):
            pass



> What will be the best  way to catch the exception in the above program  ?

Not catching it at all.


> Can we replace both the  with statement in the above program with something
> like below
> 
> try:
>     for i in range(1000):
>                with open(os.path.join(QA_TEST_DIR,"filename%d" %i),'w') as f:
>                    f.write("hello")
> except IOError as e:
>     raise

What's the point of that? All you are doing is catching the exception and then 
immediately raising it again. That's the same as not catching it.




-- 
Steven
"Ever since I learned about confirmation bias, I've been seeing 
it everywhere." - Jon Ronson




More information about the Python-list mailing list