1

I'm writing a manager class that will allow creation of different types of log files (raw, CSV, custom data format), and I'd like to keep the log file open to write lines as they come in. The log file can also be started and stopped by events (button presses, conditions).

I want to know if I can combine the with open('file') as file: syntax, with an instance variable in a class - so I'm not stuck polling in a loop while the file is open, but instead can write to the file by event.

I know how to use the open and close methods, but everyone says "with" is much more robust, and (more) certain to write the file to disk.

I want to do something like this:

class logfile:

    def __init__(self,filename,mode):
        with open(filename, mode) as self.f:
            return

    def write(self, input):
        self.f.write(input)

and use it like:

lf = logfile("junk.txt","wt")    # yeah, lf has to be global to use like this. Keeping demo simple here.

...then leave method, do other stuff to refresh screen, respond to other events, and later when a data line to log comes in:

lf.write(dataline)

I then expect things to close cleanly, file to get flushed to disk when lf disappears - either implicitly at program close, or explicitly when I set lf to None.

When I try this, the file is (apparently) closed at return from creation of lf. I can inspect lf and see that

lf.f == <_io.TextIOWrapper name='junk.txt' mode='wt' encoding='UTF-8'>

but when I try to use lf.write("text"), I get:

ValueError: I/O operation on closed file.

Is there a way of using "with" and keeping it in an instance?

Failing that, should I just use open, close and write, and ensure I have try/except/finally in init and close in exit?

jddj
  • 83
  • 7

1 Answers1

2

The with syntax is a context manager in Python. So, what it does is, it calls file.close() method once it is out of context. So, the file is closed already after its return. I think you can write your class this way:

class logfile:

    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def write(self, text):
        with open(self.filename, self.mode) as f:
           f.write(text)
Alexander
  • 105,104
  • 32
  • 201
  • 196
Pratik
  • 1,351
  • 1
  • 20
  • 37
  • OK, that seems clear. So is the only way to do this in an object to use file.open/write/close and trap exceptions in __init__ (which prevent close on exit if an unhandled crash)? – jddj Nov 12 '19 at 05:21
  • yes that's correct. otherwise force close it https://stackoverflow.com/questions/25176168/explicit-way-to-close-file-in-python – αԋɱҽԃ αмєяιcαη Nov 12 '19 at 05:24
  • 1
    @jddj see my updated answer. Instead of keeping file open we can only open it when we want to write something. – Pratik Nov 12 '19 at 05:25
  • 1
    Thanks, though that's a ton of opening and closing (log entries every second, in the context of this application). Think I probably need to go to open/write/close. Definitely appreciate the clarification! – jddj Nov 12 '19 at 05:27