ded
ded

Reputation: 430

Conditionally writing to different output files

I have customizable script that can give up to 3 different output files depending on what is requested. Currently I have:

with open("option1", "w") as file1, open("option2", "w") as file2, open("option3", "w") as file3:

The issue I'm running into is if the option is not selected, the file is still being created (because of the open statement) which is what I'd like to avoid.

Naively what I think I want is an allowed syntax along the lines of the following that would be allowed:

with (if type1: open("option1", "w") as file1), (if type2: open("option2", "w") as file2), (if type3: open("option3", "w") as file3): 

The 3 different types and corresponding options are not mutually exclusive, it is common to want more than 1 of the file types. The type1, type2, and type3 variables are booleans that are set to False by default and toggled independently to True at the command line. Overall I'm trying to efficiently avoid the creation of empty files, and am open to even fairly drastic changes in code to accomplish it.

Upvotes: 1

Views: 1989

Answers (4)

J0HN
J0HN

Reputation: 26961

filenames_map = {"type1":"option1", "type2":"option2", "type3":"option3"}
filename = filenames_map.get(type, "default_option")
with open(filname, "w") as targetFile:
    # do whatever needs to be done

dict.get gets value from the dictionary and defaults to second argument of no such key found.

If types are not mutually exclusive it's a little bit trickier. with is a compound statement, so under normal execution flow (no exceptions) these two are roughly equivivalent:

with (context_manager) as something:
    do_stuff()  

try:
    context_manager.__enter__()
    do_stuff()
finally:
    context_manager.__exit__()

So, if you can't determine the number of files to write to until runtime, you'll have to manage context yourself. Luckily, open returns FileObject, hich are context managers with __enter__ and __exit__ defined. Luckily, open returns FileObject which is a quite simple context manager. As stated in documentation

with open("hello.txt") as f:
    for line in f:
        print line,

Is equal to

f = open("hello.txt")
try:
    for line in f:
        print line,
finally:
    f.close()

Now, to the point

target_files = []
# please modify to follow PEP-8 yourself, compressed for clarity
if user_wants_type1(type): target_files.append("option1")
if user_wants_type2(type): target_files.append("option2")
if user_wants_type3(type): target_files.append("option3")

try:
    handles = [open(filename) for filename in taget_files]
    for handle in handles:
        handle.write("something")
finally:
    for handle in handles:
        handle.close()

Upvotes: 4

unutbu
unutbu

Reputation: 880967

If you are using Python3, you could use contextlib.ExitStack:

import contextlib
filenames = ['option{}'.format(i) for i in range(1,4)]
types = [type1, type2, type3]

with contextlib.ExitStack() as stack:
    files = [stack.enter_context(open(filename, 'w'))
             for filename, typ in zip(filenames, types) if typ]

For Python2, you could use the contextlib2 module.

Upvotes: 1

Cory Kramer
Cory Kramer

Reputation: 118021

I would just figure out the file before you do any opening at all.

if type1:
    filename = "option1"
elif type2:
    filename = "option2"
elif type3:
    filename = "option3"

with open(filename, 'w') as outfile:
    #do stuff

Upvotes: 0

Kevin London
Kevin London

Reputation: 4728

Can it be more than one type at once? If not, I'd set up a conditional prior to writing to the file like this:

if type1:
    fname = "option1"
elif type2:
    fname = "option2"
elif type3:
    fname = "option3"

with open(fname, "w") as outfile:
    outfile.write("ok!")

Upvotes: 0

Related Questions