@@ -1332,58 +1332,69 @@ class C:
13321332
13331333
13341334def _asdict_inner (obj , dict_factory ):
1335- if type (obj ) in _ATOMIC_TYPES :
1335+ obj_type = type (obj )
1336+ if obj_type in _ATOMIC_TYPES :
13361337 return obj
1337- elif _is_dataclass_instance ( obj ):
1338- # fast path for the common case
1338+ elif hasattr ( obj_type , _FIELDS ):
1339+ # dataclass instance: fast path for the common case
13391340 if dict_factory is dict :
13401341 return {
13411342 f .name : _asdict_inner (getattr (obj , f .name ), dict )
13421343 for f in fields (obj )
13431344 }
13441345 else :
1345- result = []
1346- for f in fields (obj ):
1347- value = _asdict_inner (getattr (obj , f .name ), dict_factory )
1348- result .append ((f .name , value ))
1349- return dict_factory (result )
1350- elif isinstance (obj , tuple ) and hasattr (obj , '_fields' ):
1351- # obj is a namedtuple. Recurse into it, but the returned
1352- # object is another namedtuple of the same type. This is
1353- # similar to how other list- or tuple-derived classes are
1354- # treated (see below), but we just need to create them
1355- # differently because a namedtuple's __init__ needs to be
1356- # called differently (see bpo-34363).
1357-
1358- # I'm not using namedtuple's _asdict()
1359- # method, because:
1360- # - it does not recurse in to the namedtuple fields and
1361- # convert them to dicts (using dict_factory).
1362- # - I don't actually want to return a dict here. The main
1363- # use case here is json.dumps, and it handles converting
1364- # namedtuples to lists. Admittedly we're losing some
1365- # information here when we produce a json list instead of a
1366- # dict. Note that if we returned dicts here instead of
1367- # namedtuples, we could no longer call asdict() on a data
1368- # structure where a namedtuple was used as a dict key.
1369-
1370- return type (obj )(* [_asdict_inner (v , dict_factory ) for v in obj ])
1371- elif isinstance (obj , (list , tuple )):
1372- # Assume we can create an object of this type by passing in a
1373- # generator (which is not true for namedtuples, handled
1374- # above).
1375- return type (obj )(_asdict_inner (v , dict_factory ) for v in obj )
1376- elif isinstance (obj , dict ):
1377- if hasattr (type (obj ), 'default_factory' ):
1346+ return dict_factory ([
1347+ (f .name , _asdict_inner (getattr (obj , f .name ), dict_factory ))
1348+ for f in fields (obj )
1349+ ])
1350+ # handle the builtin types first for speed; subclasses handled below
1351+ elif obj_type is list :
1352+ return [_asdict_inner (v , dict_factory ) for v in obj ]
1353+ elif obj_type is dict :
1354+ return {
1355+ _asdict_inner (k , dict_factory ): _asdict_inner (v , dict_factory )
1356+ for k , v in obj .items ()
1357+ }
1358+ elif obj_type is tuple :
1359+ return tuple ([_asdict_inner (v , dict_factory ) for v in obj ])
1360+ elif issubclass (obj_type , tuple ):
1361+ if hasattr (obj , '_fields' ):
1362+ # obj is a namedtuple. Recurse into it, but the returned
1363+ # object is another namedtuple of the same type. This is
1364+ # similar to how other list- or tuple-derived classes are
1365+ # treated (see below), but we just need to create them
1366+ # differently because a namedtuple's __init__ needs to be
1367+ # called differently (see bpo-34363).
1368+
1369+ # I'm not using namedtuple's _asdict()
1370+ # method, because:
1371+ # - it does not recurse in to the namedtuple fields and
1372+ # convert them to dicts (using dict_factory).
1373+ # - I don't actually want to return a dict here. The main
1374+ # use case here is json.dumps, and it handles converting
1375+ # namedtuples to lists. Admittedly we're losing some
1376+ # information here when we produce a json list instead of a
1377+ # dict. Note that if we returned dicts here instead of
1378+ # namedtuples, we could no longer call asdict() on a data
1379+ # structure where a namedtuple was used as a dict key.
1380+ return obj_type (* [_asdict_inner (v , dict_factory ) for v in obj ])
1381+ else :
1382+ return obj_type (_asdict_inner (v , dict_factory ) for v in obj )
1383+ elif issubclass (obj_type , dict ):
1384+ if hasattr (obj_type , 'default_factory' ):
13781385 # obj is a defaultdict, which has a different constructor from
13791386 # dict as it requires the default_factory as its first arg.
1380- result = type (obj )( getattr ( obj , ' default_factory' ) )
1387+ result = obj_type (obj . default_factory )
13811388 for k , v in obj .items ():
13821389 result [_asdict_inner (k , dict_factory )] = _asdict_inner (v , dict_factory )
13831390 return result
1384- return type (obj )((_asdict_inner (k , dict_factory ),
1385- _asdict_inner (v , dict_factory ))
1386- for k , v in obj .items ())
1391+ return obj_type ((_asdict_inner (k , dict_factory ),
1392+ _asdict_inner (v , dict_factory ))
1393+ for k , v in obj .items ())
1394+ elif issubclass (obj_type , list ):
1395+ # Assume we can create an object of this type by passing in a
1396+ # generator
1397+ return obj_type (_asdict_inner (v , dict_factory ) for v in obj )
13871398 else :
13881399 return copy .deepcopy (obj )
13891400
@@ -1416,11 +1427,10 @@ def _astuple_inner(obj, tuple_factory):
14161427 if type (obj ) in _ATOMIC_TYPES :
14171428 return obj
14181429 elif _is_dataclass_instance (obj ):
1419- result = []
1420- for f in fields (obj ):
1421- value = _astuple_inner (getattr (obj , f .name ), tuple_factory )
1422- result .append (value )
1423- return tuple_factory (result )
1430+ return tuple_factory ([
1431+ _astuple_inner (getattr (obj , f .name ), tuple_factory )
1432+ for f in fields (obj )
1433+ ])
14241434 elif isinstance (obj , tuple ) and hasattr (obj , '_fields' ):
14251435 # obj is a namedtuple. Recurse into it, but the returned
14261436 # object is another namedtuple of the same type. This is
0 commit comments