Reputation: 430
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
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
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
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
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