Writing string to file from loop if does not already exist - python

This has been asked and answered, and I've read lots of those posts... but for some reason my code isn't working. Hopefully someone can help.
The code matches strings within a variable and then attempts to write those strings to a file if they don't already exist within that file.
Code doesn't work. Any help please?
#this works
str_match = re.findall(r'(https?://[^\s]+)', input
if str_match:
with open (datestamp+_"strings.txt", "a+") as text_file:
for string in str_match:
#THIS DOES NOT WORK -- WITH OR WITHOUT THE '\n'
#WITH, ALWAYS SAYS IT EXISTS AND WRITES NOTHING
if (string + '\n') in text_file:
print "str exists"
else:
print "Doesn't exist"
text_file.write(string + '\n')
Without it, it says the string doesn't exist and writes it to the file multiple times.
if string in text_file:
print "str exists"
else:
print "Doesn't exist"
text_file.write(string + '\n')
If I look at the string that's written using vim, it looks like: mystring$
(the $ is appended at the end of each string -- and no, adding +"$" doesn't work)
Any help please?

The problem here is that files don't (really) support membership tests with the in operator.
The reason why no error is thrown is because files are iterable and thus x in file evaluates to any(x is e or x == e for e in file) (docs). This operation works only once, because after the first time the file has been exhausted and no more lines can be read (until you write new ones).
The solution to your problem is to read all the lines in the file into a list or set and use that for membership tests:
all_lines= set(text_file)
...
if (string + '\n') in all_lines:
However, this does not explain why if (string + '\n') in text_file: always returns True. In fact it should always (after the first iteration) return False, and that's exactly what happens when I run your code on my machine. There's probably something writing to the file in other parts of your code.

Problem is you are iterating through the file once, and file is not rewound afterwards. File is only scanned once.
You have to read the data into a set first, then you can loop over the strings (and set is very performant because uses dichotomic search in O(log(N)))
Problem: if there are duplicates in str_match, it will be written more than once, so I added unicity with a set
if str_match:
with open(datestamp+"_strings.txt", "r") as text_file: # read-only
lines = set(map(str.rstrip,text_file)) # reads the file, removes \n and \r
with open(datestamp+"_strings.txt", "a") as text_file: # append, write only
for string in set(str_match):
#THIS DOES NOT WORK -- WITH OR WITHOUT THE '\n'
#WITH, ALWAYS SAYS IT EXISTS AND WRITES NOTHING
if (string) in lines:
print("str exists")
else:
print("Doesn't exist")
text_file.write(string + '\n')
Notes:
to preserve the order in the file, remove set in the for string loop, and add the string to lines when found.
first version with \n added would work OK on Linux, but on windows it would fail because of the \r. Now I rstrip the lines when I put them in the mini-database: no need to add \n when testing and is portable
the string$ you saw in vim is explained: vim adds end-of-lines as $ when showing the text. Mystery solved.

Related

Write a program in Python 3.5 that reads a file, then writes a different file with the same text that was in the first one as well as more?

The exact question to this problem is:
*Create a file with a 20 lines of text and name it “lines.txt”. Write a program to read this a file “lines.txt” and write the text to a new file, “numbered_lines.txt”, that will also have line numbers at the beginning of each line.
Example:
Input file: “lines.txt”
Line one
Line two
Expected output file:
1 Line one
2 Line two
I am stuck, and this is what I have so far. I am a true beginner to Python and my instructor does not make things very clear. Critique and help much appreciated.
file_object=open("lines.txt",'r')
for ln in file_object:
print(ln)
count=1
file_input=open("numbered_lines.txt",'w')
for Line in file_object:
print(count,' Line',(str))
count=+1
file_object.close
file_input.close
All I get for output is the .txt file I created stating lines 1-20. I am very stuck and honestly have very little idea about what I am doing. Thank you
You have all the right parts, and you're almost there:
When you do
for ln in file_object:
print(ln)
you've exhausted the contents of that file, and you won't be able to read them again, like you try to do later on.
Also, print does not write to a file, you want file_input.write(...)
This should fix all of that:
infile = open("lines.txt", 'r')
outfile = open("numbered_lines.txt", 'w')
line_number = 1
for line in infile:
outfile.write(str(line_number) + " " + line)
infile.close()
outfile.close()
However, here is a more pythonic way to do it:
with open("lines.txt") as infile, open("numbered_lines.txt", 'w') as outfile:
for i, line in enumerate(infile, 1):
outfile.write("{} {}".format(i, line))
Good first try, and with that, I can go through your code and explain what you did right (or wrong)
file_object=open("lines.txt",'r')
for ln in file_object:
print(ln)
This is fine, though generally you want to put a space before and after assignments (you are assigning the results of open to file_object) and add a space after a,` when separating arguments, so you might want to write that like so:
file_object = open("lines.txt", 'r')
for ln in file_object:
print(ln)
However, at this point the internal reference in the file_object have reached the end of the file, so if you wish to reuse the same object, you need to seek back to the beginning position, which is 0. As your assignment only states write to the file (and not on the screen), the above loop should be omitted from the file (but I get what you want to do, you want to see the contents of the file immediately though sometimes instructors are pretty strict on what they accept). Moving on:
count=1
file_input=open("numbered_lines.txt",'w')
for Line in file_object:
Looks pretty normal so far, again, minor formatting issues. In Python, typically we name all variables lower-case, as names with Capitalization are generally reserved for class names (if you wish to, you may read about them). Now we enter into the loop you got
print(count,' Line',(str))
This prints not quite what you want. as ' Line' is enclosed inside a quote, it is treated as a string literal - so it's treated literally as text and not code. Given that you had assigned Line, you want to take out the quotes. The (str) at the end simply just print out the string object and it definitely is not what you want. Also, you forgot to specify the file you want to print to. By default it will print to the screen, but you want to print it to the the numbered_lines.txt file which you had opened and assigned to file_input. We will correct this later.
count=+1
If you format this differently, you are assigning +1 to count. I am guessing you wanted to use the += operator to increment it. Remember this on your quiz/tests.
Finally:
file_object.close
file_input.close
They are meant to be called as functions, you need to invoke them by adding parentheses at the end with arguments, but as close takes no arguments, there will be nothing inside the parentheses. Putting everything together, the complete corrected code for your program should look like this
file_object = open("lines.txt", 'r')
count = 1
file_input = open("numbered_lines.txt", 'w')
for line in file_object:
print(count, line, file=file_input)
count += 1
file_object.close()
file_input.close()
Run the program. You will notice that there is an extra empty line between every line of text. This is because by default the print function adds a new line end character; the line you got from the file included a new-line character at the end (that's what make them lines, right?) so we don't have to add our own here. You can of course change it to an empty string. That line will look like this.
print(count, line, file=file_input, end='')
Naturally, other Python programmers will tell you that there are Pythonic ways, but you are just starting out, don't worry too much about them (although you can definitely pick up on this later and I highly encourage you to!)
The right way to open a file is using a with statement:
with open("lines.txt",'r') as file_object:
... # do something
That way, the context manager introduced by with will close your file at the end of "something " or in case of exception.
Of course, you can close the file yourself if you are not familiar with that. Not that close is a method: to call it you need parenthesis:
file_object.close()
See the chapter 7.2. Reading and Writing Files, in the official documentation.
In the first loop you're printing the contents of the input file. This means that the file contents have already been consumed when you get to the second loop. (Plus the assignment didn't ask you to print the file contents.)
In the second loop you're using print() instead of writing to a file. Try file_input.write(str(count) + " " + Line) (And file_input seems like a bad name for a file that you will be writing to.)
count=+1 sets count to +1, i.e. positive one. I think you meant count += 1 instead.
At the end of the program you're calling .close instead of .close(). The parentheses are important!

Delete a line in multiple text files with the same line beginning but varying line ending using Python v3.5

I have a folder full of .GPS files, e.g. 1.GPS, 2.GPS, etc...
Within each file is the following five lines:
Trace #1 at position 0.004610
$GNGSA,A,3,02,06,12,19,24,25,,,,,,,2.2,1.0,2.0*21
$GNGSA,A,3,75,86,87,,,,,,,,,,2.2,1.0,2.0*2C
$GNVTG,39.0304,T,39.0304,M,0.029,N,0.054,K,D*32
$GNGGA,233701.00,3731.1972590,S,14544.3073733,E,4,09,1.0,514.675,M,,,0.49,3023*27
...followed by the same data structure, with different values, over the next five lines:
Trace #6 at position 0.249839
$GNGSA,A,3,02,06,12,19,24,25,,,,,,,2.2,1.0,2.0*21
$GNGSA,A,3,75,86,87,,,,,,,,,,2.2,1.0,2.0*2C
$GNVTG,247.2375,T,247.2375,M,0.081,N,0.149,K,D*3D
$GNGGA,233706.00,3731.1971997,S,14544.3075178,E,4,09,1.0,514.689,M,,,0.71,3023*2F
(I realise the values after the $GNGSA lines don't vary in the above example. This is just a bad example... in the real dataset they do vary!)
I need to remove the lines that begin with "$GNGSA" and "$GNVTG" (i.e. I need to delete lines 2, 3, and 4 from each group of five lines within each .GPS file).
This five-line pattern continues for a varying number of times throughout each file (for some files, there might only be two five-line groups, while other files might have hundreds of the five-line groups). Hence, deleting these lines based on the line number will not work (because the line number would be variable).
The problem I am having (as seen in the above examples) is that the text that follows the "$GNGSA" or "$GNVTG" varies.
I'm currently learning Python (I'm using v3.5), so figured this would make for a good project for me to learn a few new tricks...
What I've tried already:
So far, I've managed to create the code to loop through the entire folder:
import os
indir = '/Users/dhunter/GRID01/' # input directory
for i in os.listdir(indir): # for each "i" (iteration) within the indir variable directory...
if i.endswith('.GPS'): # if the filename of an iteration ends with .GPS, then...
print(i + ' loaded') # print the filename to CLI, simply for debugging purposes.
with open(indir + i, 'r') as my_file: # open the iteration file
file_lines = my_file.readlines() # uses the readlines method to create a list of all lines in the file.
print(file_lines) # this prints the entire contents of each file to CLI for debugging purposes.
Everything in the above works perfectly.
What I need help with:
How do I detect and delete the lines themselves, and then save the file (to the same location; there is no need to save to a different filename)?
The filenames - which usually end with ".GPS" - sometimes end with ".gps" instead (the only difference being the case). My above code will only work with the uppercase files. Besides completely duplicating the code and changing the endswith argument, how do I make it work with both cases?
In the end, my file needs to look something like this:
Trace #1 at position 0.004610
$GNGGA,233701.00,3731.1972590,S,14544.3073733,E,4,09,1.0,514.675,M,,,0.49,3023*27
Trace #6 at position 0.249839
$GNGGA,233706.00,3731.1971997,S,14544.3075178,E,4,09,1.0,514.689,M,,,0.71,3023*2F
Any suggestions, please? Thanks in advance. :)
You're almost there.
import os
indir = '/Users/dhunter/GRID01/' # input directory
for i in os.listdir(indir): # for each "i" (iteration) within the indir variable directory...
if i.endswith('.GPS'): # if the filename of an iteration ends with .GPS, then...
print(i + ' loaded') # print the filename to CLI, simply for debugging purposes.
with open(indir + i, 'r') as my_file: # open the iteration file
for line in my_file:
if not line.startswith('$GNGSA') and not line.startswith('$GNVTG'):
print(line)
As per what the others have said, you're on the right track! Where you're going wrong is in the case-sensitive file extension check, and in reading in the entire file contents at once (this isn't per se wrong, but it's probably adding complexity we won't need).
I've commented your code, removing all the debug stuff for simplicity, to illustrate what I mean:
import os
indir = '/path/to/files'
for i in os.listdir(indir):
if i.endswith('.GPS'): #This CASE SENSITIVELY checks the file extension
with open(indir + i, 'r') as my_file: # Opens the file
file_lines = my_file.readlines() # This reads the ENTIRE file at once into an array of lines
So we need to fix the case sensitivity issue, and instead of reading in all the lines, we'll instead read the file line-by-line, check each line to see if we want to discard it or not, and write the lines we're interested in into an output file.
So, incorporating #tdelaney's case-insensitive fix for file name, we replace line #5 with
if i.lower().endswith('.gps'): # Case-insensitively check the file name
and instead of reading in the entire file at once, we'll instead iterate over the file stream and print each desired line out
with open(indir + i) as in_file, open(indir + i + 'new.gps') as out_file: # Open the input file for reading and creates + opens a new output file for writing - thanks #tdelaney once again!
for line in in_file # This reads each line one-by-one from the in file
if not line.startswith('$GNGSA') and not line.startswith('$GNVTG'): # Check the line has what we want (thanks Avinash)
out_file.write(line + "\n") # Write the line to the new output file
Note that you should make certain that you open the output file OUTSIDE of the 'for line in in_file' loop, or else the file will be overwritten on every iteration which will erase what you've already written to it so far (I suspect this is the issue you've had with the previous answers). Open both files at the same time and you can't go wrong.
Alternatively, you can specify the file access mode when you open the file, as per
with open(indir + i + 'new.gps', 'a'):
which will open the file in append-mode, which is a specialised from of write-mode that preserves the original contents of the file, and appends new data to it instead of overwriting existing data.
Ok, based on suggestions by Avinash Raj, tdelaney, and Sampson Oliver, here on Stack Overflow, and another friend who helped privately, here is the solution that is now working:
import os
indir = '/Users/dhunter/GRID01/' # input directory
for i in os.listdir(indir): # for each "i" (iteration) within the indir variable directory...
if i.lower().endswith('.gps'): # if the filename of an iteration ends with .GPS, then...
if not i.lower().endswith('.gpsnew.gps'): # if the filename does not end with .gpsnew.gps, then...
print(i + ' loaded') # print the filename to CLI.
with open (indir + i, 'r') as my_file:
for line in my_file:
if not line.startswith('$GNGSA'):
if not line.startswith('$GNVTG'):
with open(indir + i + 'new.gps', 'a') as outputfile:
outputfile.write(line)
outputfile.write('\r\n')
(You'll see I had to add in another layer of if statement to stop it from using the output files from previous uses of the script "if not i.lower().endswith('.gpsnew.gps'):", but this line can easily be deleted for anyone who uses these instructions in future)
We switched the open mode on the third-last line to "a" for append, so that it would save all the right lines to the file, rather than overwriting each time.
We also added in the final line to add a line break at the end of each line.
Thanks everyone for their help, explanations, and suggestions. Hopefully this solution will be useful to someone in future. :)
2. The filenames:
The if accepts any expression returning a truth value, and you can combine expressions with the standart boolean operators: if i.endswith('.GPS') or i.endswith('.gps').
You can also put the ... and ... expression after the if in brackets, to feel more sure, but it's not neccessary.
Alternatively, as a less universal solution, (but since you wanted to learn a few tricks :)) you can use string manipulation in this case: an object of type string has a lot of methods. '.gps'.upper() gives '.GPS' -- try, if you can make use of this! (even a printed string is a string object, but your variables behave the same).
1. Finding the Lines:
As you can see in the other solution, you need not read out all of your lines, you can check if want to have them 'on the fly'. But I will stick to your approach with readlines. It gives you a list, and lists support indexing and slicing. Try:
anylist[stratindex, endindex, stride], for any values, so for example try: newlist = range(100)[1::5].
It's always helpfull to try out the easy basic operations in interactive mode, or at the beginning of your script. Here range(100) is just some sample list. Here you see, how the python for-syntax works, differently than in other languages: you can iterate over any list, and if you just need integers, you create a list with integers with range().
So this will work the same with any other list -- e.g. the one you get from readlines()
This selects a slice from the list, beginnig with the second element, ending at the end (since the end index is omitted), and taking every 5th element. Now you have this sub-list, you can just revome it from the original. So for the example with the range:
a = range(100)
del(a[1::5])
print a
So you see, that the appropriate items have been removed. Now do the same with your file_lines, and then proceed to remove the other lines you want to remove.
Then, in a new with block, open the file for writing and do writelines(file_lines), so the remainig lines are written back to the file.
Of course you can also take the approach to look for the content of each line with a for loop over your list and startswith(). Or you can combine the approaches, and check, if deleting lines by number leaves the right starts, so you can print an error if something is unexpected...
3. Saving the file
You can close your file after you have the lines saved in the readlines(). In fact this is done automatically at the end of the with-block. Then just open it in 'w' mode instead of 'r' and do yourfilename.writelines(yourlist). You don't need to save, it's saven on closing.

Python: How to write a list of strings on separate lines but without a blank line

EDIT: See bottom of post for the entire code
I am new to this forum and I have an issue that I would be grateful for any help solving.
Situation and goal:
- I have a list of strings. Each string is one word, like this: ['WORD', 'LINKS', 'QUOTE' ...] and so on.
- I would like to write this list of words (strings) on separate lines in a new text file.
- One would think the way to do this would be by appending the '\n' to every item in the list, but when I do that, I get a blank line between every list item. WHY?
Please have a look at this simple function:
def write_new_file(input_list):
with open('TEKST\\TEKST_ny.txt', mode='wt') as output_file:
for linje in input_list:
output_file.write(linje + '\n')
This produces a file that looks like this:
WORD
LINKS
QUOTE
If I remove the '\n', then the file looks like this:
WORDLINKSQUOTE
Instead, the file should look like this:
WORD
LINKS
QUOTE
I am obviously doing something wrong, but after a lot of experimenting and reading around the web, I can't seem to get it right.
Any help would be deeply appreciated, thank you!
Response to link to thread about write() vs. writelines():
Writelines() doesn't fix this by itself, it produces the same result as write() without the '\n'. Unless I add a newline to every list item before passing it to the writelines(). But then we're back at the first option and the blank lines...
I tried to use one of the answers in the linked thread, using '\n'.join() and then write(), but I still get the blank lines.
It comes down to this: For some reason, I get two newlines for every '\n', no matter how I use it. I am .strip()'ing the list items of newline characters to be sure, and without the nl everything is just one massive block of texts anyway.
On using another editor: I tried open the txt-file in windows notepad and in notepad++. Any reason why these programs wouldn't display it correctly?
EDIT: This is the entire code. Sorry for the Norwegian naming. The purpose of the program is to read and clean up a text file and return the words first as a list and ultimately as a new file with each word on a new line. The text file is a list of Scrabble-words, so it's rather big (9 mb or something). PS: I don't advocate Scrabble-cheating, this is just a programming exercise :)
def renskriv(opprinnelig_ord):
nytt_ord = ''
for bokstav in opprinnelig_ord:
if bokstav.isupper() == True:
nytt_ord = nytt_ord + bokstav
return nytt_ord
def skriv_ny_fil(ny_liste):
with open('NSF\\NSF_ny.txt', 'w') as f:
for linje in ny_liste:
f.write(linje + '\n')
def behandle_kildefil():
innfil = open('NSF\\NSF_full.txt', 'r')
f = innfil.read()
kildeliste = f.split()
ny_liste = []
for item in kildeliste:
nytt_ord = renskriv(item)
nytt_ord = nytt_ord.strip('\n')
ny_liste.append(nytt_ord)
skriv_ny_fil(ny_liste)
innfil.close()
def main():
behandle_kildefil()
if __name__ == '__main__':
main()
I think there must be some '\n' among your lines, try to skip empty lines.
I suggest you this code.
def write_new_file(input_list):
with open('TEKST\\TEKST_ny.txt', 'w') as output_file:
for linje in input_list:
if not linje.startswith('\n'):
output_file.write(linje.strip() + '\n')
You've said in the comments that python is writing two carriage return ('\r') characters for each line feed ('\n') character you write. It's a bit bizaare that python is replacing each line feed with two carriage returns, but this is a feature of opening a file in text mode (normally the translation would be to something more useful). If instead you open your file in binary mode then this translation will not be done and the file should display as you wish in Notepad++. NB. Using binary mode may cause problems if you need characters outside the ASCII range -- ASCII is basically just latin letters (no accents), digits and a few symbols.
For python 2 try:
filename = "somefile.txt"
with open(filename, mode="wb") as outfile:
outfile.write("first line")
outfile.write("\n")
outfile.write("second line")
Python 3 will be a bit more tricky. For each string literal you wish you write you must prepend it with a b (for binary). For each string you don't have immediate access to, or don't wish to change to a binary string, then you must encode it using the encode() method on the string. eg.
filename = "somefile.txt"
with open(filename, mode="wb") as outfile:
outfile.write(b"first line")
outfile.write(b"\n")
some_text = "second line"
outfile.write(some_text.encode())

How to append new data onto a new line

My code looks like this:
def storescores():
hs = open("hst.txt","a")
hs.write(name)
hs.close()
so if I run it and enter "Ryan"
then run it again and enter "Bob"
the file hst.txt looks like
RyanBob
instead of
Ryan
Bob
How do I fix this?
If you want a newline, you have to write one explicitly. The usual way is like this:
hs.write(name + "\n")
This uses a backslash escape, \n, which Python converts to a newline character in string literals. It just concatenates your string, name, and that newline character into a bigger string, which gets written to the file.
It's also possible to use a multi-line string literal instead, which looks like this:
"""
"""
Or, you may want to use string formatting instead of concatenation:
hs.write("{}\n".format(name))
All of this is explained in the Input and Output chapter in the tutorial.
In Python >= 3.6 you can use new string literal feature:
with open('hst.txt', 'a') as fd:
fd.write(f'\n{name}')
Please notice using 'with statment' will automatically close the file when 'fd' runs out of scope
All answers seem to work fine. If you need to do this many times, be aware that writing
hs.write(name + "\n")
constructs a new string in memory and appends that to the file.
More efficient would be
hs.write(name)
hs.write("\n")
which does not create a new string, just appends to the file.
The answer is not to add a newline after writing your string. That may solve a different problem. What you are asking is how to add a newline before you start appending your string. If you want to add a newline, but only if one does not already exist, you need to find out first, by reading the file.
For example,
with open('hst.txt') as fobj:
text = fobj.read()
name = 'Bob'
with open('hst.txt', 'a') as fobj:
if not text.endswith('\n'):
fobj.write('\n')
fobj.write(name)
You might want to add the newline after name, or you may not, but in any case, it isn't the answer to your question.
I had the same issue. And I was able to solve it by using a formatter.
file_name = "abc.txt"
new_string = "I am a new string."
opened_file = open(file_name, 'a')
opened_file.write("%r\n" %new_string)
opened_file.close()
I hope this helps.
There is also one fact that you have to consider.
You should first check if your file is empty before adding anything to it. Because if your file is empty then I don't think you would like to add a blank new line in the beginning of the file. This code
first checks if the file is empty
If the file is empty then it will simply add your input text to the file else it will add a new line and then it will add your text to the file. You should use a try catch for os.path.getsize() to catch any exceptions.
Code:
import os
def storescores():
hs = open("hst.txt","a")
if(os.path.getsize("hst.txt") > 0):
hs.write("\n"+name)
else:
hs.write(name)
hs.close()
I presume that all you are wanting is simple string concatenation:
def storescores():
hs = open("hst.txt","a")
hs.write(name + " ")
hs.close()
Alternatively, change the " " to "\n" for a newline.
import subprocess
subprocess.check_output('echo "' + YOURTEXT + '" >> hello.txt',shell=True)
f=open("Python_Programs/files_forhndling.txt","a+")
inpt=str(input("Enter anything:\n>>"))
f.write(inpt)
f.write("\n")
print("Data inserted Successfully")
f.close()
welcome to file handling
new line
file handling in python
123456
78875454
✔ Output 💡 CLICK BELOW & SEE ✔
You need to change parameter "a" => "a+".
Follow this code bellows:
def storescores():
hs = open("hst.txt","a+")

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

I'm trying to write an array (list?) to a text file using Python 3. Currently I have:
def save_to_file(*text):
with open('/path/to/filename.txt', mode='wt', encoding='utf-8') as myfile:
for lines in text:
print(lines, file = myfile)
myfile.close
This writes what looks like the array straight to the text file, i.e.,
['element1', 'element2', 'element3']
username#machine:/path$
What I'm looking to do is create the file with
element1
element2
element3
username#machine:/path$
I've tried different ways to loop through and append a "\n" but it seems that the write is dumping the array in one operation. The question is similar to How to write list of strings to file, adding newlines? but the syntax looked like it was for Python 2? When I tried a modified version of it:
def save_to_file(*text):
myfile = open('/path/to/filename.txt', mode='wt', encoding='utf-8')
for lines in text:
myfile.write(lines)
myfile.close
...the Python shell gives "TypeError: must be str, not list" which I think is because of changes between Python2 and Python 3. What am I missing to get each element on a newline?
EDIT: Thank you to #agf and #arafangion; combining what both of you wrote, I came up with:
def save_to_file(text):
with open('/path/to/filename.txt', mode='wt', encoding='utf-8') as myfile:
myfile.write('\n'.join(text))
myfile.write('\n')
It looks like I had part of the issue with "*text" (I had read that expands arguments but it didn't click until you wrote that [element] was becoming [[element]] that I was getting a str-not-list type error; I kept thinking I needed to tell the definition that it was getting a list/array passed to it and that just stating "test" would be a string.) It worked once I changed it to just text and used myfile.write with join, and the additional \n puts in the final newline at the end of the file.
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.
There are numerous mistakes there.
Your indentation is messed up.
The 'text' attribute in save_to_file refers to ALL the arguments, not just the specific argument.
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).

Categories