py/objobject: Add object.__setattr__ function.
Allows assigning attributes on class instances that implement their own __setattr__. Both object.__setattr__ and super(A, b).__setattr__ will work with this commit.
This commit is contained in:
parent
90f286465b
commit
07ccb5588c
@ -50,7 +50,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__);
|
|||||||
|
|
||||||
STATIC mp_obj_t object___new__(mp_obj_t cls) {
|
STATIC mp_obj_t object___new__(mp_obj_t cls) {
|
||||||
if (!mp_obj_is_type(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) {
|
if (!mp_obj_is_type(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) {
|
||||||
mp_raise_TypeError("__new__ arg must be a user-type");
|
mp_raise_TypeError("arg must be user-type");
|
||||||
}
|
}
|
||||||
// This executes only "__new__" part of instance creation.
|
// This executes only "__new__" part of instance creation.
|
||||||
// TODO: This won't work well for classes with native bases.
|
// TODO: This won't work well for classes with native bases.
|
||||||
@ -62,6 +62,23 @@ STATIC mp_obj_t object___new__(mp_obj_t cls) {
|
|||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__);
|
||||||
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object___new___fun_obj));
|
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object___new___fun_obj));
|
||||||
|
|
||||||
|
#if MICROPY_PY_DELATTR_SETATTR
|
||||||
|
STATIC mp_obj_t object___setattr__(mp_obj_t self_in, mp_obj_t attr, mp_obj_t value) {
|
||||||
|
if (!mp_obj_is_instance_type(mp_obj_get_type(MP_OBJ_TO_PTR(self_in)))) {
|
||||||
|
mp_raise_TypeError("arg must be user-type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mp_obj_is_str(attr)) {
|
||||||
|
mp_raise_TypeError(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
mp_map_lookup(&self->members, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_3(object___setattr___obj, object___setattr__);
|
||||||
|
#endif
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t object_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t object_locals_dict_table[] = {
|
||||||
#if MICROPY_CPYTHON_COMPAT
|
#if MICROPY_CPYTHON_COMPAT
|
||||||
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&object___init___obj) },
|
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&object___init___obj) },
|
||||||
@ -69,6 +86,9 @@ STATIC const mp_rom_map_elem_t object_locals_dict_table[] = {
|
|||||||
#if MICROPY_CPYTHON_COMPAT
|
#if MICROPY_CPYTHON_COMPAT
|
||||||
{ MP_ROM_QSTR(MP_QSTR___new__), MP_ROM_PTR(&object___new___obj) },
|
{ MP_ROM_QSTR(MP_QSTR___new__), MP_ROM_PTR(&object___new___obj) },
|
||||||
#endif
|
#endif
|
||||||
|
#if MICROPY_PY_DELATTR_SETATTR
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR___setattr__), MP_ROM_PTR(&object___setattr___obj) },
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table);
|
||||||
|
@ -1038,9 +1038,11 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t
|
|||||||
|| m_type == &mp_type_fun_builtin_1
|
|| m_type == &mp_type_fun_builtin_1
|
||||||
|| m_type == &mp_type_fun_builtin_2
|
|| m_type == &mp_type_fun_builtin_2
|
||||||
|| m_type == &mp_type_fun_builtin_3
|
|| m_type == &mp_type_fun_builtin_3
|
||||||
|| m_type == &mp_type_fun_builtin_var)) {
|
|| m_type == &mp_type_fun_builtin_var)
|
||||||
|
&& type != &mp_type_object) {
|
||||||
// we extracted a builtin method without a first argument, so we must
|
// we extracted a builtin method without a first argument, so we must
|
||||||
// wrap this function in a type checker
|
// wrap this function in a type checker
|
||||||
|
// Note that object will do its own checking so shouldn't be wrapped.
|
||||||
dest[0] = mp_obj_new_checked_fun(type, member);
|
dest[0] = mp_obj_new_checked_fun(type, member);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
@ -60,3 +60,29 @@ try:
|
|||||||
print(a.a)
|
print(a.a)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print("AttributeError")
|
print("AttributeError")
|
||||||
|
|
||||||
|
# test object.__setattr__
|
||||||
|
class C:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __setattr__(self, attr, value):
|
||||||
|
print(attr, "=", value)
|
||||||
|
|
||||||
|
c = C()
|
||||||
|
c.a = 5
|
||||||
|
try:
|
||||||
|
print(c.a)
|
||||||
|
except AttributeError:
|
||||||
|
print("AttributeError")
|
||||||
|
|
||||||
|
object.__setattr__(c, "a", 5)
|
||||||
|
super(C, c).__setattr__("b", 6)
|
||||||
|
print(c.a)
|
||||||
|
print(c.b)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# attribute name must be string
|
||||||
|
object.__setattr__(c, 5, 5)
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user