Validating file paths in Python - python

I have this code where the user has to input the name of a file which includes a message and the name of a file where the message must be written after its encrypted via Caesar-Cipher.
I would like to validate the inputs, so that if there's a wrong input, the code won't crash but ask the user for a valid file path until the user inputs it.
I have some familiarity with validation using the while loop, however I couldn't apply it here without ruining other parts of the code.
Any suggestions are appreciated.
def open_file(source_path: str, dest_path: str):
with open(source_path, mode='r') as fd:
while line := fd.readline():
return line
def write_to_file(dest_path: str, line: str):
with open(dest_path, mode='a') as fd:
fd.write(line)
source_path = input("Enter the name of the file including the message: ")
dest_path = input("Enter the name of the file where the encrypted message will be written: ")
MODE_ENCRYPT = 1
def caesar(source: str, dest: str, steps, mode):
alphabet = "abcdefghijklmnopqrstuvwxyzabcABCDEFGHIJKLMNOPQRSTUVWXYZABC"
alpha_len: int = len(alphabet)
new_data = ""
file = open_file(source_path, dest_path)
for char in file:
index = alphabet.find(char)
if index == -1:
new_data += char
else:
# compute first parth
changed = index + steps if mode == MODE_ENCRYPT else index - steps
# make an offset
changed %= alpha_len
new_data += alphabet[changed:changed + 1]
write_to_file(dest_path, new_data)
return new_data
while True:
# Validating input key
key = input("Enter the key: ")
try:
key = int(key)
except ValueError:
print("Please enter a valid key: ")
continue
break
ciphered = caesar(source_path, dest_path, key, MODE_ENCRYPT)

Not quite sure what you meant by not being able to use a while loop, but here is a simple way of checking if the paths exists using pathlib.
from pathlib import Path
while True:
source_path = Path(input("Enter the name of the file including the message: "))
if source_path.exists():
break
print("Please input a valid path")
while True:
dest_path = Path(input("Enter the name of the file where the encrypted message will be written: "))
if dest_path.exists():
break
print("Please input a valid path")

You can use inbuilt OS module in Python. Here is the code until the path is a valid path.
Note: Keeping a check for MAXIMUM RETRIES will help the code to not stuck in an infinite loop for the user.
import os
def getPath():
MAXIMUM_RETRIES = 5
count = 0
file_path = ""
while True:
count += 1
file_path = input("Enter the path: ")
if os.path.exists(file_path):
break
if count >= MAXIMUM_RETRIES:
print("You have reached maximum number or re-tries. Exiting...")
exit(1)
print("Invalid Path. Try again.")
return file_path

Related

How to open and read a file in python while it's an subfolder?

I have created a program where I have two text files: "places.txt" and "verbs.txt" and It asks the user to choose between these two files. After they've chosen it quizzes the user on the English translation from the Spanish word and returns the correct answer once the user has completed their "test". However the program runs smoothly if the text files are free in the folder for python I have created on my Mac but once I put these files and the .py file in a subfolder it says files can't be found. I want to share this .py file along with the text files but would there be a way I can fix this error?
def CreateQuiz(i):
# here i'm creating the keys and values of the "flashcards"
f = open(fileList[i],'r') # using the read function for both files
EngSpanVocab= {} # this converts the lists in the text files to dictionaries
for line in f:
#here this trims the empty lines in the text files
line = line.strip().split(':')
engWord = line[0]
spanWord = line[1].split(',')
EngSpanVocab[engWord] = spanWord
placeList = list(EngSpanVocab.keys())
while True:
num = input('How many words in your quiz? ==>')
try:
num = int(num)
if num <= 0 or num >= 10:
print('Number must be greater than zero and less than or equal to 10')
else:
correct = 0
#this takes the user input
for j in range(num):
val = random.choice(placeList)
spa = input('Enter a valid spanish phrase for '+val+'\n'+'==> ')
if spa in EngSpanVocab[val]:
correct = correct+1
if len(EngSpanVocab[val]) == 1:
#if answers are correct the program returns value
print('Correct. Good work\n')
else:
data = EngSpanVocab[val].copy()
data.remove(spa)
print('Correct. You could also have chosen',*data,'\n')
else:
print('Incorrect, right answer was',*EngSpanVocab[val])
#gives back the user answer as a percentage right out of a 100%
prob = round((correct/num)*100,2)
print('\nYou got '+str(correct)+' out of '+str(num)+', which is '+str(prob)+'%'+'\n')
break
except:
print('You must enter an integer')
def write(wrongDict, targetFile):
# Open
writeFile = open(targetFile, 'w')
# Write entry
for key in wrongDict.keys():
## Key
writeFile.write(key)
writeFile.write(':')
## Value(s)
for value in wrongDict[key]:
# If key has multiple values or user chooses more than 1 word to be quizzed on
if value == wrongDict[key][(len(wrongDict[key])) - 1]:
writeFile.write(value)
else:
writeFile.write('%s,'%value)
writeFile.write('\n')
# Close
writeFile.close()
print ('Incorrect answers written to',targetFile,'.')
def writewrong(wringDict):
#this is for the file that will be written in
string_1= input("Filename (defaults to \'wrong.txt\'):")
if string_1== ' ':
target_file='wrong.txt'
else:
target_file= string_1
# this checs if it already exists and if it does then it overwrites what was on it previously
if os.path.isfile(target)==True:
while True:
string_2=input("File already exists. Overwrite? (Yes or No):")
if string_2== ' ':
write(wrongDict, target_file)
break
else:
over_list=[]
for i in string_1:
if i.isalpha(): ovrList.append(i)
ovr = ''.join(ovrList)
ovr = ovr.lower()
if ovr.isalpha() == True:
#### Evaluate answer
if ovr[0] == 'y':
write(wrongDict, target)
break
elif ovr[0] == 'n':
break
else:
print ('Invalid input.\n')
### If not, create
else:
write(wrongDict, target)
def MainMenu():
## # this is just the standad menu when you first run the program
if len(fileList) == 0:
print('Error! No file found')
else:
print( "Vocabulary Program:\nChoose a file with the proper number or press Q to quit" )
print(str(1) ,"Places.txt")
print(str(2) ,"Verbs.txt")
while True:
#this takes the user input given and opens up the right text file depending on what the user wants
MainMenu()
userChoice = input('==> ')
if userChoice == '1':
data = open("places.txt",'r')
CreateQuiz(0)
elif userChoice == '2':
data = open("verbs.txt",'r')
CreateQuiz(1)
elif userChoice == 'Q':
break
else:
print('Choose a Valid Option!!\n')
break
You are probably not running the script from within the new folder, so it tries to load the files from the directory from where you run the script.
Try setting the directory:
import os
directory = os.path.dirname(os.path.abspath(__file__))
data = open(directory + "/places.txt",'r')

mkdir error file path does not exist in python

please guys am a beginner in python and was trying to create a simple to-do-list program, but am stuck right now at the point of making directory. I will be posting the code below all suggest to help and make it better is welcome.
#!/usr/bin/env python3
def_directory = "~/Documents/"
def fi_le():
x = int(input("Enter The Length of Your To-Do-List: "))
#this next line of codes should generate the number of list you want
xf = list(range(1, (x + 1)))
#This next liine asks for the To-do list name
import os.path
directory = def_directory
namer = input("Enter File Name: ")
file_name = namer + ".txt"
file_path = os.path.join(directory, file_name)
if not os.path.isdir(directory):
os.mkdir(directory)
f = open(file_path, "w+")
#This next line of code takes in user To-Do-List
for i in xf:
l = ("=>" + str(i) + ". ")
f.close()
def dir_check():
print("\n")
print("*NOTE: PLEASE NOTE YOUR DEFAULT DIR FOR SAVED FILE IS THE 'DOCUMENTS FOLDER'")
print("IF YOU WANT TO CHANGE DIR ENTER 'C' TO PROCEED ELSE ENTER 'D' TO USE DEFAULT FOLDER")
print("\n")
ask_user = input("Do you want to Proceed with DEFAULT FOLDER: ").upper()
if ask_user == "D":
fi_le()
elif ask_user == "C":
user_folder_name = ("~/" + input("Specify Folder Name: "))
def_directory = user_folder_name
fi_le()
else:
print("Please Enter 'D' Or 'C' to Continue")
dir_check()
dir_check()
print("\n" * 5)
print("===============> End <===============")
There are multiple issues
Indentation is important
You need to define directory variable as a full path:
For instance: in Unix system:
def_directory = "/Users/PycharmProjects/StackOverFlow-pip/"
You are actually not writing to the file. To write you need to call write function.
for i in xf:
l = ("=>" + str(i) + ". ")
f.write(l)
Full corrected Code:
def_directory = "/Users/PycharmProjects/StackOverFlow-pip/"
def fi_le():
x = int(input("Enter The Length of Your To-Do-List: "))
#this next line of codes should generate the number of list you want
xf = list(range(1, (x + 1)))
#This next liine asks for the To-do list name
import os.path
directory = def_directory
namer = input("Enter File Name: ")
file_name = namer + ".txt"
file_path = os.path.join(directory, file_name)
if not os.path.isdir(directory):
os.mkdir(directory)
f = open(file_path, "w+")
#This next line of code takes in user To-Do-List
for i in xf:
u = input("Enter the value")
f.write(("=>" + str(i) + ". " + u))
f.close()
def dir_check():
print("\n")
print("*NOTE: PLEASE NOTE YOUR DEFAULT DIR FOR SAVED FILE IS THE 'DOCUMENTS FOLDER'")
print("IF YOU WANT TO CHANGE DIR ENTER 'C' TO PROCEED ELSE ENTER 'D' TO USE DEFAULT FOLDER")
print("\n")
ask_user = input("Do you want to Proceed with DEFAULT FOLDER: ").upper()
if ask_user == "D":
fi_le()
elif ask_user == "C":
user_folder_name = ("~/" + input("Specify Folder Name: "))
def_directory = user_folder_name
fi_le()
else:
print("Please Enter 'D' Or 'C' to Continue")
dir_check()
dir_check()
print("\n" * 5)
print("===============> End <===============")
Output:
=>1. Eat Hamburger=>2. Eat Cheeseburger
Possible issue is that the intermediate directory does not exist. If that is the case, use os.makedirs instead of os.mkdir.
See documentation here: https://docs.python.org/3/library/os.html#os.makedirs
Additionally of Ahmet, you should not do this kind of check before creating a directory on the file system:
if not os.path.isdir(directory):
os.mkdir(directory)
instead, you should try to create it directly, and manage the exception:
try:
os.mkdirs(directory)
except FileExistsError:
# do something

Python outputting contents from file

When I'm running the program it is outputting that no countries exist starting with that letter, when in fact they exist. Can someone tell me what I'm doing wrong or maybe give me an alternate way to only output countries starting with the wanted letter. This is my code:
#Creating the list
CountryList = []
CountryandPopulationList = []
#Creating the Function1
def Function1(fh,letter):
count = 0
#Adding the file to the list
for word in fh:
CountryandPopulationList.append(word)
index = word.find('-')
Country = word[0:index]
CountryList.append(Country.strip())
#Printing countries starting with chosen letter
try:
for i in CountryList:
if(i[1]== letter):
print(i)
count = count + 1
else:
print('The letter does not exist')
except IndexError:
print('Total number of countries starting with letter',letter,'=',count )
#Asking user to input letter
letter = input('Enter the first letter of the country: ')
#Opening the file
try:
fh = open('D:\FOS\\Countries.txt','r')
except IOError:
print('File does not exist')
else:
function1 = Function1(fh,letter)
Thank you
Please also provide the input format of your Countries.txt file as well as the python version you are using s.t. it is easier to help you.
For a start: open() will not provide you with the file content but only gives you the textwrapper object. Try changing the line to
fh = open('D:\FOS\...\Countries.txt', 'r').read()
A slightly simpler version. Try this:
def function1(fh, letter):
count = 0
country_list = [line.split('-')[0].strip() for line in fh.readlines()]
for country in country_list:
if country.lower().startswith(letter.lower()):
count += 1
print(country)
print("Total number of countries starting with letter '%s'= %d" % (letter, count))
#Asking user to input letter
letter = input('Enter the first letter of the country: ')
#Opening the file
try:
with open('D:\FOS\\Countries.txt','r') as fh:
function1(fh, letter)
except IOError:
print('File does not exist')

Appending to a file, then reading from it into a list, then re-appending to it and overwriting certain parts

I want to be able to have a program whereby the user can input a paragraph/sentence/word/character whatever and have that stored in a list e.g. in list[0]. Then I want them to be able to write another bit of text and have that stored in e.g. list[1]. Then at any time I want the user to be able to read that from the list by choosing which segment they want to read from e.g. reading "hello" from list[0] whilst in list[1] "hi" is stored. Then when the user exits the program I want the list to be written to an external file. Then, at next start up, the program should read the file contents and store it again in the list so that the user can add more bits of text or read the current bits. When the list is saved to a file it should append new or changed parts but overwrite parts that are the same so as not to have duplicates. I have attempted this without much success. I am to be honest not sure if it is possible. I have browsed similar forums and have found that hasn't helped much so here it is.
My code so far:
import os
import time
import csv
global write_list
global f1_contents
write_list = []
def write():
os.system("cls")
user_story = input("Enter your text: \n")
write_list.append(user_story)
def read():
os.system("cls")
user_select_needs = True
while user_select_needs == True:
user_select = input("Enter the list section to read from or type exit: \n")
if user_select == "exit":
user_select_needs = False
try:
int(user_select)
select = user_select
select = int(select)
try:
print(write_list[select])
user_select_needs = False
enter = input("Press enter:")
except:
print("There is not stored data on that section!")
except ValueError:
print("That is not a valid section!")
def exit():
os.system("cls")
max_num_needs = True
while max_num_needs == True:
set_max_num = input("Set the storage: \n")
try:
int(set_max_num)
max_num = set_max_num
max_num = int(max_num)
max_num_needs = False
except:
print("It must be an integer!")
for i in range(0, max_num):
f = open("Saves.txt", "a")
f.write(write_list[i])
f.close()
os._exit(1)
def main():
store_num_needs = True
while store_num_needs == True:
set_store_num = input("State the current storage amount: \n")
try:
int(set_store_num)
store_num = set_store_num
store_num = int(store_num)
store_num_needs = False
except:
print("It must be an integer!")
try:
f1 = open("Saves.txt", "r")
for i in range(0, store_num+1):
i, = f1.split("#")
f1.close()
except:
print("--------Loading-------")
time.sleep(1)
while True:
os.system("cls")
user_choice = ""
print("Main Menu" + "\n" + "---------")
print("1) Write")
print("2) Read")
print("3) Exit")
while user_choice not in ["1", "2", "3"]:
user_choice = input("Pick 1, 2 or 3 \n")
if user_choice == "1":
write()
elif user_choice == "2":
read()
else:
exit()
if __name__ == "__main__":
main()
It might be too complicated to understand in which case just ask me in comments- otherwise general tips would be nice aswell.
Thanks in advance
A quick point of correction:
global is only required if you're defining a global variable inside a non-global context. In other words, anything defined at the default indentation level, will be accessible by everything else defined below it. For example:
def set_global():
x = 1
def use_global():
x += 1
set_global()
try:
use_global()
except Exception as e:
# `use_global` doesn't know
# about what `set_global` did
print("ERROR: " + str(e))
# to resolve this we can set `x` to a
# default value in a global context:
x = 1
# or, if it were required, we
# could create a global variable
def make_global():
global x
make_global()
# either will work fine
set_global()
use_global()
print(x) # prints 2
Now to the actual question:
I haven't read through the block of code you wrote (probably best to trim it down to just the relevant bits in the future), but this should solve the problem as I understand it, and you described it.
import os
import sys
user_text = []
# login the user somehow
user_file = 'saves.txt'
def writelines(f, lines):
"""Write lines to file with new line characters"""
f.writelines('\n'.join(lines))
def readlines(f):
"""Get lines from file split on new line characters"""
text = f.read()
return text.split('\n') if text else []
class _Choice(object):
"""Class that is equivalent to a set of choices
Example:
>>> class YesObj(Choice):
>>> options = ('y', 'yes')
>>> Yes = YesObj()
>>> assert Yes == 'yes'
>>> assert Yes == 'y'
>>> # assertions evaluate to True
Override the `options` attribute to make use
"""
allowed = ()
def __eq__(self, other):
try:
s = str(other)
except:
raise TypeError("Cannot compare with non-string")
else:
return s.lower() in self.allowed
def _choice_repr(choices):
allowed = []
for c in choices:
if isinstance(c, _Choice):
allowed.extend(c.allowed)
else:
allowed.append(c)
if len(allowed) > 2:
s = ', '.join([repr(c) for c in allowed[:-1]])
s += ', or %s' % repr(allowed[-1])
elif len(allowed) == 1:
s = '%s or %s' % allowed
else:
s = '%s' % allowed[0]
return s
def _choice_sentinel(name, allowed):
"""Creates a sentinel for comparing options"""
return type(name, (_Choice,), {'allowed': list(allowed)})()
Quit = _choice_sentinel('Quit', ('q', 'quit'))
Yes = _choice_sentinel('Yes', ('y', 'yes'))
No = _choice_sentinel('No', ('n', 'no'))
def readline_generator(f):
"""Generate a file's lines one at a time"""
t = f.readline()
# while the line isn't empty
while bool(t):
yield t
t = f.readline()
def read_from_cache():
"""Overwrite `user_text` with file content"""
if not os.path.isfile(user_file):
open(user_file, 'w').close()
globals()['user_text'] = []
else:
with open(user_file, 'r') as f:
lines = readlines(f)
# replace vs extend user text
for i, t in enumerate(lines):
if i == len(user_text):
user_text.extend(lines[i:])
else:
user_text[i] = t
def write_to_cache():
"""Overwrite cache after the first line disagrees with current text
If modifications have been made near the end of the file, this will
be more efficient than a blindly overwriting the cache."""
with open(user_file, 'r+') as f:
i = -1
last_pos = f.tell()
# enumerate is a generator, not complete list
for i, t in enumerate(readline_generator(f)):
if user_text[i] != t:
# rewind to the line before
# this diff was encountered
f.seek(last_pos)
# set the index back one in
# order to catch the change
i -= 1
break
last_pos = f.tell()
# then cut off remainder of file
f.truncate()
# recall that i is the index of the diff
# replace the rest of it with new
# (and potentially old) content
writelines(f, user_text[i+1:])
def blind_write_to_cache():
"""Blindly overwrite the cache with current text"""
with open(user_file, 'w') as f:
writelines(f, user_text)
def overwrite_user_text(i, text, save=False):
"""Overwrite a line of text
If `save` is True, then these changes are cached
"""
try:
user_text[i] = text
except IndexError:
raise IndexError("No text exists on line %r" % (i+1))
if save:
write_to_cache()
def user_input():
"""Get a new line from the user"""
return raw_input("input text: ")
def user_choice(msg, choices):
if len(choices) == 0:
raise ValueError("No choices were given")
ans = raw_input(msg)
if ans not in choices:
print("Invalid Response: '%s'" % ans)
m = "Respond with %s: " % _choice_repr(choices)
return user_choice(m, choices)
else:
return ans
def user_appends():
"""User adds a new line"""
user_text.append(user_input())
def user_reads(*args, **kwargs):
"""Print a set of lines for the user
Selects text via `user_text[slice(*args)]`
Use 'print_init' in kwargs to choose how
many lines are printed out before user must
scroll by pressing enter, or quit with 'q'."""
print_init = kwargs.get('print_init', 4)
sliced = user_text[slice(*args)]
if not isinstance(sliced, list):
sliced = [sliced]
for i, l in enumerate(sliced):
if i < print_init:
print(l)
sys.stdout.flush()
elif user_choice(l, ['', Quit]) == Quit:
break
def user_changes(i=None, save=False):
"""User changes a preexisting line"""
attempt = True
while i is None and attempt:
# get the line the user wants to change
i_text = raw_input("Line to be changed: ")
try:
# make user input an index
i = int(i_text)
except:
# check if they want to try again
c = user_choice("Bad input - '%s' is not an "
"integer. Try again? " % i_text, (Yes, No))
attempt = (c == Yes)
if attempt:
# user gave a valid integer for indexing
try:
user_reads(i-1)
overwrite_user_text(i-1, user_input(), save)
except Exception as e:
print("ERROR: %s" % e)
if user_choice("Try again? ", (Yes, No)):
user_changes(i, save)
# stores whatever text is already on
# file to `user_text` before use
read_from_cache()

python: Adding to username

I am fairly new to python and I need to make a program to ask 10 questions, save the score into a file and allow someone to read the scores in from the file.
My problem: I need to check if the person who has done the quiz already has a record in the file, and if so, I need to add their score to the end of their record.
The records should look like this:
name,score,score,score,score,
etc so they can be split using commas.
I am also looking for the simplest answer, not the most efficient. Also, if you could comment the code, it would make it much easier. Here is my code so far:
import random
import math
import operator as op
import sys
import re
def test():
num1 = random.randint(1, 10)
num2 = random.randint(1, num1)
ops = {
'+': op.add,
'-': op.sub,
'*': op.mul,
}
keys = list(ops.keys())
rand_key = random.choice(keys)
operation = ops[rand_key]
correct_result = operation(num1, num2)
print ("What is {} {} {}?".format(num1, rand_key, num2))
while True:
try:
user_answer = int(input("Your answer: "))
except ValueError:
print("Only enter numbers!")
continue
else:
break
if user_answer != correct_result:
print ("Incorrect. The right answer is {}".format(correct_result))
return False
else:
print("Correct!")
return True
print("1. Are you a student?")
print("2. Are you a teacher?")
print("3. Exit")
while True:
try:
status = int(input("Please select an option:"))
except ValueError:
print("Please enter a number!")
else:
if status not in {1,2,3}:
print("Please enter a number in {1,2,3}!")
else:
break
if status == 1:
username=input("What is your name?")
while not re.match("^[A-Za-z ]*$", username) or username=="":
username=input(str("Please enter a valid name (it must not contain numbers or symbols)."))
print ("Hi {}! Wellcome to the Arithmetic quiz...".format(username))
while True:
try:
users_class = int(input("Which class are you in? (1,2 or 3)"))
except ValueError:
print("Please enter a number!")
else:
if users_class not in {1,2,3}:
print("Please enter a number in {1,2,3}!")
else:
break
correct_answers = 0
num_questions = 10
for i in range(num_questions):
if test():
correct_answers +=1
print("{}: You got {}/{} {} correct.".format(username, correct_answers, num_questions,
'question' if (correct_answers==1) else 'questions'))
if users_class == 1:
class1 = open("Class1.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class1.write(newRecord)
class1.close()
elif users_class == 2:
class2 = open("Class2.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class2.write(newRecord)
class2.close()
elif users_class == 3:
class3 = open("Class3.txt", "a+")
newRecord = username+ "," + str(correct_answers) + "," + "\n"
class3.write(newRecord)
class3.close()
else:
print("Sorry, we can not save your data as the class you entered is not valid.")
EDIT:
Add this function before your "test" function:
def writeUserScore(file, name, score):
with open (file, "r") as myfile:
s = myfile.read()
rows = s.split("\n")
data = {}
for row in rows:
tmp = row.split(",")
if len(tmp) >= 2: data[tmp[0]] = tmp[1:]
if name not in data:
data[name] = []
data[name].append(str(score))
output = ""
for name in data:
output = output + name + "," + ",".join(data[name]) + "\n"
handle = open(file, "w+")
handle.write(output)
handle.close()
After that, where you have "if users_class == 1:" do this:
writeUserScore("Class1.txt", username, str(correct_answers))
Do the same for the other two else ifs.
Let me know what you think!
Try using a dictionary to hold the existing file data.
Read the file in a variable called "str" for example. And then do something like this:
rows = str.split("\n")
data1 = {}
for row in rows:
tmp = row.split(",")
data1[tmp[0]] = tmp[1:]
When you have a new score you should then do:
if username not in data1:
data1[username] = []
data1[username] = str(correct_answers)
And to save the data back to the file:
output = ""
for name in data1:
output = outupt + name + "," + ",".join(data1[name]) | "\n"
And save the contents of "output" to the file.
PS: If you are not bound by the file format you can use a JSON file. I can tell you more about this if you wish.
Hope that helps,
Alex
First, define these functions:
from collections import defaultdict
def read_scores(users_class):
"""
If the score file for users_class does not exist, return an empty
defaultdict(list). If the score file does exist, read it in and return
it as a defaultdict(list). The keys of the dict are the user names,
and the values are lists of ints (the scores for each user)
"""
assert 0 <= users_class <= 3
result = defaultdict(list)
try:
lines =open("Class%d.txt"%users_class,'r').readlines()
except IOError:
return result
for line in lines:
# this line requires python3
user, *scores = line.strip().split(',')
# if you need to use python2, replace the above line
# with these two lines:
# line = line.strip().split(',')
# user, scores = line[0], line[1:]
result[user] = [int(s) for s in scores]
return result
def write_scores(users_class, all_scores):
"""
Write user scores to the appropriate file.
users_class is the class number, all scores is a dict kind of dict
returned by read_scores.
"""
f = open("Class%d.txt"%users_class,'w')
for user, scores in all_scores.items():
f.write("%s,%s\n"%(user, ','.join([str(s) for s in scores])))
def update_user_score(users_class, user_name, new_score):
"""
Update the appropriate score file for users_class.
Append new_score to user_name's existing scores. If the user has
no scores, a new record is created for them.
"""
scores = read_scores(users_class)
scores[user_name].append(new_score)
write_scores(users_class, scores)
Now, in the last portion of your code (where you actually write the scores out) becomes much simpler. Here's an example of writing some scores:
update_user_score(1, 'phil', 7)
update_user_score(1, 'phil', 6)
update_user_score(1, 'alice', 6)
update_user_score(1, 'phil', 9)
there will be two lines in Class1.txt:
phil,7,6,9
alice,6
We read the whole file into a dict (actually a defaultdict(list)),
and overwrite that same file with an updated dict. By using defaultdict(list), we don't have to worry about distinguishing between updating and adding a record.
Note also that we don't need separate if/elif cases to read/write the files. "Scores%d.txt"%users_class gives us the name of the file.

Categories