[newbie] File handle destroyed before pending write is executed?

P

Pieter Lust

Hello,

I'm trying to learn myself Python. Doing that, I tried to implement
something logfile-ish. The essence looked like this:

# main module
import logmodule

mylog = logmodule.logfile()
mylog.enter('something')
# pass
# end main module

# logmodule
class logfile:
def __init__(self):
self.fh = file('log.txt', 'w')
def __del__(self):
self.fh.close()
def enter(self, text):
self.fh.write('%s\n' % text)
# end logmodule

After running the main module, log.txt was empty, though no exceptions
were raised. To get the text into the file, I had to add the pass
statement that's commented out above.

In debug mode, the line cursor jumps from the last line of the main
module into the __del__() method of the logmodule, but not into the
enter() method.

It seems that when the pass statement is not there:
- the interpreter parses the mylog.enter() line
- then sees that it is the last statement in the module
- because of that at once destroys all local objects in it, even
though the last statement requires one of those local objects
- this causes the __del__ method of the logfile to be called, so the
file is closed
- and only afterwards actually executes the last statement, which
fails but does not raise an error.

Is this what actually happened? And if so, is this triggerhappy
destroying required behaviour of a Python interpreter? (I'm using
v2.2, in the ActiveState PythonWin distribution.)

Thanks for improving my understanding of Python.

Pieter Lust
 
P

Peter Otten

Pieter said:
# main module
import logmodule

mylog = logmodule.logfile()
mylog.enter('something')
# pass
# end main module

# logmodule
class logfile:
def __init__(self):
self.fh = file('log.txt', 'w')
def __del__(self):
self.fh.close()
def enter(self, text):
self.fh.write('%s\n' % text)
# end logmodule

After running the main module, log.txt was empty, though no exceptions
were raised. To get the text into the file, I had to add the pass
statement that's commented out above.

In debug mode, the line cursor jumps from the last line of the main
module into the __del__() method of the logmodule, but not into the
enter() method.

Your code works here. I wuuld delete all logmodule.pyc files in your path
and restart the IDE. Maybe there is something out of sync.

(By the way, I think the __del__() method is superfluous)

Peter
 
P

Peter Otten

Mel said:
Pieter said:
# main module
import logmodule
mylog = logmodule.logfile()
mylog.enter('something')
# pass
# end main module

# logmodule
class logfile:
def __init__(self):
self.fh = file('log.txt', 'w')
def __del__(self):
self.fh.close()
def enter(self, text):
self.fh.write('%s\n' % text)
# end logmodule

[ ... ]
(By the way, I think the __del__() method is superfluous)

I wish it were, but no. The Python definition leaves the
door open for implementations that garbage-collect only when
they sorely need to, and may delay executing __del__ methods
indefinitely. So it could be that without the __del__ the
logfile instance got collected without collecting its fh
attribute, and therefore not closing the file.

Rather say that logfile.__del__ is only half an answer.

I really like the idea of dynamic scoping, as implemented
in CPython, but this, alas, is not the whole of Python.

Regards. Mel.

I don't understand this. Where is the difference between delaying the
garbage collection of the logfile instance or its fh attribute?

On implementations where immediate gc is not guaranteed, the only realistic
solution to avoid "dangling" open files would be to make the file closing
explicit:

class logfile:
def __init__(self):
self.fh = file('log.txt', 'w')
def close(self):
self.fh.close()
def enter(self, text):
self.fh.write('%s\n' % text)

which would then be called (in long-running apps rather than throw-away
scripts):

lf = logfile()
try:
lf.enter("something")
finally:
lf.close()

Is that the right way or would I still have to implement the __del__()
method?

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,164
Messages
2,570,901
Members
47,439
Latest member
elif2sghost

Latest Threads

Top