@@ -1026,11 +1026,36 @@ def _asdict_inner(obj, dict_factory):
10261026 value = _asdict_inner (getattr (obj , f .name ), dict_factory )
10271027 result .append ((f .name , value ))
10281028 return dict_factory (result )
1029+ elif isinstance (obj , tuple ) and hasattr (obj , '_fields' ):
1030+ # obj is a namedtuple. Recurse into it, but the returned
1031+ # object is another namedtuple of the same type. This is
1032+ # similar to how other list- or tuple-derived classes are
1033+ # treated (see below), but we just need to create them
1034+ # differently because a namedtuple's __init__ needs to be
1035+ # called differently (see bpo-34363).
1036+
1037+ # I'm not using namedtuple's _asdict()
1038+ # method, because:
1039+ # - it does not recurse in to the namedtuple fields and
1040+ # convert them to dicts (using dict_factory).
1041+ # - I don't actually want to return a dict here. The the main
1042+ # use case here is json.dumps, and it handles converting
1043+ # namedtuples to lists. Admittedly we're losing some
1044+ # information here when we produce a json list instead of a
1045+ # dict. Note that if we returned dicts here instead of
1046+ # namedtuples, we could no longer call asdict() on a data
1047+ # structure where a namedtuple was used as a dict key.
1048+
1049+ return type (obj )(* [_asdict_inner (v , dict_factory ) for v in obj ])
10291050 elif isinstance (obj , (list , tuple )):
1051+ # Assume we can create an object of this type by passing in a
1052+ # generator (which is not true for namedtuples, handled
1053+ # above).
10301054 return type (obj )(_asdict_inner (v , dict_factory ) for v in obj )
10311055 elif isinstance (obj , dict ):
1032- return type (obj )((_asdict_inner (k , dict_factory ), _asdict_inner (v , dict_factory ))
1033- for k , v in obj .items ())
1056+ return type (obj )((_asdict_inner (k , dict_factory ),
1057+ _asdict_inner (v , dict_factory ))
1058+ for k , v in obj .items ())
10341059 else :
10351060 return copy .deepcopy (obj )
10361061
@@ -1066,7 +1091,18 @@ def _astuple_inner(obj, tuple_factory):
10661091 value = _astuple_inner (getattr (obj , f .name ), tuple_factory )
10671092 result .append (value )
10681093 return tuple_factory (result )
1094+ elif isinstance (obj , tuple ) and hasattr (obj , '_fields' ):
1095+ # obj is a namedtuple. Recurse into it, but the returned
1096+ # object is another namedtuple of the same type. This is
1097+ # similar to how other list- or tuple-derived classes are
1098+ # treated (see below), but we just need to create them
1099+ # differently because a namedtuple's __init__ needs to be
1100+ # called differently (see bpo-34363).
1101+ return type (obj )(* [_astuple_inner (v , tuple_factory ) for v in obj ])
10691102 elif isinstance (obj , (list , tuple )):
1103+ # Assume we can create an object of this type by passing in a
1104+ # generator (which is not true for namedtuples, handled
1105+ # above).
10701106 return type (obj )(_astuple_inner (v , tuple_factory ) for v in obj )
10711107 elif isinstance (obj , dict ):
10721108 return type (obj )((_astuple_inner (k , tuple_factory ), _astuple_inner (v , tuple_factory ))
0 commit comments