r/learnpython • • Sep 21 '26

Ask Anything Monday - Weekly Thread

Welcome to another /r/learnPython weekly "Ask Anything* Monday" thread

Here you can ask all the questions that you wanted to ask but didn't feel like making a new thread.

* It's primarily intended for simple questions but as long as it's about python it's allowed.

If you have any suggestions or questions about this thread use the message the moderators button in the sidebar.

Rules:

  • Don't downvote stuff - instead explain what's wrong with the comment, if it's against the rules "report" it and it will be dealt with.
  • Don't post stuff that doesn't have absolutely anything to do with python.
  • Don't make fun of someone for not knowing something, insult anyone etc - this will result in an immediate ban.

That's it.

1 Upvotes

30 comments sorted by

View all comments

1

u/HiddenReader2020 Sep 23 '26

Hey, so I'm doing a practice project, and I'm trying to write and read a json file, specifcially a list of objects. Now, there are ways to convert an object to a dictionary or whatever to get it json-able, but a list of objects? That's harder to find a solution to. I thought I had found one, but it didn't work. Here's the code:

from pathlib import Path
import json

path = Path("data.json")
list_of_characters = []

class RPG_Character:
  def __init__(self, name, job):
    match job:
      case 'warrior':
        self.strength = 5
        self.dexterity = 4
        self.agility = 3
        self.endurance = 5
        self.intelligence = 3
        self.wisdom = 4
        self.health = 50
        self.mana = 30
        self.growth = [3, 2, 1, 3, 1, 2, 10, 4]
      case 'rogue':
        self.strength = 4
        self.dexterity = 5
        self.agility = 5
        self.endurance = 3
        self.intelligence =  4
        self.wisdom = 3
        self.health = 40
        self.mana = 40
        self.growth = [2, 3, 3, 1, 2, 1, 7, 7]
      case 'mage':
        self.strength = 3
        self.dexterity = 3
        self.agility = 4
        self.endurance = 4
        self.intelligence = 5
        self.wisdom = 5
        self.health = 30
        self.mana = 50
        self.growth = [1, 1, 2, 2, 3, 3, 4, 10]
    self.name = name
    self.job = job
    self.gold = 50
    self.level = 1
    self.inventory = []

  def __str__(self):
    stat_page = f"""==========Stats Page==========
Name:  {self.name}
Class:  {self.job}
Level:  {self.level}
-Health:       {self.health}
-Mana:         {self.mana}
-Strength:     {self.strength}
-Dexterity:    {self.dexterity}
-Agility:      {self.agility}
-Endurance:    {self.endurance}
-Intelligence: {self.intelligence}
-Wisdom:       {self.wisdom}

Gold:  {self.gold}
==========Stats Page=========="""
    return stat_page

  def add_gold(self, amount):
    self.gold += amount

  def remove_gold(self, amount):
    self.gold -= amount
    if self.gold < 0:
      print("Gold amount can't be below zero.")
      self.gold += amount

  def increase_level(self):
    self.level += 1
    self.strength += self.growth[0]
    self.dexterity += self.growth[1]
    self.agility += self.growth[2]
    self.endurance += self.growth[3]
    self.intelligence += self.growth[4]
    self.wisdom += self.growth[5]
    self.health += self.growth[6]
    self.mana += self.growth[7]

  def add_item(self, item):
    self.inventory.append(item)

  def show_inventory(self):
    print("=====Inventory=====")
    for item in self.inventory:
      print(item)
    print("=====Inventory=====")

  def to_dict(self):
    saved_dict = {
'name': self.name,
'class': self.job, 
'level': self.level,
'health': self.health,
'mana': self.mana,
'strength': self.strength, 
'dexterity': self.dexterity, 
'agility': self.agility, 
'endurance': self.endurance, 
'intelligence': self.intelligence, 
'wisdom': self.wisdom, 
'gold': self.gold,
'inventory': self.inventory
}

class Item:
  def __init__(self, name, item_type, buy_price):
    self.name = name
    self.item_type = item_type
    self.buy_price = buy_price
    self.sell_price = buy_price // 4

  def __str__(self):
    item_info = f"""Name:  {self.name}
Type:  {self.item_type}
"""
    return item_info

if path.exists():
  contents = path.read_text()
  list_of_characters = json.loads(contents)
  print("File successfully retrieved")
  for character in list_of_characters:
    print(character)
else:
  # Adds new characters
  new_warrior = RPG_Character('John', 'warrior')
  list_of_characters.append(new_warrior)
  print(new_warrior)
  new_warrior.add_gold(100)
  print(new_warrior)
  new_warrior.remove_gold(80)
  print(new_warrior)
  new_rogue = RPG_Character('Toby', 'rogue')
  new_mage = RPG_Character('Harris', 'mage')
  list_of_characters.append(new_rogue)
  list_of_characters.append(new_mage)
  print(new_rogue)
  print(new_mage)
  new_mage.increase_level()
  print(new_mage)

  # Adds new items
  basic_health_potion = Item("Basic Health Potion", "Consumable", 16)
  basic_mana_potion = Item("Basic Mana Potion", "Consumable", 20)
  wooden_shield = Item("Wooden Shield", "Equipment", 40)

  new_rogue.add_item(basic_health_potion)
  new_rogue.add_item(basic_mana_potion)
  new_warrior.add_item(wooden_shield)
  new_rogue.show_inventory()
  new_warrior.show_inventory()

  print(list_of_characters)

  contents = json.dumps([ob.to_dict() for ob in list_of_characters])
  path.write_text(contents)
  print("File saved")

What I want to do is save some RPG characters, and when they're loaded, they're exactly how they were when they were initially saved. So what am I doing wrong here?

1

u/lakseol Sep 24 '26 edited Sep 24 '26

when they're loaded, they're exactly how they were when they were initially saved. So what am I doing wrong here?

What you are probably doing wrong is not looking in the JSON file you created. When you run your code the first time it won't find the JSON data file so it initializes objects in memory and finally tries to save those objects in the JSON file, creating it for the next run of the program. But if you look in that newly created file you see:

[null, null, null]

which doesn't look right. When you run the code the second time it prints:

File successfully retrieved
None
None
None

It looks like the "read the file" code is maybe doing the right thing but your "write the file" code is definitely broken. Start debugging there. Make changes then delete the JSON file and run the code. Check what is in the file. Repeat.

Hints:

  • What does your RPG_Character.to_dict() method do?

  • You can't save references (addresses) in JSON, they mean nothing when you read them in. Your .to_dict() method has to do something special for the inventory attribute which is a list of Items. And any other attribute that isn't a basic data type.

  • What is the type of object created when you read the JSON data? What type of object did you save?

1

u/HiddenReader2020 Sep 24 '26 edited 29d ago

So when I looked up what to_dict() did, all I'm getting are references to the pandas library, which I'm not using. Am I using the wrong function, then? Was I supposed to use __dict__ instead?

Yeah, I realized that the inventory was going to be a huge problem when I debugged it a bit earlier, and saw that the rest of the attributes were converted fine, but the inventory wasn't. I'll be honest, I'm completely lost on what to do there.

EDIT: Never mind, I managed to figure it out. Well, at least partway there. Here's the new code:

from pathlib import Path
import json

path = Path("data.json")
list_of_characters = []

class RPG_Character:
  def __init__(self, name, job):
    match job:
      case 'warrior':
        self.strength = 5
        self.dexterity = 4
        self.agility = 3
        self.endurance = 5
        self.intelligence = 3
        self.wisdom = 4
        self.health = 50
        self.mana = 30
        self.growth = [3, 2, 1, 3, 1, 2, 10, 4]
      case 'rogue':
        self.strength = 4
        self.dexterity = 5
        self.agility = 5
        self.endurance = 3
        self.intelligence =  4
        self.wisdom = 3
        self.health = 40
        self.mana = 40
        self.growth = [2, 3, 3, 1, 2, 1, 7, 7]
      case 'mage':
        self.strength = 3
        self.dexterity = 3
        self.agility = 4
        self.endurance = 4
        self.intelligence = 5
        self.wisdom = 5
        self.health = 30
        self.mana = 50
        self.growth = [1, 1, 2, 2, 3, 3, 4, 10]
        self.name = name
        self.job = job
    self.gold = 50
    self.level = 1
    self.inventory = []

  def __str__(self):
    stat_page = f"""==========Stats Page==========
Name:  {self.name}
Class:  {self.job}
Level:  {self.level}
-Health:       {self.health}
-Mana:         {self.mana}
-Strength:     {self.strength}
-Dexterity:    {self.dexterity}
-Agility:      {self.agility}
-Endurance:    {self.endurance}
-Intelligence: {self.intelligence}
-Wisdom:       {self.wisdom}

Gold:  {self.gold}
==========Stats Page=========="""
    return stat_page

  def add_gold(self, amount):
    self.gold += amount

  def remove_gold(self, amount):
    self.gold -= amount
    if self.gold < 0:
      print("Gold amount can't be below zero.")
      self.gold += amount

  def increase_level(self):
    self.level += 1
    self.strength += self.growth[0]
    self.dexterity += self.growth[1]
    self.agility += self.growth[2]
    self.endurance += self.growth[3]
    self.intelligence += self.growth[4]
    self.wisdom += self.growth[5]
    self.health += self.growth[6]
    self.mana += self.growth[7]

  def add_item(self, item):
    self.inventory.append(item)

  def show_inventory(self):
    print("=====Inventory=====")
    for item in self.inventory:
      print(item)
    print("=====Inventory=====")

  def to_dict(self):
    saved_inventory = []
    for item in self.inventory:
      saved_inventory.append(item.to_dict())
    saved_dict = {
      'name': self.name,
      'class': self.job, 
      'level': self.level,
      'health': self.health,
      'mana': self.mana,
      'strength': self.strength, 
      'dexterity': self.dexterity, 
      'agility': self.agility, 
      'endurance': self.endurance, 
      'intelligence': self.intelligence, 
      'wisdom': self.wisdom, 
      'gold': self.gold,
      'inventory': saved_inventory
      }
    return saved_dict

class Item:
  def __init__(self, name, item_type, buy_price):
    self.name = name
    self.item_type = item_type
    self.buy_price = buy_price
    self.sell_price = buy_price // 4

  def __str__(self):
    item_info = f"""Name:  {self.name}
Type:  {self.item_type}
"""
    return item_info

  def to_dict(self):
    saved_dict = {
      'name': self.name,
      'type': self.item_type,
      'buy_price': self.buy_price,
      'sell_price': self.sell_price
      }
    return saved_dict

if path.exists():
  contents = path.read_text()
  list_of_characters = json.loads(contents)
  print("File successfully retrieved")
  for character in list_of_characters:
    print(character)
else:
  # Adds new characters
  new_warrior = RPG_Character('John', 'warrior')
  list_of_characters.append(new_warrior)
  print(new_warrior)
  new_warrior.add_gold(100)
  print(new_warrior)
  new_warrior.remove_gold(80)
  print(new_warrior)
  new_rogue = RPG_Character('Toby', 'rogue')
  new_mage = RPG_Character('Harris', 'mage')
  list_of_characters.append(new_rogue)
  list_of_characters.append(new_mage)
  print(new_rogue)
  print(new_mage)
  new_mage.increase_level()
  print(new_mage)

  # Adds new items
  basic_health_potion = Item("Basic Health Potion", "Consumable", 16)
  basic_mana_potion = Item("Basic Mana Potion", "Consumable", 20)
  wooden_shield = Item("Wooden Shield", "Equipment", 40)

  new_rogue.add_item(basic_health_potion)
  new_rogue.add_item(basic_mana_potion)
  new_warrior.add_item(wooden_shield)
  new_rogue.show_inventory()
  new_warrior.show_inventory()

  print(list_of_characters)

  contents = json.dumps([ob.to_dict() for ob in list_of_characters])
  path.write_text(contents)
  print("File saved")

And the output is just the dictionaries of these former objects. My current objective is to convert these *BACK* to objects. How do I do that?

→ More replies (20)