Home > database >  Best way to store a dictionary of custom objects in python?
Best way to store a dictionary of custom objects in python?

Time:11-17

I have a python script that is basically a team builder. However it is not running constantly as I am running it locally for now. I want users to be able to access their previously created team and so what would be the best way to store a dictionary of a custom object?

I have two classes, Team and Character. The Team class has an attribute that is a list of Character instances. And each Team is stored as a value in a dictionary with a user_id as the key.

Here is a basic outline:

master = {a_user_id:TrainerObject,another_user_id:TrainerObject,..}

class Trainer:
    def __init__(self, user):
        self.id = user.id # int
        self.name = user.name # str
        self.icon = user.icon # str, just a url link
        self.team = [] # List of Characters 

class Character:
    def __init__(self, slot, name, skills, item=None):
        self.slot = slot # int
        self.name = name # str
        self.skills = skills # dictionary of all str
        self.item = item # str
with open('master.pkl','wb') as f:
            pickle.dump(master,f)

Error:

Ignoring exception in command store:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/discord/ext/commands/core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "/Users/roopesh_m/Documents/Python/Coromon Battlesim/cogs/teambuild.py", line 565, in store
    pickle.dump(master,f)
TypeError: cannot pickle 'weakref' object

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/discord/ext/commands/bot.py", line 939, in invoke
    await ctx.command.invoke(ctx)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/discord/ext/commands/core.py", line 863, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/discord/ext/commands/core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: cannot pickle 'weakref' object

Edit: I have tried using pickle to store the dictionary, however I get a 'weakref' error when attempting to dump the dictionary

Edit2: Specified data types of class attributes

Edit3: Added pickle attempt and error

CodePudding user response:

The easiest way is to use pickle, a module in the standard library intended for this purpose.

import pickle


def save(save_file_path, team):
    with open(save_file_path, 'wb') as f:
        pickle.dump(team, f)


def load(save_file_path):
    with open(save_file_path, 'rb') as f:
        return pickle.load(f)


# Example
save('version_1.team', master)
print(load('version_1.team')

You may need to handle some exceptions when loading if the file doesn't exist, but I left that out for simplicity. The reference for pickle can be found here.

CodePudding user response:

Use dataclass dacite. See the example below.

The code shows how we take a dict, convert it to a Trainer, back to dict and back to Trainer.

This is actually what you are looking for.

from typing import List,Optional
from dataclasses import dataclass,asdict

from dacite import from_dict

@dataclass
class Character:
    slot:int 
    name:str
    skills:str
    item:Optional[str]

@dataclass
class Trainer:
    id :int
    name:str
    icon:str
    team: List[Character] 

data = {'id':3,'name':'jack','icon':'something','team':[{'slot':9,'name':'Jim','skills':'well','item':'zoot'}]}

trainer = from_dict(data_class=Trainer,data=data)
print(trainer)
data = asdict(trainer)

print(data)

trainer = from_dict(data_class=Trainer,data=data)

print(trainer)
  • Related