how do you write integers to an external file in python - python

i am trying to create a leaderboard for a game and need to decide if a players score is there high score or not but every time i try to run the program it says " '>' not supported between instances of 'int' and 'str'" what do i do
heres my code:
score = 0
s = open("highscore.txt", 'r')
scores = s.read()
s.close()
if score > (scores):
highscore = score
s = open("highscore.txt", 'w')
s.write(highscore)
s = open("highscore.txt", 'r')
scores = s.read()
s.close()
print(f"your score was {score}")

When you use a read() method it returns a string. That means value in "scores" is a string and you cannot compare a String with an integer. Hence you need to typecast it.
if score > int(scores):
highscore = score

You will need to convert to a string and back again.
For example, here is how you could write the number to a file. By calling str(highscore) it converts it to the equivalent string (e.g. '0'). This can then be written to the file.
with open("highscore.txt", 'w') as s:
s.write(str(highscore))
You can optionally also add a newline if you use s.write(str(highscore) + '\n'), but it will work without it.
Here is how you would read the whole contents of the file - i.e. the string that you wrote - and convert it to an integer using int(). This relies on the fact that the file only contains the number and nothing else.
with open("highscore.txt") as s:
highscore = int(s.read())
Note also the pattern for reading and writing files using with. It is probably best to learn this as-is for now, but note that you do not need a close statement when doing it this way.

Related

Saving Highscore in textfile for a game

I created a small game. I would like to save the 3 highest scores in a textfile and display them after the game. I created a textfile with following content: 0 0 0 (should represent the status before you play game for first time). I created 2 functions update_highscores() and display_highscores(), but nothing happens after finishing the game. the achieved scores are not stored in the text file and the highscores were not displayed after the game. How can i save and show the highscores?
def update_highscores():
global score, scores
file = "C:\Programmieren\Eigene Spiele\Catch The Bananas\highscores.txt"
scores=[]
with open(filename, "r") as file:
line = file.readline()
high_scores = line.split()
for high_score in high_scores:
if (score > int(high_score)):
scores.append(str(score) + " ")
score = int(high_score)
else:
scores.append(str(high_score) + " ")
with open (filename, "w") as file:
for high_score in scores:
file.write(high_score)
def display_highscores():
screen.draw.text("HIGHSCORES", (350,150), fontsize=40, color = "black")
y = 200
position = 1
for high_score in scores:
screen.draw.text(str(position) + ". " + high_score, (350, y), color = "black")
y = y + 25
position = position + 1
The update_highscores code should work fine if you change
file = "C:\Programmieren\Eigene Spiele\Catch The Bananas\highscores.txt"
to
filename = r"C:\Programmieren\Eigene Spiele\Catch The Bananas\highscores.txt"
The two things that changed were: changing file to filename, otherwise this code throws an exception because filename is not defined. I assume it's meant to be this way. The second thing I changed is adding an r before the string so that the backslashes are interpreted literally. Two other options that would also work are:
"C:\\Programmieren\\Eigene Spiele\\Catch The Bananas\\highscores.txt"
or
"C:/Programmieren/Eigene Spiele/Catch The Bananas/highscores.txt"
Just remember that a single backslash in a non-raw string will usually try to escape the next character.
Aside from that, just make sure that the file exists, and that it contains 0 0 0, or any sequence of characters separated by spaces. If the file is not initialized properly, there won't be any scores to replace.
This code works for me, so if there's still a problem, it's just with displaying the scores. They update in the file just fine. But I don't know what library you're using for screen, so I can't test that.
Oh, also: make sure you're actually calling the function. I assume it's elsewhere in your code and you just omitted it. Obviously, your code won't work if you don't call the function.
Here is my code that works. Just replace the path to highscores.txt and run this code by itself. If it works, the problem is somewhere else in your code, and we won't be able to help you unless you give us more of your code.
score = int(input("Enter new score: "))
scores = []
def update_highscores():
global score, scores
filename = r"path\to\highscores.txt"
scores=[]
with open(filename, "r") as file:
line = file.readline()
high_scores = line.split()
for high_score in high_scores:
if (score > int(high_score)):
scores.append(str(score) + " ")
score = int(high_score)
else:
scores.append(str(high_score) + " ")
with open (filename, "w") as file:
for high_score in scores:
print(high_score)
file.write(high_score)
update_highscores()
input()

Prevent closing file in Python

I have a problem reading characters from a file. I have a file called fst.fasta and I want to know the number of occurrences of the letters A and T.
This is the first code sample :
f = open("fst.fasta","r")
a = f.read().count("A")
t = f.read().count("T")
print "nbr de A : ", a
print "nbr de T : ", t
The result:
nbr of A : 255
nbr of T : 0
Even if there are Ts i get always 0
But after that, I tried this :
f = open("fst.fasta","r")
a = f.read().count("A")
f = open("fst.fasta","r")
t = f.read().count("T")
print "nbr de A : ", a
print "nbr de T : ", t
This worked! Is there any other way to avoid repeating f = open("fst.fasta","r") ?
You're dealing with the fact that read() has a side effect (to use the term really loosely): it reads through the file and as it does so sets a pointer to where it is in that file. When it returns you can expect that pointer to be set to the last position. Therefore, executing read() again starts from that position and doesn't give you anything back. This is what you want:
f = open("fst.fasta","r")
contents = f.read()
a = contents.count("A")
t = contents.count("T")
The documentation also indicates other ways you can use read:
next_value = f.read(1)
if next_value == "":
# We have reached the end of the file
What has happened in the code above is that, instead of getting all the characters in the file, the file handler has only returned 1 character. You could replace 1 with any number, or even a variable to get a certain chunk of the file. The file handler remembers where the above-mentioned pointer is, and you can pick up where you left off. (Note that this is a really good idea for very large files, where reading it all into memory is prohibitive.)
Only once you call f.close() does the file handler 'forget' where it is - but it also forgets the file, and you'd have to open() it again to start from the beginning.
There are other functions provided (such as seek() and readline()) that will let you move around a file using different semantics. f.tell() will tell you where the pointer is in the file currently.
Each time you call f.read(), it consumes the entire remaining contents of the file and returns it. You then use that data only to count the as, and then attempt to read the data thats already been used. There are two solutions"
Option 1: Use f.seek(0)
a = f.read().count("A")
f.seek(0)
t = f.read().count("T")
The f.seek call sets the psoition of the file back to the beginning.
Option 2. Store the result of f.read():
data = f.read()
a = data.count("A")
t = data.count("T")
f.seek(0) before the second f.read() will reset the file pointer to the beginning of the file. Or more sanely, save the result of f.read() to a variable, and you can then call .count on that variable to your heart's content without rereading the file pointlessly.
Try the with construct:
with open("fst.fasta","r") as f:
file_as_string = f.read()
a = file_as_string.count("A")
t = file_as_string.count("T")
This keeps the file open until you exit the block.
Read it into a string:
f = open ("fst.fasta")
allLines = f.readlines()
f.close()
# At this point, you are no longer using the file handler.
for line in allLines:
print (line.count("A"), " ", line.count("T"))

Deleting and inserting a score into a text file form python

I have created a text based game in python 3.3 were users pick a class for their character. I want the game to store three scores so an average can be taken. My problem is that i am unsure how to get the program to search for a name in the file and delete there oldest score, This is what the file where the scores are saved looks like:
Bennie
33
62
94
Josh
82
55
31
Jackie
10
4
3
My current code that sees if they have done the game before and if not writes there score to the file if they have i have got the code to split the lines and read them. It needs to delete the score closet to their name and insert and new score just before the next name but i am unsure how to do this. This is my current code
class_choice = input('Enter Class one, Class two or Class three.')
if class_choice == "One":
text_file = 'class1.txt'
elif class_choice == "Two":
text_file = 'class2.txt'
elif class_choice == "Three":
text_file = 'class3.txt'
else:
False
first_time = input('Is this the first you have completed this game: Yes or No?')
if first_time == 'Yes':
with open(text_file, "a") as file:
file.write("{}\n".format(name))
file.write("0\n")
file.write("0\n")
file.write("{}\n".format(score))
sys.exit()
else:
file = open(text_file, 'r')
lines = file.read().splitlines()
giving a sample python method to add a score to the file (pseudo-code) modify as needed to suit your needs (your requirement is not the most efficient method):
def add_score(user, score, text_file):
lines = text_file.splitlines()
count = len(lines)
user_exists = False
user_index = -1
num_scores = 3
user_num_scores = 0
for i in range(count-1):
line = lines[i]
if user == line:
# user previous scores start after here
user_exists = True
user_index = i
break
if not user_exists:
# user does not exist, create by appending
lines.append(user)
lines.append(str(score))
else: # user exists, fix the scores
j=1
while j <= num_scores:
line = lines[user_index+j]
j += 1
if line.isdigit():
# user score line
user_num_scores +=1
if user_num_scores == num_scores:
for i in range(1,num_scores-1): lines[user_index+i] = lines[user_index+i+1] # shift up
lines[user_index+num_scores] = str(score) # add the latest score
else: # just append/insert the score, as the previous scores are less than num_scores
lines.insert(user_index+user_num_scores, str(score))
return "\n".join(lines) # return the new text_file back
use like this:
text = file.read()
updated_text = add_score('UserName', 32, text)
Note the function given will not change the file it will just operate on the given file contents (as text_file argument). This is on purpose since if the function itself manipulated the files it would limit its use, since one can read or write the file in any convenient instant for the whole application. So this function only operates on strings. This is not the most efficient method, for example one can use a file per user and a much simpler format, but since this what is asked for this answer covers only that.
When you have finished adding scores and manipulating the files, you can update the file by writing the updated_text back to it. (Probably if the file is already opened in read mode, you will have to close it and re-open it in write mode).
To write (update) the file with the new contents use sth like this:
file.write(updated_text)
for example see here for python file I/O operations
It is not possible to change a single line inside a file. You can only append content at the end of the file or override the entire content.
If you wat to store the scores on a file, you need to read the file line by line storing each line in an auxiliar variable (concatenating lines) and when you reach the line you need to modify, concatenate the modified line into the auxiliar variable. Then keep reading the file line by line and storing it into the auxiliar variable.
When done, write down the content of the auxiliar variable in the file.
Why dont you try creating an .ini file and store your data in the attributes under sections. It's framework suits your requirements. It kind-of works like an xml file, but since your input and output parameters are limited (as you mentioned; 3 scores), it seems like the best option to opt for. Simply go through ini file manipulation using python in python docs and you will know what to do. Cheers !
My problem is that i am unsure how to get the program to search for a name in the file and delete there oldest score
I would create several .txt (or .dat) files with the name "< class >_stats[.txt]" (without the spaces, obviously). From there:
class_choice = raw_input("Choose your class")
# if needing stats
f = open("%s_stats.txt" % class_choice, "r+")
lines = f.readlines()
f.close()
stats = [float(i) for i in lines] # i.e. [3, 5.5, 4]
# rest of game
# overwrite with new stats
new_stat = get_new_stat()
f = open("%s_stats.txt" % class_choice, "w")
f.write("\n".join([str(i) for i in stats]))
However, I would recommend just keeping the stats, you may want them later, and text is cheap. Instead of reading all lines, simply open the file for appending, read the last three, and append the new stat to the end when you get your new stat, i.e.
f = open("%s_stats.txt")
lines = f.readlines[-3:] # reads last 3
f.close()
# stuff
f = open("%s_stats.txt", "a")
f.write(get_new_stat())
f.close()

making lists from data in a file in python

I'm really new at python and needed help in making a list from data in a file. The list contains numbers on separate lines (by use of "\n" and this is something I don't want to change to CSV). The amount of numbers saved can be changed at any time because the way the data is saved to the file is as follows:
Program 1:
# creates a new file for writing
numbersFile = open('numbers.txt', 'w')
# determines how many times the loop will iterate
totalNumbers = input("How many numbers would you like to save in the file? ")
# loop to get numbers
count = 0
while count < totalNumbers:
number = input("Enter a number: ")
# writes number to file
numbersFile.write(str(number) + "\n")
count = count + 1
This is the second program that uses that data. This is the part that is messy and that I'm unsure of:
Program 2:
maxNumbers = input("How many numbers are in the file? ")
numFile = open('numbers.txt', 'r')
total = 0
count = 0
while count < maxNumbers:
total = total + numbers[count]
count = count + 1
I want to use the data gathered from program 1 to get a total in program 2. I wanted to put it in a list because the amount of numbers can vary. This is for an introduction to computer programming class, so I need a SIMPLE fix. Thank you to all who help.
Your first program is fine, although you should use raw_input() instead of input() (which also makes it unnecessary to call str() on the result).
Your second program has a small problem: You're not actually reading anything from the file. Fortunately, that's easy in Python. You can iterate over the lines in a file using
for line in numFile:
# line now contains the current line, including a trailing \n, if present
so you don't need to ask for the total of numbers in your file at all.
If you want to add the numbers, don't forget to convert the string line to an int first:
total += int(line) # shorthand for total = total + int(line)
There remains one problem (thanks #tobias_k!): The last line of the file will be empty, and int("") raises an error, so you could check that first:
for line in numFile:
if line:
total += int(line)

PYTHON how to search a text file for a number

There's a text file that I'm reading line by line. It looks something like this:
3
3
67
46
67
3
46
Each time the program encounters a new number, it writes it to a text file. The way I'm thinking of doing this is writing the first number to the file, then looking at the second number and checking if it's already in the output file. If it isn't, it writes THAT number to the file. If it is, it skips that line to avoid repetitions and goes on to the next line. How do I do this?
Rather than searching your output file, keep a set of the numbers you've written, and only write numbers that are not in the set.
Instead of checking output file for the number if it was already written it is better to keep this information in a variable (a set or list). It will save you on disk reads.
To search a file for numbers you need to loop through each line of that file, you can do that with for line in open('input'): loop, where input is the name of your file. On each iteration line would contain one line of input file ended with end of line character '\n'.
In each iteration you should try to convert the value on that line to a number, int() function may be used. You may want to protect yourself against empty lines or non-number values with try statement.
In each iteration having the number you should check if the value you found wasn't already written to the output file by checking a set of already written numbers. If value is not in the set yet, add it and write to the output file.
#!/usr/bin/env python
numbers = set() # create a set for storing numbers that were already written
out = open('output', 'w') # open 'output' file for writing
for line in open('input'): # loop through each line of 'input' file
try:
i = int(line) # try to convert line to integer
except ValueError: # if conversion to integer fails display a warning
print "Warning: cannot convert to number string '%s'" % line.strip()
continue # skip to next line on error
if i not in numbers: # check if the number wasn't already added to the set
out.write('%d\n' % i) # write the number to the 'output' file followed by EOL
numbers.add(i) # add number to the set to mark it as already added
This example assumes that your input file contains single numbers on each line. In case of empty on incorrect line a warning will be displayed to stdout.
You could also use list in the above example, but it may be less efficient.
Instead of numbers = set() use numbers = [] and instead of numbers.add(i): numbers.append(i). The if condition stays the same.
Don't do that. Use a set() to keep track of all the numbers you have seen. It will only have one of each.
numbers = set()
for line in open("numberfile"):
numbers.add(int(line.strip()))
open("outputfile", "w").write("\n".join(str(n) for n in numbers))
Note this reads them all, then writes them all out at once. This will put them in a different order than in the original file (assuming they're integers, they will come out in ascending numeric order). If you don't want that, you can also write them as you read them, but only if they are not already in the set:
numbers = set()
with open("outfile", "w") as outfile:
for line in open("numberfile"):
number = int(line.strip())
if number not in numbers:
outfile.write(str(number) + "\n")
numbers.add(number)
Are you working with exceptionally large files? You probably don't want to try to "search" the file you're writing to for a value you just wrote. You (probably) want something more like this:
encountered = set([])
with open('file1') as fhi, open('file2', 'w') as fho:
for line in fhi:
if line not in encountered:
encountered.add(line)
fho.write(line)
If you want to scan through a file to see if it contains a number on any line, you could do something like this:
def file_contains(f, n):
with f:
for line in f:
if int(line.strip()) == n:
return True
return False
However as Ned points out in his answer, this isn't a very efficient solution; if you have to search through the file again for each line, the running time of your program will increase proportional to the square of the number of numbers.
It the number of values is not incredibly large, it would be more efficient to use a set (documentation). Sets are designed to very efficiently keep track of unordered values. For example:
with open("input_file.txt", "rt") as in_file:
with open("output_file.txt", "wt") as out_file:
encountered_numbers = set()
for line in in_file:
n = int(line.strip())
if n not in encountered_numbers:
encountered_numbers.add(n)
out_file.write(line)

Categories