นี้เป็นเรื่องยุ่งยากสวยเนื่องจากเป็นโรงงานที่ส่งกลับเป็นชนิดใหม่ที่ได้มาจากnamedtuple()
tuple
แนวทางหนึ่งคือให้คลาสของคุณสืบทอดจากUserDict.DictMixin
แต่tuple.__getitem__
มีการกำหนดไว้แล้วและคาดว่าจำนวนเต็มแสดงถึงตำแหน่งขององค์ประกอบไม่ใช่ชื่อของแอตทริบิวต์:
>>> f = foobar('a', 1)
>>> f[0]
'a'
หัวใจของมันคือ namedtuple เป็นแบบแปลก ๆ สำหรับ JSON เนื่องจากเป็นประเภทที่สร้างขึ้นเองซึ่งมีการแก้ไขชื่อคีย์เป็นส่วนหนึ่งของคำจำกัดความประเภทซึ่งแตกต่างจากพจนานุกรมที่ชื่อคีย์ถูกเก็บไว้ในอินสแตนซ์ สิ่งนี้จะป้องกันไม่ให้คุณ "ปัดเศษ" ชื่อทูเปิลเช่นคุณไม่สามารถถอดรหัสพจนานุกรมกลับไปที่ชื่อไฟล์ทูปเปิ้ลโดยไม่มีข้อมูลอื่น ๆ เช่นเครื่องหมายประเภทเฉพาะแอปในคำสั่ง{'a': 1, '#_type': 'foobar'}
ซึ่งค่อนข้างแฮ็ก
สิ่งนี้ไม่เหมาะอย่างยิ่ง แต่หากคุณต้องการเพียงแค่เข้ารหัสชื่อไฟล์ลงในพจนานุกรมอีกวิธีหนึ่งคือการขยายหรือแก้ไขตัวเข้ารหัส JSON ของคุณเป็นกรณีพิเศษประเภทเหล่านี้ นี่คือตัวอย่างของ subclassing json.JSONEncoder
หลาม สิ่งนี้ช่วยแก้ปัญหาในการตรวจสอบว่ามีการแปลงชื่อรายการที่ซ้อนกันเป็นพจนานุกรมอย่างถูกต้อง:
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"}}