How can I input information in json file with commas between values?
import json
class Calculation():
"""The Program class(ALL)"""
def __init__(self,money_earned = 0,money_spended = 0):
self.money_earned = money_earned
self.money_spended = money_spended
def m_s(self):
"""input daily spend to file"""
self.money_spended = str(input("How much money you spend today?"))
print(self.money_spended)
file = "data_txt_cat/spend.json"
with open(file,"a") as f_obj:
json.dump(self.money_spended,f_obj)
def m_e(self):
"""input daily earn to file"""
self.money_earned = input("How much money earned today? ")
print(self.money_earned)
file = "data_txt_cat/earn.json"
with open(file, "a") as f_obj:
json.dump(self.money_earned, f_obj)
spend = Calculation()
spend.m_s()
spend.m_e()
Currently this writes a file with "11""12" in it from that input, rather than JSON output
The problem is that you're writing a json object with just a single value, rather than really a json structure
Try putting your inputs into a dictionary or list and adding a newline
Additionally, if you're not making some sort of key-value mapping, consider if you're really using JSON at all
You may find it convenient to use a dictionary .update() method
import json
earned = {
"value": [] # this is the list being appended to
}
try:
with open("whatever.json", "r") as fh: # open for reading and writing
earned.update(json.load(fh))
except FileNotFoundError:
print("warning: no starting file")
with open("whatever.json", 'w') as fh: # NOTE clobbers - consider backup and swap
earned["value"].append(input("How much money earned today?: "))
json.dump(earned, fh) # rewrite file
Related
I've recently started to learn some python.
After finishing all the learnpython.org tutorials I'm trying something on my own (So you know my knowledge level).
I want to build a small script that lets you build a DnD character and save it in a file. The idea was to use JSON (Since this was included in the learnpython tutorials) and put in dictionaries along the lines of:
data = { playerName ; {"Character Name" : characterName, "Character Class" : characterClass...ect.}}
I was hoping that it is possible to add new dics into the JSON file inside that original data dic, So the dictionary is a list of playerName's that have the character dics under them.
Not only did I fail to get it exactly like this, I also fail at just adding following dictionaries without making the file unreadable. Here is my code, since it isn't very long:
import json
def dataCollection():
print("Please write your character name:")
characterName = input()
print("%s, a good name! \nNow tell me your race:" % characterName)
characterRace = input()
print("And what about the class?")
characterClass = input()
print("Ok so we have; \nName = %s \nRace = %s \nClass = %s \nPlease tell me the player name now:" % (characterName, characterRace, characterClass))
playerName = input()
print("Nice to meet you %s. \nI will now save your choices..." % playerName)
localData = { playerName :
{"Character Name" : characterName,
"Character Class" : characterClass,
"Character Race" : characterRace}}
with open("%s_data_file.json" % playerName, "a") as write_file:
json.dump(localData, write_file)
dataCollection()
with open("data_file.json", "r") as read_file:
data = json.load(read_file)
# different .json name here since I'm trying around with different files
print(data)
Edit: It might also be possible that JSON is not the "right" thing to use for my idea. If you have any alternative ideas for storing that information (Besides straight txt file), feel free to suggest them!
i made little modification, i try to read the file for init the data json, if it fail i init the data.
import json
def createPlayer():
print("Please write your character name : ")
characterName = input()
print("%s, a good name! \nNow tell me your race : " % characterName)
characterRace = input()
print("Nice to meet you %s. \nI will now save your choices..." % characterName)
try :
with open('data_file.json') as json_file:
data = json.load(json_file)
except :
data = {}
data['player'] = []
data['player'].append({
'name': characterName,
'race': characterRace,
})
with open("data_file.json", "w+") as write_file:
json.dump(data, write_file)
createPlayer()
with open("data_file.json", "r") as read_file:
data = json.load(read_file)
print(data)
I think that the way you think of a dictionnary might not be exactly what it is.
A dictionary is a data structure that can holds many key-value pairs.
Here the key to your dictionary would be the player's name and the value would be the dictionary that holds the character's name, class and race.
So a json file that holds a dictionary cannot be appended to because a json file can only hold 1 json object.
{ 'playerName': {...character\'s attributes...}}
If you were to open the file and append a json object (like you do at the end of dataCollection) then your file would be like this
{ 'playerName':
{...characters attributes...}
}
{ 'playerName2':
{...characters attributes...}
}
And when reading the file json will stop when the first json object it finds will end. So it won't load the 2nd dictionary.
If you want to add something to the dictionary inside your json file, you need to load the json file to access the dictionary and then add your new key-value pair and then dump this new dictionary. Which will result in the following json file:
{ 'playerName':
{...characters attributes...},
'playerName2':
{...characters attributes...}
}
I hope it's kinda clear.
I add to my dictionary 2 different meals and 2 different unit amounts, which then saves to my text file perfectly fine, but then when I exit the program and reload the file, I get a syntax error. (Also some functions look like they are not completed but that's just because Stack Overflow told me not to add all the code in.
Tried making the dictionary not start as an empty dictionary but that didn't solve anything.
import pprint
import time
pretty = pprint.PrettyPrinter(width = 20)
meals = {}
command = ""
condition = False
f = open("meals.txt", "r+")
f.write(str(meals))
f.close()
def save_dict_to_file(meals):
f = open("meals.txt", "r+")
f.write(str(meals))
f.close()
def load_dict_from_file():
f = open("meals.txt", "r+")
data = f.read()
f.close()
return eval(data)
load_dict_from_file()
def add_entry():
meal = input("Enter name of meal: ").lower()
units = int(input("Enter units needed: "))
meals[meal] = units
pretty.pprint(meals)
save_dict_to_file(meals)
def remove_entry():
def help():
def view_dict():
def ending_message():
while True:
command = input("> ").lower()
if command == "help":
help()
elif command == "add":
add_entry()
elif command == "exit":
save_dict_to_file(meals)
ending_message()
time.sleep(3)
break
elif command == "remove":
remove_entry()
elif command == "view":
view_dict()
After adding multiple entries to the dictionary, I'm expecting to be able to quit the program, load back up and when I type view to look at my entries, see what I have previously added in.This is what I get -
PS C:\Users\Alex\Desktop\Python\own_projects\mosh> python diabetes.py
Traceback (most recent call last):
File "diabetes.py", line 24, in <module>
load_dict_from_file()
File "diabetes.py", line 22, in load_dict_from_file
return eval(data)
File "<string>", line 1
{}lasagne': 12, 'fish and chips': 16}
^
SyntaxError: invalid syntax
The problem is probably caused by not adding newlines to your file. A simple fix would be: f.write(str(meals) + "\n")
But writing code in a textfile and then evaluating it is a bad idea:
The file will only ever be readable by your python program
It is prone to syntax errors (as in your question)
It is very unsafe. Malicious code could end up in your file.
As long as you only store text, numbers and true/false in your dictionary, it can be represented very cleanly by a JSON file. JSON has the advantage that it can be read by basically any programming language:
import json
data = {
"A": 1,
"B": {"C": 2}
}
# write data to file
with open("file.txt", "w") as file:
file.write(json.dumps(data))
# read data from file
with open("file.txt", "r") as file:
data = json.load(file)
If you store more complex objects in your file, maybe instances of classes etc, then you should look at pickle. That's another built-in library and a very convenient way to store almost everything from your python program. As Klaus D. has pointed out in a comment, pickle is not safer than your approach. You should never load a pickle object from an origin that you don't trust.
import pickle
with open("file.txt", "wb") as file:
pickle.dump(data, file)
with open("file.txt", "rb") as file:
data = pickle.load(file)
I don't entirely remember how pretty print works, but this way of accomplishing this is very fragile. The likelihood of something not printing in a way you expect it to is pretty high, which could break things as it is now.
I recommend using a more standard data transmission format like CSV or JSON. If your data is flat, I recommend CSV. If your data is more complex, I recommend JSON.
I'll edit this answer momentarily with examples of both methods.
CSV example:
import csv
# This is a list of dictionaries
data = [
{
'meal': 'breakfast',
'units': 20
},
{
'meal': 'lunch',
'units': 40
},
{
'meal': 'dinner',
'units': 50
}
]
# If you wanted the values for lunch, you could do data[1]['units']
# This says access the second value inside the data list,
# and get the value for the units in that dictionary
def write_data(file_path='meals.csv'):
# Open the file for writing without adding extra new lines
# The with syntax will automatically close it for us
with open(file_path, 'w', newline='') as f:
# Create a dictionary writer, telling it what columns to expect
writer = csv.DictWriter(f, ['meal', 'units'])
writer.writeheader()
writer.writerows(data)
def read_data(file_path='meals.csv'):
new_data = []
# open the file for reading
with open(file_path) as f:
# Create a dictionary reader. It will figure things out automagically
reader = csv.DictReader(f)
for row in reader:
print(row)
new_data.append(row)
return new_data
print('writing data...')
write_data()
print('reading data...')
print(read_data())
JSON example:
import json
data = {
'lunch': 10,
'breakfast': 20,
'dinner': 30
}
def write_data(file_path='meals.json'):
# Open the file for writing without adding extra new lines
# The with syntax will automatically close it for us
with open(file_path, 'w', newline='') as f:
json.dump(data, f)
def read_data(file_path='meals.json'):
# open the file for reading
with open(file_path) as f:
new_data = json.load(f)
return new_data
print('writing data...')
write_data()
print('reading data...')
print(read_data())
this need to work:
import pprint
import time
import os
pretty = pprint.PrettyPrinter(width = 20)
meals = {}
command = ""
condition = False
n = False
if not os.path.isfile('meals.txt'):
f = open("meals.txt", "w+")
f.write(str(meals))
f.close()
else:
n = True
def save_dict_to_file(meals):
f = open("meals.txt", "w+")
f.write(str(meals))
f.close()
def load_dict_from_file():
f = open("meals.txt", "r+")
data = f.read()
f.close()
return eval(data)
if n:
meals = load_dict_from_file()
def add_entry():
meal = input("Enter name of meal: ").lower()
units = int(input("Enter units needed: "))
meals[meal] = units
pretty.pprint(meals)
save_dict_to_file(meals)
import os
def remove_entry():
os.remove('meals.txt')
def help():
pretty.pprint('help')
def view_dict():
pretty.pprint(load_dict_from_file())
def ending_message():
pretty.pprint('done')
while True:
command = input("> ").lower()
if command == "help":
help()
elif command == "add":
add_entry()
elif command == "exit":
save_dict_to_file(meals)
ending_message()
time.sleep(3)
break
elif command == "remove":
remove_entry()
elif command == "view":
view_dict()
The task:
Your program should read from the file, storing the names and
corresponding email addresses in a dictionary as key-value pairs.
Then, the program should display a menu that lets the user enter the
numbers 1 through 5, each corresponding to a different menu item:
When the user enters 5, the program should write the names and email
addresses in alphabetical order by first name to the file
phonebook.out You can use the sorted() function which accepts a
dictionary argument to sort a dictionary based on Key
This is my code:
def write_to_file(contact):
file = open("phonebook.out", "w")
contactsort = dict(sorted(contact.items()))
phonebook.write(contact)
phonebook.close
However, this code isn't working. I'm not sure why, so any help is appreciated. thank you.
Have you tried json file?
Like this:
import json
filename = "phonebook.json"
def write_to_file(contact):
with open(filename, 'w') as f_obj:
contactsort = dict(sorted(contact.items()))
json.dump(contact, f_obj)
This is your code:
def write_to_file(contact):
file = open("phonebook.out", "w")
contactsort = dict(sorted(contact.items()))
phonebook.write(contact)
phonebook.close
As #Cheche mentioned, you are declaring the output as file but using it as phonebook. Simply replace file = open("phonebook.out", "w") with phonebook = open("phonebook.out", "w"). Also, you are storing the sorted names to contactsort but writing contact to the file. As a side note, phonebook.close needs to be be phonebook.close() with the parentheses to call the function.
The way you sort the dict is incorrect. Try:
contactsort = {key: contact[key] for key in sorted(contact.iterkeys())}
Also, you should try to use with when possible. with takes care of closing the file for you. Final code:
def write_to_file(contact):
with open("phonebook.out", "w") as phonebook:
contactsort = {key: contact[key] for key in sorted(contact.iterkeys())}
phonebook.write(str(contactsort))
def write_to_file(contact):
phonebook = open("phonebook.out", "w")
contactsort = dict(sorted(contact.items()))
phonebook.write(str(contactsort))
phonebook.close()
write_to_file({"name":9090909090, "name_a":8080808080})
here You go
I'm writing a simple python game where I have a text file in the following format where the key on the left is the player's name and the value on the right is the player's score:
Name 134
Next Name 304958
Etc....
Question: How can I read in a text file in that format and create a dictionary from the values on each line, and once the player exits the program, the file is updated with the latest dictionary entries?
I already have some code commented out that I've started but have been unable to implement and get working. Any help is appreciated.
Here is my code:
# with open('scores.txt', 'r') as file:
# scores = {}
# for line in file:
# line = line.split()
# do stuff
# with open("scores.txt", "w") as f: # Save dictionary in file
# do stuff
To load that format:
with open('scores.txt', 'r') as infile:
scores = {}
for line in infile:
name, _, score = line.rpartition(' ')
scores[name] = int(score)
To save that format:
with open('scores.txt', 'w') as outfile:
for name, score in scores:
outfile.write('%s %s\n' % (name, score))
penne12 is correct, though. You could save a few lines of code by using the json library to store JSON instead of this particular text format.
Here's an example that uses JSON as suggested in the comments:
import json
def load_game_data():
data = None
with open('savegame.json', 'r') as savefile:
data = json.load(savefile)
return data
def save_game_data(data):
with open('savegame.json', 'w') as savefile:
json.dump(data, savefile)
# Store the game data as a dictionary:
data = { 'player_name' : 'wolfram', 'hp' : 8 }
save_game_data(data)
data = load_game_data()
print(data)
# prints {'player_name': 'wolfram', 'hp': 8}
print(data['player_name'])
print(data['hp'])
The data gets saved to disk as JSON and is loaded from disk as a dictionary, which is easy to use. You'll need to add code error handling, of course, this is just intended as a simple illustration.
I want to learn Python so I started writing my first program which is a phone book directory.
It has the options to add a name and phone number, remove numbers, and search for them.
Ive been stuck on the remove part for about 2 days now and just can't get it working correctly. I've been in the Python IRC and everything, but haven't been able to figure it out.
Basically, my program stores the numbers to a list in a file. I cannot figure out how to remove a particular line in the file but keep the rest of the file intact. Can someone please help me with this?
Some people have advised that it will be easier to do if I create a temp file, remove the line, then copy the remaining lines from the original file over to the temp file. Then write over the original file over with the temp file. So I have been trying this...
if ui == 'remove':
coname = raw_input('What company do you want to remove? ') # company name
f = open('codilist.txt', 'r') # original phone number listing
f1 = open('codilist.tmp', 'a') # open a tmp file
for line in f:
if line.strip() != coname.strip():
for line in f:
f1.write(line)
break # WILL LATER OVERWRITE THE codilist.txt WITH THE TMP FILE
else:
f1.write(line)
else:
print 'Error: That company is not listed.'
f1.close()
f.close()
continue
I assume your file contains something like <name><whitespace><number> on each line? If that's the case, you could use something like this for your if statement (error handling not included!):
name, num = line.strip().split()
if name != coname.strip():
# write to file
Suggestion:
Unless there is some specific reason for you to use a custom format, the file format json is quite good for this kind of task. Also note the use of the 'with' statement in these examples, which saves you having to explicitly close the file.
To write the information:
import json
# Somehow build a dict of {coname: num,...}
info = {'companyA': '0123456789', 'companyB': '0987654321'}
with open('codilist.txt', 'w') as f:
json.dump(info, f, indent=4) # Using indent for prettier files
To read/amend the file:
import json
with open('codilist.txt', 'r+') as f:
info = json.load(f)
# Remove coname
if coname in info:
info.pop(coname)
else:
print 'No record exists for ' + coname
# Add 'companyC'
info['companyC'] = '0112233445'
# Write back to file
json.dump(info, f, indent=4)
You'll need python2.6 or later for these examples. If you're on 2.5, you'll need these imports:
import simplejson as json
from __future__ import with_statement
Hope that helps!
Here is a pretty extensively rewritten version:
all the phone data is wrapped into a Phonebook class; data is kept in memory (instead of being saved and reloaded for every call)
it uses the csv module to load and save data
individual actions are turned into short functions or methods (instead of One Big Block of Code)
commands are abstracted into a function-dispatch dictionary (instead of a cascade of if/then tests)
This should be much easier to understand and maintain.
import csv
def show_help():
print('\n'.join([
"Commands:",
" help shows this screen",
" load [file] loads the phonebook (file name is optional)",
" save [file] saves the phonebook (file name is optional)",
" add {name} {number} adds an entry to the phonebook",
" remove {name} removes an entry from the phonebook",
" search {name} displays matching entries",
" list show all entries",
" quit exits the program"
]))
def getparam(val, prompt):
if val is None:
return raw_input(prompt).strip()
else:
return val
class Phonebook(object):
def __init__(self, fname):
self.fname = fname
self.data = []
self.load()
def load(self, fname=None):
if fname is None:
fname = self.fname
try:
with open(fname, 'rb') as inf:
self.data = list(csv.reader(inf))
print("Phonebook loaded")
except IOError:
print("Couldn't open '{}'".format(fname))
def save(self, fname=None):
if fname is None:
fname = self.fname
with open(fname, 'wb') as outf:
csv.writer(outf).writerows(self.data)
print("Phonebook saved")
def add(self, name=None, number=None):
name = getparam(name, 'Company name? ')
number = getparam(number, 'Company number? ')
self.data.append([name,number])
print("Company added")
def remove(self, name=None):
name = getparam(name, 'Company name? ')
before = len(self.data)
self.data = [d for d in self.data if d[0] != name]
after = len(self.data)
print("Deleted {} entries".format(before-after))
def search(self, name=None):
name = getparam(name, 'Company name? ')
found = 0
for c,n in self.data:
if c.startswith(name):
found += 1
print("{:<20} {:<15}".format(c,n))
print("Found {} entries".format(found))
def list(self):
for c,n in self.data:
print("{:<20} {:<15}".format(c,n))
print("Listed {} entries".format(len(self.data)))
def main():
pb = Phonebook('phonebook.csv')
commands = {
'help': show_help,
'load': pb.load,
'save': pb.save,
'add': pb.add,
'remove': pb.remove,
'search': pb.search,
'list': pb.list
}
goodbyes = set(['quit','bye','exit'])
while True:
# get user input
inp = raw_input("#> ").split()
# if something was typed in
if inp:
# first word entered is the command; anything after that is a parameter
cmd,args = inp[0],inp[1:]
if cmd in goodbyes:
# exit the program (can't be delegated to a function)
print 'Goodbye.'
break
elif cmd in commands:
# "I know how to do this..."
try:
# call the appropriate function, and pass any parameters
commands[cmd](*args)
except TypeError:
print("Wrong number of arguments (type 'help' for commands)")
else:
print("I didn't understand that (type 'help' for commands)")
if __name__=="__main__":
main()
Something simple like this will read all of f, and write out all the lines that don't match:
for line in f:
if line.strip() != coname.strip():
f1.write(line)
Ned's answer looks like it should work. If you haven't tried this already, you can set python's interactive debugger above the line in question. Then you can print out the values of line.strip() and coname.strip() to verify you are comparing apples to apples.
for line in f:
import pdb
pdb.set_trace()
if line.strip() != coname.strip():
f1.write(line)
Here's a list of pdb commands.
You probably don't want to open the temp file in append ('a') mode:
f1 = open('codilist.tmp', 'a') # open a tmp file
also, be aware that
for line in f:
...
f1.write(line)
will write everything to the file without newlines.
The basic structure you want is:
for line in myfile:
if not <line-matches-company>:
tmpfile.write(line + '\n') # or print >>tmpfile, line
you'll have to implement <line-matches-company> (there isn't enough information in the question to know what it should be -- perhaps if you showed a couple of lines from your data file..?)
I got this working...
if ui == 'remove':
coname = raw_input('What company do you want to remove? ') # company name
f = open('codilist.txt')
tmpfile = open('codilist.tmp', 'w')
for line in f:
if coname in line:
print coname + ' has been removed.'
else:
tmpfile.write(line)
f.close()
tmpfile.close()
os.rename('codilist.tmp', 'codilist.txt')
continue