Does Python still print a trailing newline after printing the contents of a file?

97 Views Asked by At

Disclaimer: I know I essentially answer my own question, but please humor me anyway.

I'm working through a Python book I have (Python Crash Course 2nd Edition), and it says, "The only difference between this output and the original file is the extra blank line at the end of the output. The blank line appears because read() returns an empty string when it reaches the end of the file; this empty string shows up as blank line. If you want to remove the extra blank line, you can use rstrip() in the call to print()." That is the exact wording they use in the book. However, when I do what they tell me to do, no blank line is printed.

All of my code:

with open('/workspaces/functions/files_exceptions/pi_digits.txt', encoding='utf-8') as file_object:
    contents = file_object.read()

print(contents)
print("Hello World!") # To show a newline is not printed

Everything in the file I'm reading from:

 3.1415926535
      8979323846
      2643383279

Output:

3.1415926535
  8979323846
  2643383279
Hello World!

The output the book shows (the underlines are meant to represent a blank line (Stack Overflow won't let me include a blank line as code)):

3.1415926535
  8979323846
  2643383279
____________

As you can see, there is no trailing newline printed by Python. Does it not do this anymore? I know Python is now in version 3.12, so I'm wondering if it's a recent change made to Python. It might not be though, because the VS Code repo I'm working in was created before the update (I don't know whether or not it updates automatically, or if you have to do it manually (and if so, how) (please tell me the answer to this)).

2

There are 2 best solutions below

2
Cooper Harasyn On

I don't think the book which you're quoting is correct. Whether or not f.read() has a newline character at the end of the string which it returns is dependent on the contents of the file which is being read. Many text editors will add newlines at the end of text files, even if the user does not input them manually. I also use Visual Studio Code and my experience is that it does not enforce newlines at the end of files, so I think that a difference in editor or editor settings is the most likely explanation for your difference in behaviour.

Observe the following test, in which I use echo -n to create a file without a newline at the end, and echo to create a file with a newline at the end:

WSL /tmp/python-test$ echo -n "Test with no newline at the end" > no-newline.txt
WSL /tmp/python-test$ echo "Test with newline at the end" > newline.txt
WSL /tmp/python-test$ cat test.py
with open('no-newline.txt') as f:
  textWithoutNewline = f.read()
with open('newline.txt') as f:
  textWithNewline = f.read()

print('=' * 10)
print(textWithoutNewline)
print('=' * 10)
print(textWithNewline)
print('=' * 10)
WSL /tmp/python-test$ python3 test.py
==========
Test with no newline at the end
==========
Test with newline at the end

==========
WSL /tmp/python-test$
0
dawg On

You are conflating, I think, the default result of print with what is happening with file.read(). The \n is added by print and not by reading the file.

Even if you print a null string, print as a default adds a \n at the end:

>>> print("")

>>> 

vs:

>>> print("something")
something
>>> 

If you read an entire file into a string, that is read and then print adds that same \n. Your code is reading the whole contents of the file in one read. No \n is added (or ever was added) by Python's .read() method.

You can override the terminating \n for print in Python 3 (or with the print function in Python 2):

>>> print("something",end="!")
something!>>> 

But the default is \n.

Contrast this with file.write for stream output where a \n is NOT added at the end. This is important to know since a Unix file should be terminated with a \n to not break certain utilities...


With several edits of the post, maybe an example is helpful.

First, create a file as I understand what you have:

fn='/tmp/file.txt'

string='''\
 3.1415926535
      8979323846
      2643383279'''  # Note no trailing \n
        
with open(fn, 'w') as f:
    f.write(string)

Now read that file and print the repr of it which shows the acutual \n that were read:

with open(fn, 'r') as f:
    input_string=f.read()    # read entire file as a string
    print(repr(input_string))   

That prints:

' 3.1415926535\n      8979323846\n      2643383279'

So you can see that no new line is added by .read at the end.

If you just print that string and then another line of output:

print(input_string); print('on a new line') 

Your output is replicated:

 3.1415926535
      8979323846
      2643383279
on a new line

Contrast with:

print(input_string, 'NOT on a new line')

Where there is NOT a \n inserted:

 3.1415926535
      8979323846
      2643383279 NOT on a new line

Instead, the print sep property of print is used which, default, is a space.