@@ -1332,58 +1332,69 @@ class C:
1332
1332
1333
1333
1334
1334
def _asdict_inner (obj , dict_factory ):
1335
- if type (obj ) in _ATOMIC_TYPES :
1335
+ obj_type = type (obj )
1336
+ if obj_type in _ATOMIC_TYPES :
1336
1337
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
1339
1340
if dict_factory is dict :
1340
1341
return {
1341
1342
f .name : _asdict_inner (getattr (obj , f .name ), dict )
1342
1343
for f in fields (obj )
1343
1344
}
1344
1345
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' ):
1378
1385
# obj is a defaultdict, which has a different constructor from
1379
1386
# 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 )
1381
1388
for k , v in obj .items ():
1382
1389
result [_asdict_inner (k , dict_factory )] = _asdict_inner (v , dict_factory )
1383
1390
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 )
1387
1398
else :
1388
1399
return copy .deepcopy (obj )
1389
1400
@@ -1416,11 +1427,10 @@ def _astuple_inner(obj, tuple_factory):
1416
1427
if type (obj ) in _ATOMIC_TYPES :
1417
1428
return obj
1418
1429
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
+ ])
1424
1434
elif isinstance (obj , tuple ) and hasattr (obj , '_fields' ):
1425
1435
# obj is a namedtuple. Recurse into it, but the returned
1426
1436
# object is another namedtuple of the same type. This is
0 commit comments