1271

How do I write a line to a file in modern Python? I heard that this is deprecated:

print >>f, "hi there"

Also, does "\n" work on all platforms, or should I use "\r\n" on Windows?

Mateen Ulhaq
  • 21,459
  • 16
  • 82
  • 123
Yaroslav Bulatov
  • 55,467
  • 20
  • 132
  • 186
  • 21
    "\n" is not Unix-specific. When the file is opened in text mode (the default), it is translated automatically to the correct line ending for the current platform. Writing "\r\n" would produce "\r\r\n" which is wrong. – Chiara Coetzee Nov 02 '13 at 17:39
  • 1
    Just add the print ord(os.linesep) statement to see the ascii code (10 on most UNIX systems) – Stefan Gruenwald Mar 20 '17 at 17:08
  • 1
    Why do you think it is deprecated? – hola Jun 15 '19 at 07:32

16 Answers16

1431

This should be as simple as:

with open('somefile.txt', 'a') as the_file:
    the_file.write('Hello\n')

From The Documentation:

Do not use os.linesep as a line terminator when writing files opened in text mode (the default); use a single '\n' instead, on all platforms.

Some useful reading:

user35443
  • 6,021
  • 11
  • 51
  • 72
johnsyweb
  • 129,524
  • 23
  • 177
  • 239
  • 51
    This example is better than the open/close example. Using `with` is a safer way to remember to close a file. – Eyal Feb 08 '14 at 05:11
  • 29
    I don't have to call `the_file.close()` ? – Hussain Jun 05 '14 at 15:26
  • 31
    no you don't: http://stackoverflow.com/questions/3012488/what-is-the-python-with-statement-designed-for – Tal Jerome Oct 06 '14 at 07:54
  • @Johnsyweb Why do you say "os.linesep. There's lots of good stuff in os!", when you've earlier in the post recommended against using it? I'm suspecting an edit here, and it might be the reason for the down votes. – Horse SMith Dec 02 '14 at 19:35
  • @HorseSMith: 3.5 years after the events, I may misremember, but I edited my on the day to include the paragraph from the docs, leaving the link to `os.linesep` documentation for interested readers. The downvote, as I recall, came 2 years later. – johnsyweb Dec 02 '14 at 20:50
  • @Johnsyweb I think you misunderstood me. I didn't mean you edited after they had down voted. That'd make no sense of you to ask why people voted you down. What I do suspect happened is that you added the warning about why not to use os.linesep in an edit and forgot you advertised about how os had good stuff when the only thing used there in this case was os.linesep, which is rather useless and misleading in this case. People may have down voted you for sending the message that os.linesep was good in this case. It's okay you add it for documentation, but you do send mixed messages. – Horse SMith Dec 02 '14 at 22:44
  • 1
    @HorseSMith: I see. Hopefully my most recent edit clarifies my intent. Feel free to edit my answers if they are "rather useless and misleading". – johnsyweb Dec 03 '14 at 09:57
  • CLI: `python -c 'with open("file.txt", "w") as file: file.write("Hello\n")'`. – kenorb Apr 22 '16 at 09:41
  • "text mode (the default)" means `open` with `"w"`, you still need `os.linesep` with `"wb"` – user3226167 May 31 '17 at 07:27
  • 2
    @user3226167: That's an interesting point. But why would you open a binary file to write plain text? – johnsyweb May 31 '17 at 08:40
989

You should use the print() function which is available since Python 2.6+

from __future__ import print_function  # Only needed for Python 2
print("hi there", file=f)

For Python 3 you don't need the import, since the print() function is the default.

The alternative would be to use:

f = open('myfile', 'w')
f.write('hi there\n')  # python will convert \n to os.linesep
f.close()  # you can omit in most cases as the destructor will call it

Quoting from Python documentation regarding newlines:

On output, if newline is None, any '\n' characters written are translated to the system default line separator, os.linesep. If newline is '', no translation takes place. If newline is any of the other legal values, any '\n' characters written are translated to the given string.

Martin Tournoij
  • 24,971
  • 24
  • 101
  • 136
sorin
  • 149,293
  • 163
  • 498
  • 754
  • Is this going to be OK on Windows? (ie, \r\n newlines) – Yaroslav Bulatov May 28 '11 at 06:13
  • 42
    -1 "If you want to be sure, add os.linesep to the string instead of `\n`" would require newline="" otherwise you'd get `\r\r\n` on Windows. There is no reason to futz about with os.linesep at all. – John Machin May 28 '11 at 07:23
  • 1
    @Sorin Sbarnea: Both of your sentences are quite correct, but absolutely nothing to do with (explicitly) writing os.linesep instead of `\n`. Still -1 – John Machin May 28 '11 at 08:57
  • 1
    @Sorin: **Still -1. You only get the same result from f.write(os.linesep) on non-Windows systems.** By the way, your code won't work, you need mode='w' – John Machin May 28 '11 at 10:32
  • 9
    @Sorin: Your edit to add write mode is of course an improvement. However you strangely remain intransigent about os.linesep. See my answer. By the way, the documentation that you quote is for 3.x, but this part is also valid for 2.x in text mode: *any '\n' characters written are translated to the system default line separator, os.linesep** ... Windows: writing os.linesep is the same as writing `\r\n` which contains `\n` which is translated to os.linesep which is `\r\n` so the end result is `\r\r\n`. – John Machin May 29 '11 at 03:16
  • 7
    @John you were right, I corrected the os.linesep bug. Thanks. – sorin May 29 '11 at 07:24
  • 1
    Finish this with f.close() to close the file. Only then will you be able to see what's been written. – Suraj Kapoor Oct 14 '13 at 16:46
  • please do not tell me that 'print("hi there", file=f)' method is buildin method for python3. That makes me feel that i need to move to python3 – Ayrat Oct 21 '14 at 12:37
  • 1
    @sorin Why is the first way, using file=f, preferable to the second method using f.write? – I. J. Kennedy Nov 15 '14 at 16:02
  • when I am using this method it will remove all of the newlines. How can I fix that to have it written line by line? – UserYmY Jan 21 '15 at 16:32
  • 3
    For appending isnt it `open('myfile','a')` instead `open('myfile','w')`? – NeDark Aug 01 '15 at 00:59
  • My issue with this approach is that it adds a new line character to the last line in the file. Best approach for removing that. – Brad Ruderman Apr 12 '16 at 18:06
  • @psun: What's unclear about it? What's unclear about the documentation for `open`? – Lightness Races in Orbit Aug 03 '16 at 12:30
  • f is a file handler object and you could have found this inside the documentation. – sorin Aug 03 '16 at 17:43
  • @psun: Look up `open` and read what it returns. Takes ten seconds. – Lightness Races in Orbit Aug 03 '16 at 22:33
  • 7
    @BradRuderman That's part of the [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206) standard for what constitutes a "line" in a text file, i.e. every line in a text file must be terminated by a newline, even the last line. – wheeler Mar 02 '17 at 20:18
  • A better way would be to encode the string. So, use `open('myfile', 'w', encoding='utf-8')` instead of `open('myfile', 'w')`. – Vishal Gupta Jun 03 '20 at 00:32
128

The python docs recommend this way:

with open('file_to_write', 'w') as f:
    f.write('file contents\n')

So this is the way I usually do it :)

Statement from docs.python.org:

It is good practice to use the 'with' keyword when dealing with file objects. This has the advantage that the file is properly closed after its suite finishes, even if an exception is raised on the way. It is also much shorter than writing equivalent try-finally blocks.

dcoles
  • 3,385
  • 2
  • 26
  • 21
j7nn7k
  • 16,709
  • 18
  • 76
  • 87
89

Regarding os.linesep:

Here is an exact unedited Python 2.7.1 interpreter session on Windows:

Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.linesep
'\r\n'
>>> f = open('myfile','w')
>>> f.write('hi there\n')
>>> f.write('hi there' + os.linesep) # same result as previous line ?????????
>>> f.close()
>>> open('myfile', 'rb').read()
'hi there\r\nhi there\r\r\n'
>>>

On Windows:

As expected, os.linesep does NOT produce the same outcome as '\n'. There is no way that it could produce the same outcome. 'hi there' + os.linesep is equivalent to 'hi there\r\n', which is NOT equivalent to 'hi there\n'.

It's this simple: use \n which will be translated automatically to os.linesep. And it's been that simple ever since the first port of Python to Windows.

There is no point in using os.linesep on non-Windows systems, and it produces wrong results on Windows.

DO NOT USE os.linesep!

John Machin
  • 78,552
  • 11
  • 135
  • 182
  • great example -- curious if you're an ipython user? nice functions for formatting sessions – Alvin Sep 12 '12 at 08:22
  • I'm not entirely sure what you are trying to tell us here. os.linesep will return the line term character (or string) as defined by the operating system. Windows uses \r\n for line endings by default. However, a single \n is recognised. Using \n is going to give a fully portable OUTPUT but os.linesep is not wrong on windows. – Gusdor Feb 13 '13 at 12:08
  • 5
    @Gusdor: The point is that if you explicitly use `os.linesep` in Windows in text mode, the outcome is `\r\r\n` which is wrong. "Windows uses ..." is meaningless. The C runtime library (and hence Python) translate `\n` to `\r\n` on output in text mode. Other software may behave differently. It is NOT the case that all software running on Windows recognises a lone `\n` as a line separator when reading in text mode. Python does. Microsoft's Notepad text editor doesn't. – John Machin Feb 13 '13 at 20:32
  • @JohnMachin I think I understand what you mean. Worst case scenario is that you get a double \r in your file. I don't see what the consequence will be. Arguably, if you are writing text mode, you will be reading in it. At which point the extra \r is bloat, but nothing more (only the presence of \n marks a line end) I write for .Net usually, which lets me pick my line term to use with WriteLine(). Perhaps a similar method on TextIOWrapper would save this confusion. – Gusdor Feb 14 '13 at 09:32
  • 6
    Arguably somebody else will be reading it, not you, with some mickey-mouse software that will barf about the extra `\r` ... – John Machin Feb 14 '13 at 11:42
  • 2
    @Gusdor are you coming to python from a different language, where using '\n' results in output of '\n' on window, rather than '\r\n' -- so it lacks the '\r' expected by dumb text editors? As John says, that isn't how Python behaves -- '\n' is automatically replaced by '\r\n', if that is what os.linesep says to do. Hence, explicitly saying `os.linesep` *is* "wrong" here. Its like `Department of Redundancy Department`. Yes you can do it. No, you don't want to. – ToolmakerSteve Dec 19 '13 at 03:12
  • I totally agree that it should be explicit. Never blindly assume things are configured properly unless you set it yourself. In the case of EOL it is no sweat to just do it. Send what you know the receiver requires. `f.write('hi there\n')` for unix and `f.write('hi there\r\n')` for DOS. I suggest you build an output line like `outline = "Hi There!" + "\r\n"` then simply `f.write(outline)` – SDsolar Aug 19 '17 at 08:45
59

I do not think there is a "correct" way.

I would use:

with open ('myfile', 'a') as f: f.write ('hi there\n')

In memoriam Tim Toady.

Hyperboreus
  • 31,109
  • 9
  • 45
  • 84
  • But the OP might want to write additional stuff to the file. Here the file will be closed when the `with` goes out of scope. – Keith May 28 '11 at 05:51
  • That might want to be `open(..., 'a')` or even `'at'`. – mtrw May 28 '11 at 05:53
  • 6
    Erm, yeah. That is the idea of using with. If you want to keep the file open, just call open at the beginning and call close when you are done... – Hyperboreus May 28 '11 at 05:53
  • 1
    @mtrw. True. OP was appending. – Hyperboreus May 28 '11 at 05:54
  • 1
    As far as python is concerned is RIP Tim Toady - and very very _very_ rightfully so – Mr_and_Mrs_D Jul 06 '17 at 12:27
  • I just saw this `Zen of Python is, "There should be one — and preferably only one — obvious way to do it."` . This explains much of my disappointment with the language. I have used it a lot for five years plus but for its libraries and often in spite of the syntax. No inline comments? The mystifying class structure? Single line only lambdas? – WestCoastProjects Feb 08 '18 at 00:26
  • 1
    The `zen of perl` would be a bit of an oxymoron. – Davos Mar 02 '18 at 03:13
23

In Python 3 it is a function, but in Python 2 you can add this to the top of the source file:

from __future__ import print_function

Then you do

print("hi there", file=f)
Keith
  • 40,128
  • 10
  • 53
  • 74
17

If you are writing a lot of data and speed is a concern you should probably go with f.write(...). I did a quick speed comparison and it was considerably faster than print(..., file=f) when performing a large number of writes.

import time    

start = start = time.time()
with open("test.txt", 'w') as f:
    for i in range(10000000):
        # print('This is a speed test', file=f)
        # f.write('This is a speed test\n')
end = time.time()
print(end - start)

On average write finished in 2.45s on my machine, whereas print took about 4 times as long (9.76s). That being said, in most real-world scenarios this will not be an issue.

If you choose to go with print(..., file=f) you will probably find that you'll want to suppress the newline from time to time, or replace it with something else. This can be done by setting the optional end parameter, e.g.;

with open("test", 'w') as f:
    print('Foo1,', file=f, end='')
    print('Foo2,', file=f, end='')
    print('Foo3', file=f)

Whichever way you choose I'd suggest using with since it makes the code much easier to read.

Update: This difference in performance is explained by the fact that write is highly buffered and returns before any writes to disk actually take place (see this answer), whereas print (probably) uses line buffering. A simple test for this would be to check performance for long writes as well, where the disadvantages (in terms of speed) for line buffering would be less pronounced.

start = start = time.time()
long_line = 'This is a speed test' * 100
with open("test.txt", 'w') as f:
    for i in range(1000000):
        # print(long_line, file=f)
        # f.write(long_line + '\n')
end = time.time()

print(end - start, "s")

The performance difference now becomes much less pronounced, with an average time of 2.20s for write and 3.10s for print. If you need to concatenate a bunch of strings to get this loooong line performance will suffer, so use-cases where print would be more efficient are a bit rare.

  • There is no need to call `print()` multiple times for each line, you can input each line as a positional argument and specify a newline delimiter using `print(line1, line2, ... sep="\n")`. This makes only one write call. – Zenul_Abidin Sep 08 '20 at 15:00
13

Since 3.5 you can also use the pathlib for that purpose:

Path.write_text(data, encoding=None, errors=None)

Open the file pointed to in text mode, write data to it, and close the file:

import pathlib

pathlib.Path('textfile.txt').write_text('content')
Community
  • 1
  • 1
johnson
  • 2,846
  • 3
  • 23
  • 28
7

When you said Line it means some serialized characters which are ended to '\n' characters. Line should be last at some point so we should consider '\n' at the end of each line. Here is solution:

with open('YOURFILE.txt', 'a') as the_file:
    the_file.write("Hello")

in append mode after each write the cursor move to new line, if you want to use w mode you should add \n characters at the end of the write() function:

the_file.write("Hello\n")
alper
  • 2,299
  • 4
  • 36
  • 73
Reza Tanzifi
  • 492
  • 4
  • 13
4

One can also use the io module as in:

import io
my_string = "hi there"

with io.open("output_file.txt", mode='w', encoding='utf-8') as f:
    f.write(my_string)
kmario23
  • 50,454
  • 13
  • 141
  • 141
4

If you want to avoid using write() or writelines() and joining the strings with a newline yourself, you can pass all of your lines to print(), and the newline delimiter and your file handle as keyword arguments. This snippet assumes your strings do not have trailing newlines.

print(line1, line2, sep="\n", file=f)

You don't need to put a special newline character is needed at the end, because print() does that for you.

If you have an arbitrary number of lines in a list, you can use list expansion to pass them all to print().

lines = ["The Quick Brown Fox", "Lorem Ipsum"]
print(*lines, sep="\n", file=f)

It is OK to use "\n" as the separator on Windows, because print() will also automatically convert it to a Windows CRLF newline ("\r\n").

Zenul_Abidin
  • 453
  • 5
  • 16
4

If you want to insert items in a list with a format per line, a way to start could be:

with open('somefile.txt', 'a') as the_file:
    for item in items:
        the_file.write(f"{item}\n")
Higgs
  • 513
  • 4
  • 16
Alfredo EP
  • 51
  • 3
1

To write text in a file in the flask can be used:

filehandle = open("text.txt", "w")
filebuffer = ["hi","welcome","yes yes welcome"]
filehandle.writelines(filebuffer)
filehandle.close()
  • 2
    It is always more advisable to write to a file with a `with open('file_to_write', 'w') as f:` statement. It's much easier to make sure that file will not be left open if someone accidentally wrote something in between that would result in not having an explicit `close()` call – Artūras Jonkus Jun 25 '20 at 12:55
0

You can also try filewriter

pip install filewriter

from filewriter import Writer

Writer(filename='my_file', ext='txt') << ["row 1 hi there", "row 2"]

Writes into my_file.txt

Takes an iterable or an object with __str__ support.

Emin Bugra Saral
  • 3,716
  • 1
  • 15
  • 25
0

When I need to write new lines a lot, I define a lambda that uses a print function:

out = open(file_name, 'w')
fwl = lambda *x, **y: print(*x, **y, file=out) # FileWriteLine
fwl('Hi')

This approach has the benefit that it can utilize all the features that are available with the print function.

Update: As is mentioned by Georgy in the comment section, it is possible to improve this idea further with the partial function:

from functools import partial
fwl = partial(print, file=out)

IMHO, this is a more functional and less cryptic approach.

MxNx
  • 1,240
  • 17
  • 26
  • 2
    Or another (probably cleaner) way to write this: `from functools import partial; fwl = partial(print, file=out)`. – Georgy Jul 05 '19 at 10:56
  • @Georgy Your approach is so good that it can be given as a new answer. – MxNx Jul 05 '19 at 11:10
  • 1
    The idea is the same as yours, just implementation is a bit different. If you want, you can add it in an edit to your answer. I'm fine with it. – Georgy Jul 05 '19 at 11:30
-2

since others have answered how to do it, I'll answer how it happens line by line.

with FileOpenerCM('file.txt') as fp: # is equal to "with open('file.txt') as fp:"
      fp.write('dummy text')

this is a so-called context manager, anything that comes with a with block is a context manager. so let's see how this happens under the hood.

class FileOpenerCM:
     def __init__(self, file, mode='w'):
         self.file = open(file, mode)
      
     def __enter__(self):
          return self.file
      
     def __exit__(self, exc_type, exc_value, exc_traceback):
         self.file.close()

the first method __init__ is (as you all know) the initialization method of an object. whenever an object is created obj.__init__ is definitely called. and that's the place where you put your all the init kinda code.

the second method __enter__ is a bit interesting. some of you might not have seen it because it is a specific method for context managers. what it returns is the value to be assigned to the variable after the as keyword. in our case, fp.

the last method is the method to run after an error is captured or if the code exits the with block. exc_type, exc_value, exc_traceback variables are the variables that hold the values of the errors that occurred inside with block. for example,

exc_type: TypeError
exc_value: unsupported operand type(s) for +: 'int' and 'str
exc_traceback: <traceback object at 0x6af8ee10bc4d>

from the first two variables, you can get info enough info about the error. honestly, I don't know the use of the third variable, but for me, the first two are enough. if you want to do more research on context managers surely you can do it and note that writing classes are not the only way to write context managers. with contextlib you can write context managers through functions(actually generators) as well. it's totally up to you to have a look at it. you can surely try generator functions with contextlib but as I see classes are much cleaner.

Hyperx837
  • 598
  • 2
  • 12