9

I know the best way to open files for reading/writing is using 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 with this

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 that, should I open a file in a function and pass the pointer to other functions for writing or should I declare it as a global variable?

For example

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()
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
micheal
  • 1,283
  • 3
  • 14
  • 23
  • As an aside, the straightforward answer to the question as posed in the title is thus: `with open('file.txt', 'w') as f: f.write('some text')` for writing or `with open('file.txt') as f: contents = f.read()` for reading. – Two-Bit Alchemist Feb 23 '15 at 19:26
  • Isn't it bizarre, that the question "What is the problem with opening and reading files in a one-liner in Python?" was closed with reference to "How should I read a file line-by-line in Python?", which has nothing to do with this question as stated? – sdbbs Jun 19 '23 at 13:30

2 Answers2

8

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.

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
Two-Bit Alchemist
  • 17,966
  • 6
  • 47
  • 82
  • so what do you suggest for 2nd problem. first solution or second? – micheal Feb 23 '15 at 18:41
  • Sorry - I was adding that second example. I don't quite get the thrust of your second question. The idea of my answer is to say, "This is really about as simple as it gets for file reading and writing, and everything you're proposing is essentially what is there by default." What's stopping you from using the `with` statement in your main function? – Two-Bit Alchemist Feb 23 '15 at 18:48
  • You are providing a different solution. why would I create a `FileContextManager` when there is already `with`. my point is I can not do file operation in same function and I have to make a separate function for that, and for that I have to use a (global or parametrized ) file object – micheal Feb 23 '15 at 19:01
  • "Why would I create a `FileContextManager` when there is already `with`?" I don't know. I wrote that to show you that you _could_. But why would you make a separate function that takes a file handle and writes to it? It's already what `file.write` does. "I cannot do a file operation in the same function without making a separate function and a global variable and passing the file object around." Where did you get that idea? – Two-Bit Alchemist Feb 23 '15 at 19:05
  • Updated my answer with a second attempt to answer your final question. HTH – Two-Bit Alchemist Feb 23 '15 at 19:19
-5

The problem is you put a space between print and (). This code works good in Python3:

print(open('yourfile.ext').read())
Texom512
  • 4,785
  • 3
  • 16
  • 16