Nat*_*tte 5 python json python-3.x
我正在编写一个充当字典的类,但每次进行修改以确保同步状态时,都会将其内容保存到 json 文件中。
但是,我偶然发现了一个中断同步的特殊情况:将值附加到字典中的列表时。由于这使用__getitem__,我如何确保如果返回的项目被修改,我将其保存到 JSON 文件?
这是一个功能齐全的代码片段(Python 3.9.2)来说明我的意思
import json
class SyncDictJSON(dict):
__instances: dict = {}
@classmethod
def create(cls, filepath: str, **kwargs):
if filepath not in SyncDictJSON.__instances:
SyncDictJSON.__instances[filepath] = cls(filepath, **kwargs)
return SyncDictJSON.__instances[filepath]
def __init__(self, filepath: str, **kwargs):
super().__init__(**kwargs)
self.filepath = filepath
self.update(SyncDictJSON.read_data_from_filename(self.filepath))
def __getitem__(self, item):
print(f"getitem {item}")
return super(SyncDictJSON, self).__getitem__(item)
def __setitem__(self, key, value):
print(f"set item {key},{value}")
super().__setitem__(key, value)
SyncDictJSON.write_data_to_filename(self, self.filepath)
def __delitem__(self, key):
super().__delitem__(key)
SyncDictJSON.write_data_to_filename(self, self.filepath)
@staticmethod
def write_data_to_filename(data, filepath: str):
with open(filepath, "w", encoding="utf-8") as file:
json.dump(data, file, indent=2, ensure_ascii=False)
@staticmethod
def read_data_from_filename(filename: str):
with open(filename, "r", encoding="utf-8") as file:
return json.load(file)
@classmethod
def from_file(cls, filepath):
return cls(filepath)
if __name__ == '__main__':
with open("testing.json", "w") as file:
file.write("{}")
dico = SyncDictJSON.create("testing.json")
dico["a_list"] = []
dico["a_list"].append(5)
print(dico) # {'a_list': [5]} but testing.json will be empty
Run Code Online (Sandbox Code Playgroud)
该SyncDictJSON对象将记录对字典的更改。但是,一旦创建了列表a_list,向其追加内容将不会更改字典;字典将包含对 list 的引用[5],该引用仍然与该列表为空时的引用相同。
要记录附加到列表,您也可以使用以下代码,该代码将类包装list到类似的包装器中。它依赖于对传递到列表的同步字典的引用,因此需要一点额外的空间。如果您计划删除列表项和/或插入它们,您也需要覆盖 中的这些方法SyncList。
import json
class SyncList(list):
def __init__(self, container, *args, **kwargs):
print('list init', *args, **kwargs)
self._container = container
super().__init__(*args, **kwargs)
def append(self, x):
print('list.append', self, x)
super().append(x)
self._container.write_data_to_filename(
self._container, self._container.filepath)
class SyncDictJSON(dict):
__instances: dict = {}
@classmethod
def create(cls, filepath: str, **kwargs):
if filepath not in SyncDictJSON.__instances:
SyncDictJSON.__instances[filepath] = cls(filepath, **kwargs)
return SyncDictJSON.__instances[filepath]
def __init__(self, filepath: str, **kwargs):
super().__init__(**kwargs)
self.filepath = filepath
self.update(SyncDictJSON.read_data_from_filename(self.filepath))
def __getitem__(self, item):
print(f"getitem {item}")
return super(SyncDictJSON, self).__getitem__(item)
def __setitem__(self, key, value):
print(f"set item {key},{value}")
super().__setitem__(key, value)
SyncDictJSON.write_data_to_filename(self, self.filepath)
def __delitem__(self, key):
super().__delitem__(key)
SyncDictJSON.write_data_to_filename(self, self.filepath)
@staticmethod
def write_data_to_filename(data, filepath: str):
with open(filepath, "w", encoding="utf-8") as file:
json.dump(data, file, indent=2, ensure_ascii=False)
@staticmethod
def read_data_from_filename(filename: str):
with open(filename, "r", encoding="utf-8") as file:
return json.load(file)
@classmethod
def from_file(cls, filepath):
return cls(filepath)
if __name__ == '__main__':
with open("testing.json", "w") as file:
file.write("{}")
dico = SyncDictJSON.create("testing.json")
dico["a_list"] = SyncList(dico, [])
dico["a_list"].append(5)
print(dico) # {'a_list': [5]}; testing.json will have the same
# list init []
# set item a_list,[]
# getitem a_list
# list.append [] 5
# {'a_list': [5]}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
69 次 |
| 最近记录: |