How to write a list to a file with newlines in Python3

Solution 1:

myfile.close -- get rid of that where you use with. with automatically closes myfile, and you have to call close like close() anyway for it to do anything when you're not using with. You should just always use with on Python 3.

with open('/path/to/filename.txt', mode='wt', encoding='utf-8') as myfile:
    myfile.write('\n'.join(lines))

Don't use print to write to files -- use file.write. In this case, you want to write some lines with line breaks in between, so you can just join the lines with '\n'.join(lines) and write the string that is created directly to the file.

If the elements of lines aren't strings, try:

    myfile.write('\n'.join(str(line) for line in lines))

to convert them first.

Your second version doesn't work for a different reason. If you pass

['element1', 'element2', 'element3']

to

def save_to_file(*text):

it will become

[['element1', 'element2', 'element3']]

because the * puts each argument it gets into a list, even if what you pass is already a list.

If you want to support passing multiple lists, and still write them one after another, do

def save_to_file(*text):

    with open('/path/to/filename.txt', mode='wt', encoding='utf-8') as myfile:
        for lines in text:
            myfile.write('\n'.join(str(line) for line in lines))
            myfile.write('\n')

or, for just one list, get rid of the * and do what I did above.

Edit: @Arafangion is right, you should probably just use b instead of t for writing to your files. That way, you don't have to worry about the different ways different platforms handle newlines.

Solution 2:

There are numerous mistakes there.

  1. Your indentation is messed up.
  2. The 'text' attribute in save_to_file refers to ALL the arguments, not just the specific argument.
  3. You're using "text mode", which is also confusing. Use binary mode instead, so that you have a consistent and defined meaning for '\n'.

When you iterate over the 'lines in text', because of these mistakes, what you're really doing is iterating over your arguments in the function, because 'text' represents all your arguments. That is what '*' does. (At least, in this situation. Strictly speaking, it iterates over all the remaining arguments - please read the documentation).