Skip to content

Commit ae7c0a2

Browse files
committed
py/objtype: Add __dict__ attribute for class objects.
1 parent 29e2586 commit ae7c0a2

File tree

4 files changed

+36
-11
lines changed

4 files changed

+36
-11
lines changed

py/obj.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in);
895895
mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index);
896896
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
897897
mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key);
898+
mp_obj_t mp_obj_dict_copy(mp_obj_t self_in);
898899
static inline mp_map_t *mp_obj_dict_get_map(mp_obj_t dict) {
899900
return &((mp_obj_dict_t *)MP_OBJ_TO_PTR(dict))->map;
900901
}

py/objdict.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ STATIC mp_obj_t dict_clear(mp_obj_t self_in) {
227227
}
228228
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear);
229229

230-
STATIC mp_obj_t dict_copy(mp_obj_t self_in) {
230+
mp_obj_t mp_obj_dict_copy(mp_obj_t self_in) {
231231
mp_check_self(mp_obj_is_dict_type(self_in));
232232
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
233233
mp_obj_t other_out = mp_obj_new_dict(self->map.alloc);
@@ -240,7 +240,7 @@ STATIC mp_obj_t dict_copy(mp_obj_t self_in) {
240240
memcpy(other->map.table, self->map.table, self->map.alloc * sizeof(mp_map_elem_t));
241241
return other_out;
242242
}
243-
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy);
243+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, mp_obj_dict_copy);
244244

245245
#if MICROPY_PY_BUILTINS_DICT_FROMKEYS
246246
// this is a classmethod

py/objtype.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -587,17 +587,16 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
587587
}
588588
#if MICROPY_CPYTHON_COMPAT
589589
if (attr == MP_QSTR___dict__) {
590-
// Create a new dict with a copy of the instance's map items.
590+
// Returns a read-only dict of the instance members.
591+
// If the internal locals is not fixed, a copy will be created.
591592
// This creates, unlike CPython, a 'read-only' __dict__: modifying
592593
// it will not result in modifications to the actual instance members.
593-
mp_map_t *map = &self->members;
594-
mp_obj_t attr_dict = mp_obj_new_dict(map->used);
595-
for (size_t i = 0; i < map->alloc; ++i) {
596-
if (mp_map_slot_is_filled(map, i)) {
597-
mp_obj_dict_store(attr_dict, map->table[i].key, map->table[i].value);
598-
}
599-
}
600-
dest[0] = attr_dict;
594+
mp_obj_dict_t dict;
595+
dict.map = self->members;
596+
dict.base.type = &mp_type_dict;
597+
dest[0] = mp_obj_dict_copy(MP_OBJ_FROM_PTR(&dict));
598+
mp_obj_dict_t *dest_dict = MP_OBJ_TO_PTR(dest[0]);
599+
dest_dict->map.is_fixed = 1;
601600
return;
602601
}
603602
#endif
@@ -1013,6 +1012,21 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
10131012
dest[0] = MP_OBJ_NEW_QSTR(self->name);
10141013
return;
10151014
}
1015+
#if MICROPY_CPYTHON_COMPAT
1016+
if (attr == MP_QSTR___dict__) {
1017+
// Returns a read-only dict of the class attributes.
1018+
// If the internal locals is not fixed, a copy will be created.
1019+
mp_obj_dict_t *dict = MP_OBJ_FROM_PTR(self->locals_dict);
1020+
if (dict->map.is_fixed) {
1021+
dest[0] = dict;
1022+
} else {
1023+
dest[0] = mp_obj_dict_copy(dict);
1024+
dict = MP_OBJ_TO_PTR(dest[0]);
1025+
dict->map.is_fixed = 1;
1026+
}
1027+
return;
1028+
}
1029+
#endif
10161030
if (attr == MP_QSTR___bases__) {
10171031
if (self == &mp_type_object) {
10181032
dest[0] = mp_const_empty_tuple;

tests/basics/class_dict.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
class Foo:
3+
self.a = 1
4+
self.b = "bar"
5+
6+
if not hasattr(Foo, "__dict__"):
7+
print("SKIP")
8+
raise SystemExit
9+
10+
print(Foo.__dict__ == {'a': 1, 'b': 'bar'})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy