Some hours ago, someone asked on StackExchange about a more pythonic way to represent the following code:
-
with open(read_csv, 'r') as read_file:
-
with open(write_csv, 'r') as write_file:
-
reader = csv.reader(read_file)
-
writer = csv.writer(write_file)
-
for row in reader:
-
#Do some stuff to manipulate the fields from read_file and th
Unfortunately, the user deleted his question, before i could post my suggestion. The only evidence of the question remaining is this tweet from PythonQuestions. I'm posting my extended answer here for future reference and to see, if someone more versed in python might correct me.
Major update
Please have a look at the comments section below and some of the corrections posted there. Some suggested the use of contextlib, which is a part of the standard library i didn't know about yet.. Also, it seems python >2.7 can handle more than one context at a time so that my "solution" isn't really needed.
My try
Starting off, i do not think that the syntax used is too unpythonic. If it is only used once or twice, i wouldn't change anything about it, but if someone likes to open more than one file within a single with-statement often, then writing a proxy class that adheres to the with-statements syntax might be useful. For opening two files it would look like this:
-
class openTwoFiles():
-
def __init__(self, file1, file2):
-
self.fn1 = file1
-
self.fn2 = file2
-
-
def __enter__(self):
-
self.f1 = open(self.fn1,'r')
-
self.f2 = open(self.fn2,'r')
-
return (self.f1, self.f2)
-
-
def __exit__(self, type, value, traceback):
-
self.f1.close()
-
self.f2.close()
The class openTwoFiles implements the two basic methods __enter__ and __exit__ which the with-statement needs to execute. Using this class might look like this:
-
with openTwoFiles('test.txt','test2.txt') as (f1,f2):
-
print f1
-
print f2
Of course for the specific code in question the implementation of the csv-class and an iterator over the reader might also help, but i'm sticking with the general case, in which the opening of the files suffices. The class openTwoFiles might be extended to open a arbitrary number of files with custom flags:
-
class openFiles():
-
def __init__(self, files, flags):
-
if isinstance(files,basestring):
-
files = [files]
-
if isinstance(flags,basestring):
-
flags = [flags]
-
assert len(flags)==len(files)
-
self.files = files
-
self.flags = flags
-
-
def __enter__(self):
-
self.fhs = []
-
for f, fl in zip(self.files, self.flags):
-
self.fhs.append(open(f,fl))
-
return self.fhs
-
-
def __exit__(self, type, value, traceback):
-
for f in self.fhs:
-
f.close()
-
-
with openFiles(['test.txt','test2.txt'], ['r','r']) as ll:
-
print ll