Dies ist ziemlich schwierig, da namedtuple()
es sich um eine Factory handelt, die einen neuen Typ zurückgibt, der von abgeleitet ist tuple
. Ein Ansatz wäre, dass Ihre Klasse auch von erbt UserDict.DictMixin
, aber tuple.__getitem__
bereits definiert ist und eine Ganzzahl erwartet, die die Position des Elements angibt, nicht den Namen seines Attributs:
>>> f = foobar('a', 1)
>>> f[0]
'a'
Im Kern passt das Namedtuple ungerade zu JSON, da es sich tatsächlich um einen benutzerdefinierten Typ handelt, dessen Schlüsselnamen als Teil der Typdefinition festgelegt sind , im Gegensatz zu einem Wörterbuch, in dem Schlüsselnamen in der Instanz gespeichert sind. Dies verhindert, dass Sie ein benanntes Tupel "umrunden", z. B. können Sie ein Wörterbuch nicht ohne andere Informationen wie ein app-spezifischer {'a': 1, '#_type': 'foobar'}
Typmarker im Diktat, der etwas hackig ist, zurück in ein benanntes Tupel dekodieren.
Dies ist nicht ideal, aber wenn Sie nur Namedtuples in Wörterbücher codieren müssen, besteht ein anderer Ansatz darin, Ihren JSON-Encoder zu erweitern oder zu ändern, um diese Typen in Sonderfällen zu verwenden. Hier ist ein Beispiel für die Unterklasse von Python json.JSONEncoder
. Dies behebt das Problem, sicherzustellen, dass verschachtelte benannte Tupel ordnungsgemäß in Wörterbücher konvertiert werden:
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"}}