Skip to content

Commit 745ce4c

Browse files
committed
Merge pull request adafruit#131 from chipaca/dict_fromkeys
Added dict.fromkeys.
2 parents bab5cfb + 4bee76e commit 745ce4c

5 files changed

Lines changed: 95 additions & 18 deletions

File tree

py/builtin.c

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -166,25 +166,12 @@ static mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
166166
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
167167

168168
mp_obj_t mp_builtin_len(mp_obj_t o_in) {
169-
mp_small_int_t len = 0;
170-
if (MP_OBJ_IS_TYPE(o_in, &str_type)) {
171-
len = strlen(qstr_str(mp_obj_str_get(o_in)));
172-
} else if (MP_OBJ_IS_TYPE(o_in, &tuple_type)) {
173-
uint seq_len;
174-
mp_obj_t *seq_items;
175-
mp_obj_tuple_get(o_in, &seq_len, &seq_items);
176-
len = seq_len;
177-
} else if (MP_OBJ_IS_TYPE(o_in, &list_type)) {
178-
uint seq_len;
179-
mp_obj_t *seq_items;
180-
mp_obj_list_get(o_in, &seq_len, &seq_items);
181-
len = seq_len;
182-
} else if (MP_OBJ_IS_TYPE(o_in, &dict_type)) {
183-
len = mp_obj_dict_len(o_in);
184-
} else {
169+
mp_obj_t len = mp_obj_len_maybe(o_in);
170+
if (len == NULL) {
185171
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
172+
} else {
173+
return len;
186174
}
187-
return MP_OBJ_NEW_SMALL_INT(len);
188175
}
189176

190177
mp_obj_t mp_builtin_max(int n_args, const mp_obj_t *args) {

py/obj.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <stdlib.h>
33
#include <stdio.h>
44
#include <stdarg.h>
5+
#include <string.h>
56
#include <assert.h>
67

78
#include "nlr.h"
@@ -229,3 +230,26 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index)
229230
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "%s indices must be integers, not %s", type->name, mp_obj_get_type_str(index)));
230231
}
231232
}
233+
234+
// may return NULL
235+
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
236+
mp_small_int_t len = 0;
237+
if (MP_OBJ_IS_TYPE(o_in, &str_type)) {
238+
len = strlen(qstr_str(mp_obj_str_get(o_in)));
239+
} else if (MP_OBJ_IS_TYPE(o_in, &tuple_type)) {
240+
uint seq_len;
241+
mp_obj_t *seq_items;
242+
mp_obj_tuple_get(o_in, &seq_len, &seq_items);
243+
len = seq_len;
244+
} else if (MP_OBJ_IS_TYPE(o_in, &list_type)) {
245+
uint seq_len;
246+
mp_obj_t *seq_items;
247+
mp_obj_list_get(o_in, &seq_len, &seq_items);
248+
len = seq_len;
249+
} else if (MP_OBJ_IS_TYPE(o_in, &dict_type)) {
250+
len = mp_obj_dict_len(o_in);
251+
} else {
252+
return NULL;
253+
}
254+
return MP_OBJ_NEW_SMALL_INT(len);
255+
}

py/obj.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
234234
qstr mp_obj_get_qstr(mp_obj_t arg);
235235
mp_obj_t *mp_obj_get_array_fixed_n(mp_obj_t o, machine_int_t n);
236236
uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index);
237+
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return NULL */
237238

238239
// none
239240
extern const mp_obj_type_t none_type;

py/objdict.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,61 @@ static mp_obj_t dict_values(mp_obj_t self_in) {
376376
}
377377
static MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values);
378378

379+
380+
/******************************************************************************/
381+
/* dict metaclass */
382+
383+
static mp_obj_t dict_fromkeys(int n_args, const mp_obj_t *args) {
384+
assert(2 <= n_args && n_args <= 3);
385+
mp_obj_t iter = rt_getiter(args[1]);
386+
mp_obj_t len = mp_obj_len_maybe(iter);
387+
mp_obj_t value = mp_const_none;
388+
mp_obj_t next = NULL;
389+
mp_obj_dict_t *self = NULL;
390+
391+
if (n_args > 2) {
392+
value = args[2];
393+
}
394+
395+
if (len == NULL) {
396+
/* object's type doesn't have a __len__ slot */
397+
self = mp_obj_new_dict(0);
398+
} else {
399+
self = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len));
400+
}
401+
402+
while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
403+
mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
404+
}
405+
406+
return self;
407+
}
408+
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_obj, 2, 3, dict_fromkeys);
409+
410+
static const mp_method_t dict_class_methods[] = {
411+
{ "fromkeys", &dict_fromkeys_obj },
412+
{ NULL, NULL }, // end-of-list sentinel
413+
};
414+
415+
/* this should be unnecessary when inheritance works */
416+
static void dict_class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
417+
print(env, "<class 'dict'>");
418+
}
419+
420+
/* this should be unnecessary when inheritance works */
421+
static mp_obj_t dict_class_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
422+
return rt_build_map(0);
423+
}
424+
425+
static const mp_obj_type_t dict_class = {
426+
{ &mp_const_type },
427+
"dict_class",
428+
.print = dict_class_print,
429+
.methods = dict_class_methods,
430+
.call_n = dict_class_call_n,
431+
};
432+
433+
379434
/******************************************************************************/
380435
/* dict constructors & etc */
381436

@@ -394,7 +449,7 @@ static const mp_method_t dict_type_methods[] = {
394449
};
395450

396451
const mp_obj_type_t dict_type = {
397-
{ &mp_const_type },
452+
{ &dict_class },
398453
"dict",
399454
.print = dict_print,
400455
.make_new = dict_make_new,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
d = dict.fromkeys([1, 2, 3, 4])
2+
l = list(d.keys())
3+
l.sort()
4+
print(l)
5+
6+
d = dict.fromkeys([1, 2, 3, 4], 42)
7+
l = list(d.values())
8+
l.sort()
9+
print(l)
10+

0 commit comments

Comments
 (0)