@@ -1073,7 +1073,7 @@ def unpack_named_tuple(spec: ValueSpec) -> Expression:
10731073 }
10741074 fields = getattr (spec .type , "_fields" , ())
10751075 defaults = getattr (spec .type , "_field_defaults" , {})
1076- unpackers = []
1076+ unpackers : dict [ str , Expression ] = {}
10771077 as_dict = spec .builder .get_dialect_or_config_option (
10781078 "namedtuple_as_dict" , False
10791079 )
@@ -1107,11 +1107,11 @@ def unpack_named_tuple(spec: ValueSpec) -> Expression:
11071107 could_be_none = True ,
11081108 )
11091109 )
1110- unpackers . append ( unpacker )
1110+ unpackers [ field ] = unpacker
11111111
11121112 if not defaults :
11131113 field_type = spec .builder .get_type_name_identifier (spec .type )
1114- return f"{ field_type } ({ ', ' .join (unpackers )} )"
1114+ return f"{ field_type } ({ ', ' .join (unpackers . values () )} )"
11151115
11161116 lines = CodeLines ()
11171117 method_name = (
@@ -1130,14 +1130,30 @@ def unpack_named_tuple(spec: ValueSpec) -> Expression:
11301130 # we shouldn't be here because there will be default_kwargs
11311131 lines .append (f"def { method_name } ({ method_args } ):" )
11321132 with lines .indent ():
1133- lines .append ("fields = []" )
1134- with lines .indent ("try:" ):
1135- for unpacker in unpackers :
1136- lines .append (f"fields.append({ unpacker } )" )
1137- with lines .indent ("except IndexError:" ):
1138- lines .append ("pass" )
1133+ use_fields_list = not as_dict or len (fields ) - len (defaults ) > 0
1134+ if use_fields_list :
1135+ lines .append ("fields_list = []" )
1136+ if as_dict :
1137+ lines .append ("fields_dict = {}" )
1138+ if use_fields_list :
1139+ with lines .indent ("try:" ):
1140+ for field , unpacker in unpackers .items ():
1141+ if not as_dict or as_dict and field not in defaults :
1142+ lines .append (f"fields_list.append({ unpacker } )" )
1143+ with lines .indent ("except IndexError:" ):
1144+ lines .append ("pass" )
1145+ if as_dict :
1146+ for field , unpacker in unpackers .items ():
1147+ if field in defaults :
1148+ with lines .indent ("try:" ):
1149+ lines .append (f"fields_dict['{ field } '] = { unpacker } " )
1150+ with lines .indent ("except KeyError:" ):
1151+ lines .append ("pass" )
11391152 field_type = spec .builder .get_type_name_identifier (spec .type )
1140- lines .append (f"return { field_type } (*fields)" )
1153+ args = "*fields_list" if use_fields_list else ""
1154+ if as_dict :
1155+ args = ", " .join (filter (None , (args , "**fields_dict" )))
1156+ lines .append (f"return { field_type } ({ args } )" )
11411157 lines .append (
11421158 f"setattr({ spec .cls_attrs_name } , '{ method_name } ', { method_name } )"
11431159 )
0 commit comments