Search code examples
pythonwith-statementzen-of-python

With-statement with several variables: is there a more readable way to write this?


For example, I need to open two files using one with statement. And there's also a condition for each of them: to actually open or to use something instead.

In my case, it's whether to open a file specified by name or use stdin/stdout if name is not specified. The problem is that it's too long and complex for single line.

with    open(src_name, 'r') if src_name else sys.stdin as src, open(dst_name, 'w') if dst_name else sys.stdout as dst:
    # do something
    pass

For the first time, I had something like:

with    open(src_name, 'r') if src_name else sys.stdin as src, \
        open(dst_name, 'w') if dst_name else sys.stdout as dst:
    # do something
    pass

I personally like this version. For me it looks straightforward, but I need to use spaces to align two lines (and my IDE, PyCharm, warns me about extra spaces). BTW, Is it really critical to use spaces in python to align code?

The other way to align is:

with open(src_name, 'r') if src_name else sys.stdin as src, \
     open(dst_name, 'w') if dst_name else sys.stdout as dst:
    # do something
    pass

But it seems even worse due to PEP 8 – indentation.

And I don't like the "correct" version which is less readable and for the first glance even confusing:

with open(src_name, 'r') if src_name else sys.stdin as src, \
        open(dst_name, 'w') if dst_name else sys.stdout as dst:
    # do something
    pass

I can nest it in two levels but it is bad according to zen..

So i'm interested if there's a more elegant way to write this? Or maybe my version is good and I should ignore that warning about spaces.


Solution

  • To quote the great uncle bob, author of 'Clean Code' and famed engineer, 'never let the readers of your code scroll sideways', and 'your code should read like well written prose'.

    Instead of placing the if statement within the with block, why not separate them.

    if src_name:
        with open(src_name, 'r') as f:
            pass #do something
    else:
        pass # do something else
    

    Also, consider using better names for your variables, i.e. instead of src_name use file_path > makes more sense.

    I highly recommend 'Clean Code' by Robert C. Martin - it changed my life.