![](/img/trans.png)
[英]What is the best way to store big amount of custom Python objects in a file?
[英]Best way to store a dictionary of custom objects in python?
我有一个 Python 脚本,它基本上是一个团队构建器。 然而,它并没有持续运行,因为我现在在本地运行它。 我希望用户能够访问他们以前创建的团队,那么存储自定义对象字典的最佳方式是什么?
我有两个班级, Team
和Character
。 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.