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.
Related
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
With indentation:
a_dict = ({"name": "kevin", "id":100001 })
with open('test.json',"a+") as f:
json.dump(a_dict, f, indent=4) # Indent makes it more readable
f.write("\n")
print("done")
Output as below, won't be able to read, says json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes:
{
"name": "kevin",
"id": 100001
}
{
"name": "kevin",
"id": 100001
}
Without indentation:
a_dict = ({"name": "kevin", "id":100001 })
with open('test.json',"a+") as f:
json.dump(a_dict, f) # Indent makes it more readable
f.write("\n")
print("done")
Output that can be read:
{"name": "kevin", "id": 100001}
{"name": "kevin", "id": 100001}
{"name": "kevin", "id": 100001}
{"name": "kevin", "id": 100001}
Decoding:
p_list = []
with open('test.json') as f:
for json_obj in f:
test_dict = json.loads(json_obj)
p_list.append(test_dict)
# print(test_dict)
for emp in p_list:
print(emp['name'])
Looks like you're trying to use the JSONL / JSON Lines format. The predicate for this format is that each object, or whichever JSON entity, is wholly represented in a single line of the file. So you can't have it be JSONL and indented/prettified at the same time.
When you do:
with open('test.json') as f:
for json_obj in f:
...
each json_obj is just one line of the file, not the JSON object read-in till the end of that object.
If you want to do it that way, you'll need to write your own JSON Decoder that reads in more lines until it's found the end-delimiter and a valid JSON entity. Same goes for writing the file - you'd need to write your own JSON Encoder.
The closest thing to being able to do JSON Lines & Pretty'fied is jq command line tool. And since it's not a Python package, in order to read and write data, use subprocess.run() with capture_output=True.
You can find questions related to this tool on StackOverflow with the tag jq.
Edit: If you are certain that you will only be writing JSON objects to the file the same way always, you can setup the read to start at a line which starts with { without any spaces/indentation before it and continue reading until you reach a line with } without any spaces/indentation before it.
A rough idea:
with open('test.json') as f:
parts = []
in_obj = False
for some_text in f:
if some_text == '{' and not in_obj:
in_obj = True
parts.append('{')
elif in_obj:
parts.append(some_text)
if some_text == '}':
in_obj = False
# put this in a try-except block
json_obj = json.loads('\n'.join(parts))
yield json_obj # or return
parts = [] # reset
elif not some_text.startswith(' ' * 4):
print('error') # in an object but wrong indent
# the check above should actually include checking more than
# just the starting 4 spaces since it could be nested further
else:
print('error') # not in an object and not end delimeter
You'll need to modify that to read multiple objects and be an actual parser.
Also, as noted by #ewen-lbh below, files in this format should have the .jsonl extension. If it's .json you're implying that it holds a single valid loadable json entity.
I'm trying to figure out how to make sure that when I run a new dict entry that it actually saves. Before last exception, when you "print(dictio.fullDict3[firstLetter])", it shows the new appended dict entry, but doesn't actually save in the external file called dictio.
The following is the main:
import fileinput
import dictio
from dictio import fullDict3
while True:
try:
srcTxt = input("Input word you want to look up: ")
firstLetter = srcTxt[0]
print(dictio.fullDict3[firstLetter][srcTxt])
except:
try:
queryInput = input('What does '+srcTxt+' mean?: ')
with open("C:\\Users...\\dictio.py", "a"):
dictio.fullDict3[firstLetter].update({srcTxt:queryInput})
print(dictio.fullDict3[firstLetter])
except:
print("error has occured.")
The following is the external file called dictio.py that holds the dictionary:
fullDict3 = {
'0':{
'0data':'0datttaaa',
'0mada':'0mmmaadaa'
},
'a':{
'arbre':'tree',
'arc-en-ciel':'rainbow'
},
'b':{
'bierre':'beer',
'belle':'beautiful'
}
}
You can't change the contents of a module by operating on the module's contents via import. There is no reason to import fullDict3. Instead, store your starting structure in fullDict3.json. Convert that file to a Python object via json.load -- that returns a dict you can change. When you have the updated dict ready to write to disk, save it via json.dump.
Alright. Haven't had much time to code, but finally fixed my issue after some reading and trial an error, for anyone that comes across this for answers, however, there could easily be a cleaner and more efficient way to get it done:
while True:
try:
srcTxt = input("Input word you want to look up: ")
firstLetter = srcTxt[0]
if srcTxt == "ESC":
break
print(dictio.fullDict3[firstLetter][srcTxt])
except:
try:
queryInput = input('What does '+srcTxt+' mean?: ')
with open('C:\\Users...\\dictio.py', 'r') as f:
fullDict3[firstLetter].update({srcTxt:queryInput})
newDict = "fullDict3 = "+json.dumps(fullDict3)
with open('C:\\Users...\\dictio.py', 'w') as f:
f.write(newDict)
f.close()
except:
print("error has occured.")
I have this JSON in a file:
{"groupcolor":[
{"user":"group01", "color":"blue"},
{"user":"group02", "color":"yellow"},
{"user":"group03", "color":"green"}
]}
and I want to use Python(3) to verify if the content of "user" matches with "color". I've tried:
import json
with open('groupcolor.json') as f:
for line in f:
if f.user == group01 and f.color = blue:
print("ok!")
else:
print ("not ok")
but it obviously isn't the right syntax. most of the information that I found is focused on parsing or adding information, but I haven't found anything about checking the relation between two elements. is a way to do it in Python?
You definitely have the right idea: just the wrong syntax, as you point out.
As a comment suggests, you need to use json.load() (but not json.loads(), as json.loads() is for a string, not a file). This will rope in the json file as a dictionary.
import json
with open('groupcolor.json') as f:
json_dict = json.load(f)
users = json_dict["groupcolor"]
for item in users:
if item["user"] == "group01" and item["color"] == "blue":
print("ok!")
else:
print ("not ok")
Here is one solution:
import json
with open('groupcolor.json') as f:
group_color = json.load(f) # parse json into dict
group_color = group_color["groupcolor"] # get array out of dict
# create a dictionary where user is group01 and color is blue
search_criteria = dict(zip(("user", "color"), ("group01", "blue")))
for user_data in group_color:
message = "ok!" if user_data == search_criteria else "not ok"
print(message)
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.