@@ -1026,11 +1026,36 @@ def _asdict_inner(obj, dict_factory):
1026
1026
value = _asdict_inner (getattr (obj , f .name ), dict_factory )
1027
1027
result .append ((f .name , value ))
1028
1028
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 ])
1029
1050
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).
1030
1054
return type (obj )(_asdict_inner (v , dict_factory ) for v in obj )
1031
1055
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 ())
1034
1059
else :
1035
1060
return copy .deepcopy (obj )
1036
1061
@@ -1066,7 +1091,18 @@ def _astuple_inner(obj, tuple_factory):
1066
1091
value = _astuple_inner (getattr (obj , f .name ), tuple_factory )
1067
1092
result .append (value )
1068
1093
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 ])
1069
1102
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).
1070
1106
return type (obj )(_astuple_inner (v , tuple_factory ) for v in obj )
1071
1107
elif isinstance (obj , dict ):
1072
1108
return type (obj )((_astuple_inner (k , tuple_factory ), _astuple_inner (v , tuple_factory ))
0 commit comments