I created a student class.I stored every student details in a file.I used serialization concept to store the details.The problem is while unpickling the data it gives first object only.Can anyone say how to retrieve all objects which are in .pkl file
and my code is
this is my code
'''
Created on Apr 20, 2015
#author: murali
'''
import pickle
from pip._vendor.distlib.compat import raw_input
class Student:
def __init__(self, name, roll, sex, subject, total):
"""Return a new Car object."""
self.name = name
self.roll = roll
self.sex = sex
self.subject = subject
self.total = total
print ("*************MENU*******************************")
print ("\t 1.Add New Student")
print ("\t 2.Display all Students")
print ("\t 3.Delete Student")
print ("\t 4.Display all Boys")
print ("\t 5.Display all Girls")
print ("\t 6.Display ascending order of marks")
print ("\t 7.Display alphabetical order of names ")
print ("\t 0.exit")
print ("************************************************")
print ("\n Enter your choice")
ch=int(raw_input())
if ch==1:
print ("Enter Student Details")
print ("Enter Student Name")
n=raw_input()
print ("Enter Student Roll number")
r=raw_input()
print ("Male or Female")
s=raw_input()
print ("Enter Subject ")
su=raw_input()
print ("Enter Student marks ")
t=raw_input()
s=Student(n,r,s,su,t);
with open("save2.pkl",'ab') as outfile:
pickle.dump(s,outfile)
print ("Data saved Successfully")
elif ch==2:
st=[];
f=open("save2.pkl",'rb')
storedlist=pickle.load(f)
print (storedlist)
#st.append(storedlist)
print ("Students are-")
print (storedlist)
#for i in storedlist:
print(storedlist.name)
print(storedlist.roll)
print(storedlist.sex)
print(storedlist.subject)
print(storedlist.total)
f.close();
#s1=None
#with open("save2.pkl",'rb') as infile:
#s1=pickle.load(infile)
#print (s1.name)
#print (s1.roll)
#print (s1.sex)
#print (s1.subject)
The issue you're encountering is that pickle.load only reads one item from your pkl file. That's just how its designed. If you have more than one item in the same file, you'll need to repeatedly load them until you get an EOFError when there is nothing more to read. Something like:
students = []
try:
with open("save2.pkl",'rb') as f:
while True: # loop indefinitely
students.append(pickle.load(f)) # add each item from the file to a list
except EOFError: # the exception is used to break the loop
pass # we don't need to do anything special
Alternatively, you could maintain in memory a complete list of the items your file is intended to contain (e.g. all the Student instances). When the list is modified, you'd pickle the whole list and write it all out together in one call to pickle.dump, overwriting the previous contents of the your data file. Rather than reading the data when the user requested it, you'd read it at the start of the program, and already have it in memory if the user wants it later.
This is a bit harder to show, as I don't want to rewrite large chunks of your code. I think these snippets are all you need:
Just below definition of the Student class:
try:
with open("save2.pkl",'rb') as f:
students = pickle.load(f) # just one call, loads the whole list
except FileNotFoundError: # if the file doesn't exist, make an empty list
students = []
Where you are currently appending to the file:
s=Student(n,r,s,su,t)
students.append(s) # update the in-memory list of students
with open("save2.pkl",'wb') as outfile: # use mode "w" to overwrite existing file
pickle.dump(students, outfile) # dump the whole list, not only s
print ("Data saved Successfully")
In the later code you wouldn't need to re-read the file. It can just use the students list you already have in memory.
This second approach is not terribly useful given your current menu design which can only be passed through a single time. But if you later put the menu in a loop (as the 0 option suggests you eventually will want to do), you might appreciate not needing to read the data file over and over.
This approach is also much better than the other version if you ever extend your Student type to have references to other Student instances (perhaps you're recording lab partners, or teams for some group project). If you pickle such interconnected objects separately, the links between them will not be retained when you load them again. The loaded versions will still have references, but the references will be to copies of the other Student instances, not the same ones you'll get when the other Students are loaded themselves. If you dump and load a whole list of Students at once, however, their interconnections will be maintained. (This is fairly deep stuff, don't worry too much if you don't understand what I'm talking about.)
Related
import pickle
med = {}
medfile = open("Medicines.dat","wb")
while True:
name = input("Enter the name: ")
company = input("Enter the company: ")
chemical = input("Enter the chemical: ")
price = input("Enter the price: ")
med['name'] = name
med['company'] = company
med['chemical'] = chemical
med['price'] = price
pickle.dump(med,medfile)
ans = input("Wouldyou like to add more(y/n) ")
if ans == "y":
continue
elif ans == "n":
break
medfile = open("Medicines.dat","r+")
print(pickle.load(medfile))
medfile.close()
The question is as follows:
A binary file "Medicines.dat has structure [Name, Company, Chemical, Price] a) Write a user defined function add_data() to input the data for a record and store in the file b) Write a function search() which accepts a company name and displays the details of all the Medicines by that company
There are a few problems here:
1st Opening the file correctly
medfile = open("Medicines.dat","r+")
You mean rb. The difference is explained here, but pickle parsing requires the file to be in "binary" mode, hence the "b".
2nd Closing the file correctly
You should close the file before re-opening it for writing, as a matter of best practce. (medfile.close()). Even better, python will take care of when the file gets closed if you use the "with" syntax to create a context
3rd Having the right values
While the code should now run, I doubt it will do what you want. Your query asks "Wouldyou [sic] like to add more(y/n)", but it does not look to me like it is adding more values, since you use the same "med" dictionary over and over. Consider how the "new" fields would ever be distinguishable from the "old" ones, based on their key
I'm making a project for school where users are quizzed on subjects and their results are saved into a report (CSV file called 'reportForFergusTwo') for the 'customer' (Fergus). The report shows the average score a certain quiz, the high score, and the username of the person who achieved it. And then, I'm meant to display the user's details but the user's details are saved in a different CSV file ('details').
So far I've made a function that finds the highest score and username of the person who achieved it in the CSV 'reportForFergusTwo'. I now need to work on a function that searches through another CSV file ('details').
def findHighScoreUser():
print(user)
with open ('details.csv', 'r') as stalking:
stalkingReader=csv.reader(stalking)
valid4=False
for row in stalkingReader:
if user in row:
valid4=True
print("Here are the details for user {}... ".format(user))
splitter=row.split(',')
name=splitter[0]
age=splitter[1]
year=splitter[2]
print("Name: {}".format(name))
print("Age: {}".format(age))
print("Year Group: {}".format(year))
postReport()
if valid4==False:
print("Sorry Fergus, this user doesn't seem to be in our records.")
'user' is a variable from my previous function, where I found the username of the person with the highest score. It holds the username. I made it global and printed it at the start of this function, and that's working, making me think this is an issue I've made in reading the CSV.
Here is the details CSV:
Name,Age,Year Group,Username,Password
Erin Jones,15,11,Eri15,Password
Lucas Jones,16,11,Luc16,Password2
Michael Jordan,11,7,Mic11,GetSomeHelp
La Roux,14,9,La 14,Bulletproof
And here is the reportForFergusTwo CSV:
Subject,Difficulty,Score,Username
language,easy,10,Luc16
chemistry,easy,10,Luc16
maths,easy,9,Luc16
chemistry,easy,5,Eri15
chemistry,easy,6,Mic11
chemistry,easy,0,Eri15
I'm still fairly new to code, so please excuse me if the answer is obvious.
If your user is no longer in scope you can provide it to your function like this:
def functionThatFindsHighestScoreUser():
# do stuff
return maxScoreUser
def findHighScoreUser(user):
print(user)
# the rest of your existing code
# get the user
maxScoreUser = functionThatFindsHighestScoreUser()
# find it and print details
findHighScoreUser(maxScoreUser)
There is almost always a way around global variables by using parameters in the function - don't use them, provide each function exactly with what it needs.
As for the csv-issues: csv module does the splitting for you as Tomalak mentioned. You can consume the reader line wise and get a list of all fields:
import csv
def checkUsers(name):
with open("users.csv",encoding="utf8",newline='\n') as u:
reader = csv.DictReader(u, delimiter=',', quotechar='|' )
found = False
for row in reader:
if row["Name"] == name:
print("Here are the details for user {}... ".format(row["Name"]))
print("Name: {}".format( row["Name"]))
print("Age: {}".format( row["Age"]))
print("Year Group: {}".format( row["Year Group"]))
found = True
break # leave for loop
if not found:
print("Not in users")
checkUsers("Michael Jordan")
checkUsers("Chris Cringle")
Output:
OrderedDict([('Name', 'Michael Jordan'), ('Age', '11'),
('Year Group', '7'), ('Username', 'Mic11'), ('Password', 'GetSomeHelp')])
Not in users
Try this?:
import pandas
#read csv data
stalking = pandas.read_csv('details.csv')
#Select all records from the stalking csv where Username equals the user you are looking for
user_details = stalking[stalking['Username']==user]
#Print values for each column from subset of data which only contains records where username == user
print('Name: {}'.format(user_details['Name']))
print('Age: {}'.format(user_details['Age']))
print('Year Group: {}'.format(user_details['Year Group']))
edit: FYI if there are multiple rows with the same username this will print all the names, ages and year groups associated with that username.
pandas makes accessing and working with csvs really easily. Once you've done var = pandas.read_csv('somefile.csv') you can access all the values in a given column using var['col1']. Subsetting can be done by doing var[var['col1'] == 'something'], which reads as 'Select records from dataset var where the values of col1 are 'something'.
The pandas docs can be found here: http://pandas.pydata.org/pandas-docs/stable/
Dictreader might also be a good way to go if pandas seems a bit too complex for what you're tyring to do.
the problem i have is that i have a quiz which the user can pick from 3 classes. they then proceed to complete the quiz and currently their name and score is saved into a text file for the correct class (there are 3 different files for the 3 different classes). but how do i make it so if the same user has completed the quiz that only the last 2 scores that the student obtained is saved in the file rather than all of the scores.
if classChoice ==1:
File=open("A.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()
if classChoice ==2:
File=open("B.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()
if classChoice ==3:
File=open("C.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()
Clearly you want to save your data in a specific data structure defined by yours. In your case you are interested in saving only last two scores of a specific student.
Let's observe how does your file "A.txt" look:
John,90
Sam,80
Alice,100
Sam,90
John,100
Instead of appending text each time, you have to read the whole file first, and convert it to something you can work with like dictionary.
def convert_file_to_dict(path):
d = {}
lines = open(path).splitlines()
for line in lines:
name, grade = line.split(',')
if name in d:
d[name].append(grade)
else:
d[name] = [grade]
return grade
In our case if I'll call convert_file_to_dict('A.txt'), I will receive dictionary which consists of { 'John':['90','100'], 'Sam':['80','90'], 'Alice':['100'] }. Notice that the order in the list of grades is preserved by order of lines in "A.txt".
Now with that dictionary you can control that only last 2 grades are kept:
def insert_new_grade(grades_dict, name, grade):
if name in grades_dict:
if len(grades_dict[name]) == 1:
grades_dict[name].append(str(grade))
else:
grades_dict[name] = grades_dict[name][1:] + [str(grade)]
else:
grades_dict[name] = [str(grade)]
Now all you need is to write a function which converts this dict to a file...
* You might want to use helpful objects like collections.defaultdict, but I didn't want to overkill here...
back again with another problem. I am trying to make a "table maker" - for now just creating files with dictionaries and checking keys.
I have two problems: firstly i don't know if there is a file format for writing in binary but not overwriting a previous file if it already exists? I tried the (try, except) method but the excepted FileExistsError does never come up :/ (in the createTable function)
Secondly I have a problem with creating lists. I made a loop which asks for entries and values for them to be stored in separate lists. Those lists will later be zipped into a dictionary and pickled into a file. (in the createTable function)
Of course if there are other mistakes I'd love them pointed out :)
import pickle
def checkTable(nameOfTable) :
try :
#seeing what is it they are looking for
prompt = input("What do you want to check?\n")
with open("%s.pkl" % nameOfTable, "rb") as f:
data = pickle.load(f)
#getting what they want from the data from table
whatTheyWant = data.get(prompt, "There is nothing like that in the table.\n")
print(whatTheyWant)
#if table doesn't exist
except IOError as e:
print("Sorry such a directory doesn't exist.\n")
def createTable(nameOfYourTable) :
try :
#opens a new file with the table
with open("%s.pkl" %nameOfYourTable, "wb+") as f :
decision = "yes"
if decision == "yes" :
#asking for entries and keys to put into the table
#creates lists with entries and values to be zipped together
entry.append = input("What is the entry?\n")
value.append = input("What is the value of the entry?\n")
decision = input("Do you want to go on? (yes/no)\n")
i += 1
else :
#getting it all into a dictionary and putting it into a file
table={dict(zip(entry, value))}
pickle.dump(table, f)
#if a file with the name already exists
except FileExistsError as e :
print("Sorry, a file with this name already exists.")
#what the person wants to do
answer = input("Hello. Do you want to create a table or check an existing one?\n")
#asking for the name of the new table
if answer == "create" :
nameOfYourTable = input("What do you want the table to be called?\n")
createTable(nameOfYourTable)
#asking what table to look in
elif answer == "check" :
nameOfTable = input("What is the name of the table?\n")
checkTable(nameOfTable)
else :
print("\nThat's not a valid option.\n")
print("Thank you for using me. It was very nice.")
There is a file mode just for what you want, open(file, "x"), add b or t as per your need.
In x mode a file is created only when it does not already exist, raises exception otherwise. The createTable function does not really make sense to me. decision = "yes" then if decision == "yes":? decision is supposed to be a global? It's very fuzzy.
You need to pickle read the list from the file first, add to the list, and then write a new pickle file at the end. Btw, you can check if a file exists with os.path.exists. Appending items to a list is done with list_name.append(new_item). You need to have initialized the list first with list_name = [].
So I am making a simple randomized number game, and I want to save the players High Score even after the program is shut down and ran again. I want the computer to be able to ask the player their name, search through the database of names in a text file, and pull up their high score. Then if their name is not there, create a name in the database. I am unsure on how to do that. I am a noob programmer and this is my second program. Any help would be appreciated.
Here is the Code for the random number game:
import random
import time
def getscore():
score = 0
return score
print(score)
def main(score):
number = random.randrange(1,5+1)
print("Your score is %s") %(score)
print("Please enter a number between 1 and 5")
user_number = int(raw_input(""))
if user_number == number:
print("Congrats!")
time.sleep(1)
print("Your number was %d, the computers number was also %d!") %(user_number,number)
score = score + 10
main(score)
elif user_number != number:
print("Sorry")
time.sleep(1)
print("Your number was %d, but the computers was %d.") %(user_number, number)
time.sleep(2)
print("Your total score was %d") %(score)
time.sleep(2)
getscore()
score = getscore()
main(score)
main(score)
EDIT:
I am trying this and it seems to be working, except, when I try to replace the string with a variable, it gives an error:
def writehs():
name = raw_input("Please enter your name")
a = open('scores.txt', 'w')
a.write(name: 05)
a.close()
def readhs():
f = open("test.txt", "r")
writehs()
readhs()
with open('out.txt', 'w') as output:
output.write(getscore())
Using with like this is the preferred way to work with files because it automatically handles file closure, even through exceptions.
Also, remember to fix your getscore() method so it doesn't always return 0. If you want it to print the score as well, put the print statement before the return.
In order to write a file using python do the following:
file2write=open("filename",'w')
file2write.write("here goes the data")
file2write.close()
If you want to read or append the file just change 'w' for 'r' or 'a' respectively
First of all you should ask your question clearly enough for others to understand.To add a text into text file you could always use the open built-in function.Do it like this.
>>> a = open('test.txt', 'w')
>>> a.write('theunixdisaster\t 05')
>>> a.close()
Thats all.If need further help try this website.
http://www.afterhoursprogramming.com/tutorial/Python/Writing-to-Files/
You could also use a for loop for the game to print all the scores.
Try this one on your own.It would rather be fun.
THE RECOMENDED WAY
Well as if the recommended way use it like this:
>>> with open('test.txt', 'w') as a:
a.write('theunixdisaster\t 05')
With this its certain that the file would close.
With variables
>>> name = sempron
>>> with open('test.txt', 'w') as a:
a.write('%s: 05' % name)
Now try calling it.Well I use python 3.4.2.So, if you get into errors, try to check if there is any difference in the string formatting with the python version that you use.