はnamedtuple()
から派生した新しい型を返すファクトリであるため、これはかなり注意が必要tuple
です。1つのアプローチは、クラスもから継承することですがUserDict.DictMixin
、tuple.__getitem__
すでに定義されており、属性の名前ではなく、要素の位置を示す整数を期待しています。
>>> f = foobar('a', 1)
>>> f[0]
'a'
名前付きタプルは、キー名がインスタンス内に格納されている辞書とは異なり、実際にはキー名が型定義の一部として固定されているカスタムビルドの型であるため、本質的にはJSONに奇妙に適合します。これにより、名前付きタプルを「ラウンドトリップ」することができなくなります。たとえば、辞書のアプリ固有のタイプマーカーなど{'a': 1, '#_type': 'foobar'}
、少しハッキーな情報がないと、辞書をデコードして名前付きタプルに戻すことはできません。
これは理想的ではありませんが、名前付きタプルを辞書にエンコードするだけでよい場合は、JSONエンコーダーを拡張または変更してこれらのタイプを特殊なケースにすることもできます。Pythonをサブクラス化する例を次に示し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"}}