Questo è piuttosto complicato, poiché namedtuple()
è una fabbrica che restituisce un nuovo tipo derivato da tuple
. Un approccio potrebbe essere quello di far ereditare anche la tua classe da UserDict.DictMixin
, ma tuple.__getitem__
è già definita e si aspetta un numero intero che denoti la posizione dell'elemento, non il nome del suo attributo:
>>> f = foobar('a', 1)
>>> f[0]
'a'
Fondamentalmente namedtuple è una scelta strana per JSON, poiché è in realtà un tipo personalizzato i cui nomi di chiave sono fissati come parte della definizione del tipo , a differenza di un dizionario in cui i nomi di chiave sono memorizzati all'interno dell'istanza. Questo ti impedisce di eseguire il "round trip" di una namedtuple, ad esempio non puoi decodificare un dizionario in una namedtuple senza qualche altra informazione, come un marcatore di tipo specifico dell'app nel dict {'a': 1, '#_type': 'foobar'}
, che è un po 'hacky.
Questo non è l'ideale, ma se hai solo bisogno di codificare namedtuples in dizionari, un altro approccio è estendere o modificare il tuo codificatore JSON a questi tipi di casi speciali. Ecco un esempio di sottoclasse di Python json.JSONEncoder
. Questo affronta il problema di garantire che le coppie denominate annidate siano convertite correttamente in dizionari:
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"}}