Điều này khá phức tạp, vì namedtuple()
là một nhà máy trả về một kiểu mới bắt nguồn từ tuple
. Một cách tiếp cận là để lớp của bạn cũng kế thừa từ UserDict.DictMixin
, nhưng tuple.__getitem__
đã được xác định và mong đợi một số nguyên biểu thị vị trí của phần tử, không phải tên của thuộc tính của nó:
>>> f = foobar('a', 1)
>>> f[0]
'a'
Về cơ bản, nametuple là một sự phù hợp kỳ lạ đối với JSON, vì nó thực sự là một kiểu được xây dựng tùy chỉnh có tên khóa được cố định như một phần của định nghĩa kiểu , không giống như một từ điển nơi các tên khóa được lưu trữ bên trong phiên bản. Điều này ngăn bạn "làm hỏng" một tệp tin có tên, ví dụ như bạn không thể giải mã từ điển trở lại một tệp tin có tên mà không có một số thông tin khác, chẳng hạn như mã đánh dấu loại ứng dụng cụ thể trong dict {'a': 1, '#_type': 'foobar'}
, điều này hơi khó hiểu.
Điều này không phải là lý tưởng, nhưng nếu bạn chỉ cần mã hóa các cụm từ có tên vào từ điển, thì một cách tiếp cận khác là mở rộng hoặc sửa đổi bộ mã hóa JSON của bạn thành các loại này. Đây là một ví dụ về phân lớp Python json.JSONEncoder
. Điều này giải quyết vấn đề đảm bảo rằng các nhóm có tên lồng nhau được chuyển đổi đúng cách thành từ điển:
from collections import namedtuple
from json import JSONEncoder
class MyEncoder(JSONEncoder):
def _iterencode(self, obj, markers=None):
if isinstance(obj, tuple) and hasattr(obj, '_asdict'):
gen = self._iterencode_dict(obj._asdict(), markers)
else:
gen = JSONEncoder._iterencode(self, obj, markers)
for chunk in gen:
yield chunk
class foobar(namedtuple('f', 'foo, bar')):
pass
enc = MyEncoder()
for obj in (foobar('a', 1), ('a', 1), {'outer': foobar('x', 'y')}):
print enc.encode(obj)
{"foo": "a", "bar": 1}
["a", 1]
{"outer": {"foo": "x", "bar": "y"}}