繁体   English   中英

在python中存储自定义对象字典的最佳方法?

[英]Best way to store a dictionary of custom objects in python?

我有一个 Python 脚本,它基本上是一个团队构建器。 然而,它并没有持续运行,因为我现在在本地运行它。 我希望用户能够访问他们以前创建的团队,那么存储自定义对象字典的最佳方式是什么?

我有两个班级, TeamCharacter Team类有一个属性,它是一个Character实例列表。 每个Team都作为一个值存储在一个字典中,以 user_id 作为键。

下面是一个基本的大纲:

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)

错误:

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

编辑:我尝试使用 pickle 来存储字典,但是在尝试转储字典时出现“weakref”错误

Edit2:类属性的指定数据类型

Edit3:添加了泡菜尝试和错误

最简单的方法是使用pickle ,这是标准库中专门用于此目的的模块。

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')

如果文件不存在,您可能需要在加载时处理一些异常,但为了简单起见,我将其省略。 可以在此处找到pickle的参考。

使用dataclass + dacite 看下面的例子

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)

您可以使用dataclass-wizard库,它执行相对较快的 JSON(反)序列化。 我对下面的pickle库进行了计时,看起来性能大致相同。

注意:下面的示例应该适用于包含__future__导入的 Python 3.7+

from __future__ import annotations

import json
import pickle
from dataclasses import dataclass, asdict
from timeit import timeit

from dataclass_wizard import fromdict


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


@dataclass
class Character:
    slot: int
    name: str
    skills: dict[str, str]
    item: str | None


master = Trainer(12345, 'Johnny Smidt', 'The Great Icon 123',
                 team=[Character(7, 'Jim Raynor', {'A1': 'Catching Criminals'}, item='Pistol'),
                       Character(321, 'Tom Rebel', {'C3': 'Squirrel Hunting'}, item='Snare')],
                 )


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


def save2(save_file_path, team):
    with open(save_file_path, 'w') as f:
        json.dump(asdict(team), f)


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


def load2(save_file_path):
    with open(save_file_path, 'rb') as f:
        return fromdict(Trainer, json.load(f))


# Example
n = 1_000
print('pickle -> save:    ', timeit("save('version_1.team', master)", number=n, globals=globals()))
print('dataclass -> save: ', timeit("save2('version_1.json', master)", number=n, globals=globals()))
print('pickle -> load:    ', timeit("load('version_1.team')", number=n, globals=globals()))
print('dataclass -> load: ', timeit("load2('version_1.json')", number=n, globals=globals()))

# assert that Trainer object loaded from pickle/json have the same data
assert load('version_1.team') == load2('version_1.json')

print()
print(load2('version_1.json'))

结果 - 在 Mac OS Big Sur 上测试,运行 Python 3.10.0

pickle -> save:     0.18621111599986762
dataclass -> save:  0.38911844700032816
pickle -> load:     0.18183052699987456
dataclass -> load:  0.06633681200037245

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM