Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python opening and reading files one liner

I know best way to file opening for reading/writing is using with with

instead of using

f = open('file.txt', 'w')
f.write('something')
f.close()

we should write --

with open('file.txt', 'w') as f:
    f.write('something')

but what if I want to simply read a file ? I can do this

with open('file.txt') as f:
    print (f.read())

but what is the problem in below line

print (open('file.txt').read())

OR

alist = open('file.txt').readlines()
print (alist)

does it automatically close the file after executing this statement? is this a standard way to write? should we write like this?

other than this - should I open a file in a function and pass the pointer to other for writing or should I declared it as a global variable? i.e

def writeto(f):
    #do some stuff
    f.write('write stuff')

def main():
   f = open('file.txt', 'w')
   while somecondition:
        writeto(f)
   f. close()

OR

f = open('file.txt', 'w')

def writeto():
    #do some stuff
    f.write('write stuff')

def main():
   while somecondition:
        writeto()

f. close()
like image 202
micheal Avatar asked Feb 23 '15 18:02

micheal


1 Answers

Addressing your questions in order,

"What's wrong with print(open(file).readlines())?"

Well, you throw away the file object after using it so you cannot close it. Yes, Python will eventually automatically close your file, but on its terms rather than yours. If you are just playing around in a shell or terminal, this is probably fine, because your session will likely be short and there isn't any resource competition over the files usually. However, in a production environment, leaving file handles open for the lifetime of your script can be devastating to performance.

As far as creating a function that takes a file object and writes to it, well, that's essentially what file.write is. Consider that a file handle is an object with methods, and those methods behind the scenes take self (that is, the object) as the first argument. So write itself is already a function that takes a file handle and writes to it! You can create other functions if you want, but you're essentially duplicating the default behavior for no tangible benefit.

Consider that your first function looks sort of like this:

def write_to(file_handle, text):
    return file_handle.write_to(text)

But what if I named file_handle self instead?

def write_to(self, text):
    return self.write(text)

Now it looks like a method instead of a stand-alone function. In fact, if you do this:

f = open(some_file, 'w')   # or 'a' -- some write mode
write_to = f.write

you have almost the same function (just bound to that particular file_handle)!

As an exercise, you can also create your own context managers in Python (to be used with the with statement). You do this by defining __enter__ and __exit__. So technically you could redefine this as well:

class FileContextManager():
    def __init__(self, filename):
        self.filename = filename
        self._file = None

    def __enter__(self):
        self._file = open(self.filename, 'w')

    def __exit__(self, type, value, traceback):
        self._file.close()

and then use it like:

with FileContextManager('hello.txt') as filename:
    filename.write('Hi!')

and it would do the same thing.

The point of all of this is just to say that Python is flexible enough to do all of this if you need to reimplement this and add to the default behavior, but in the standard case there's no real benefit to doing so.


As far as the program in your example, there's nothing wrong with virtually any of these ways in the trivial case. However, you are missing an opportunity to use the with statement in your main function:

def main():
    with open('file.txt') as filename:
        while some_condition:
            filename.write('some text')
    # file closed here after we fall off the loop then the with context

if __name__ == '__main__':
    main()

If you want to make a function that takes a file handle as an argument:

def write_stuff(file_handle, text):
    return file_handle.write(text)

def main():
    with open('file.txt', 'w') as filename:
        while some_condition:
            write_stuff(filename, 'some text')
    # file closed here after we fall off the loop then the with context

if __name__ == '__main__':
    main()

Again, you can do this numerous different ways, so what's best for what you're trying to do? What's the most readable?

"Should I open a file in a function and pass the pointer to other for writing or should I declared it as a module variable?"

Well, as you've seen, either will work. This question is highly context-dependent and normally best practice dictates having the file open for the least amount of time and in the smallest reasonable scope. Thus, what needs access to your file? If it is many things in the module, perhaps a module-level variable or class to hold it is a good idea. Again, in the trivial case, just use with as above.

like image 87
Two-Bit Alchemist Avatar answered Sep 22 '22 01:09

Two-Bit Alchemist