py/objtype: Use mp_obj_dict_copy() for creating obj.__dict__ attribute.

The resulting dict is now marked as read-only (is_fixed=1) to enforce the
fact that changes to this dict will not be reflected in the class instance.

This commit reduces code size by about 20 bytes, and should be more
efficient because it creates a direct copy of the dict rather than
reinserting all elements.
This commit is contained in:
Andrew Leech 2020-06-10 10:46:38 +10:00 committed by Damien George
parent 28370c0450
commit 95cbe6b65e
1 changed files with 7 additions and 10 deletions

View File

@ -588,16 +588,13 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
#if MICROPY_CPYTHON_COMPAT
if (attr == MP_QSTR___dict__) {
// Create a new dict with a copy of the instance's map items.
// This creates, unlike CPython, a 'read-only' __dict__: modifying
// it will not result in modifications to the actual instance members.
mp_map_t *map = &self->members;
mp_obj_t attr_dict = mp_obj_new_dict(map->used);
for (size_t i = 0; i < map->alloc; ++i) {
if (mp_map_slot_is_filled(map, i)) {
mp_obj_dict_store(attr_dict, map->table[i].key, map->table[i].value);
}
}
dest[0] = attr_dict;
// This creates, unlike CPython, a read-only __dict__ that can't be modified.
mp_obj_dict_t dict;
dict.base.type = &mp_type_dict;
dict.map = self->members;
dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(&dict));
mp_obj_dict_t *dest_dict = MP_OBJ_TO_PTR(dest[0]);
dest_dict->map.is_fixed = 1;
return;
}
#endif