1

I am following the 'python crash course', one of the practice questions ask me to open/create the txt file 'guest_book' in append mode and create a while loop to ask user input their name, at the same time append their name into the 'guest_book' txt and print that they have been logged. I have wrote the following code.

filename = 'guest_book'

with open(filename, 'a') as f:
    while True:
        name = input('enter name ')
        f.write(name + '\n')
        print(f"You have been added to the guest book, {name}")

The problem: the while loop is successful and the final print is also successful, however when I check the guest_book txt. it does not record the inputted name. Interestingly, by simply switching the order of while loop and open txt command, it seems to work, like this:

filename = 'guest_book.txt'   

while True:
    with open(filename, 'a') as f:
        name = input('enter name ')
        f.write(name + '\n')
        print(f"You have been added to the guest book, {name}")

the only difference between the two codes are switched order of the while loop and "with open" line. Can someone explain to me why this order matters? No matter how hard I tried, I can't seem to understand the logic behind this. Thanks

  • 1
    How do you exit your program? When do you check ``guest_book.txt``? Do you know what the ``while`` and ``with`` statements do? – MisterMiyagi Apr 06 '20 at 10:35

2 Answers2

1

looks like the problem is that the oppened txt file is not closed properly, the program ends by force, not alowing the closing code to run, or something like that. the reason why the:

filename = 'guest_book.txt'   

while True:
  with open(filename, 'a') as f:
    name = input('enter name ')
    f.write(name + '\n')
    print(f"You have been added to the guest book, {name}")

works is because you are constantly closing and oppening the file.

if you want the file to close, I recomend adding a save funcion or an exit function. This will make the file close properly and save itself, kind of like this:

filename = 'guest_book'

with open(filename, 'a') as f:
  while True:
    name = input('enter name ')
    if name == 'exit':
         break
    f.write(name + '\n')
    print(f"You have been added to the guest book, {name}")
DrHax
  • 13
  • 3
  • The point of a ``with open`` statement is that it triggers under all normal circumstances, including exceptions and handle-able signals. A ``break`` is handled just like a ``KeyboardInterrupt`` or similar. – MisterMiyagi Apr 06 '20 at 10:40
  • XD thanks for correcting me... your way is much better – DrHax Apr 06 '20 at 22:30
1

Short explanation

Since your

while True

loop never ends your changes to the file are never actually "committed".

Long explanation

The whole reason we use

with open(filename, 'a') as f:
    f.write("write something")

instead of

f= open("myfile.txt","w+")
f.write("write something")
f.close() 

is so we don't have to close the file-access manually - only upon "f.close()" are the changes actually written to the local file!

In your code, close() is called behind the scenes once your "with"-block ends:

with open(filename, 'a') as f:
    while True:
        name = input('enter name ')
        f.write(name + '\n')
        print(f"You have been added to the guest book, {name}")
# close() would be triggered behind the scenes here
# only after completing ALL statements in your with-block, the changes get saved to the file.
print("We never reach this point...")

Since your code never reaches that point as you have a "while true loop", the file never gets closed and the changes are never written to the file.

In your second code example, the file gets opened and closed in every iteration of the "while true"-loop as your with-block starts and ends in one iteration of the loop. This means all changes are commited every iteration of the loop.

Edit:

As MisterMiyagi has pointed out:

"f.close() releases the file handle. It also calls (the internal equivalent of) f.flush() to commit outstanding changes. The primary purpose is releasing the file handle, though."

So you can either close the entire file (as Python flushes files automatically when closing) or call f.flush() in your while-loop after writing to flush the internal buffer, but to keep the file-handle open in case you want to continue writing afterwards.

So here is a working adaption of your first code (with flush):

filename = 'guest_book'

with open(filename, 'a') as f:
    while True:
        name = input('enter name ')
        f.write(name + '\n')
        f.flush() # making sure the changes are in the file.
        print(f"You have been added to the guest book, {name}")
Cribber
  • 2,513
  • 2
  • 21
  • 60
  • Changes are written even before ``f.close()`` or the end of a ``with`` block. Python has a buffer by default, but it is not infinite. – MisterMiyagi Apr 06 '20 at 10:38
  • I was under the impression that the entire purpose of f.close() was to make sure that all changes get flushed / written to the file. If Python even writes to the file before that, the behavior just gets more muddy... In any case, calling f.close() will guarantee that your changes are saved to the file at that point. – Cribber Apr 06 '20 at 11:06
  • 1
    ``f.close()`` releases the file handle. It *also* calls (the internal equivalent of) ``f.flush()`` to commit outstanding changes. The primary purpose is releasing the file handle, though. – MisterMiyagi Apr 06 '20 at 11:10
  • what is the purpose of flushing if the file is closed and flushed by default at each iteration? @MisterMiyagi or is the file not actually closed at the end of each iteration? – oldboy May 18 '21 at 09:39
  • The file never gets closed in the original code of OP and is *not* flushed at each iteration. The file only gets closed once you leave the `with` block - which never happens because of the infinity-loop inside the `with` block. You usually use flushing to clear the internal buffer of the file and actually write it to the file. Note: Python does it automatically when the buffer is full - see https://stackoverflow.com/questions/3167494/how-often-does-python-flush-to-a-file#3168436 ) – Cribber May 18 '21 at 09:50
  • 1
    @oldboy For the code in this answer, the file is *not* closed after each iteration. The [default buffering policy for ``open``](https://docs.python.org/3/library/functions.html#open) here is "after each N bytes", where N is usually 4096 or 8192 – that's roughly 300 or 600 lines of my name. So, explicit flushing in the loop is needed to get the "at each iteration" behaviour. – MisterMiyagi May 18 '21 at 09:51
  • In my last example I use `flush` to write the result of every iteration directly to the file. – Cribber May 18 '21 at 09:51
  • @MisterMiyagi ahhh, okay, very good to know. thank you. – oldboy May 19 '21 at 22:32