py: Initial attempts to actually allow implementing __new__ in Python.
Caveat is that __new__ should recurse to base class __new__, and ultimately, object.__new__ is what handles instance allocation.
This commit is contained in:
parent
0c937fa25a
commit
806ea1f6ca
@ -33,6 +33,8 @@
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
|
||||
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
|
||||
typedef struct _mp_obj_object_t {
|
||||
mp_obj_base_t base;
|
||||
} mp_obj_object_t;
|
||||
@ -52,12 +54,23 @@ STATIC mp_obj_t object___init__(mp_obj_t self) {
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__);
|
||||
|
||||
STATIC mp_obj_t object___new__(mp_obj_t cls) {
|
||||
mp_obj_t o = MP_OBJ_SENTINEL;
|
||||
mp_obj_t res = instance_make_new(cls, 1, 0, &o);
|
||||
return res;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__);
|
||||
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, (const mp_obj_t)&object___new___fun_obj);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t object_locals_dict_table[] = {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&object___init___obj },
|
||||
#endif
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___new__), (mp_obj_t)&object___new___obj },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(object_locals_dict, object_locals_dict_table);
|
||||
|
12
py/objtype.c
12
py/objtype.c
@ -51,7 +51,7 @@
|
||||
|
||||
#define is_instance_type(type) ((type)->make_new == instance_make_new)
|
||||
#define is_native_type(type) ((type)->make_new != instance_make_new)
|
||||
STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
|
||||
STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_instance(mp_obj_t class, uint subobjs) {
|
||||
@ -208,7 +208,7 @@ STATIC void instance_print(void (*print)(void *env, const char *fmt, ...), void
|
||||
print(env, "<%s object at %p>", mp_obj_get_type_str(self_in), self_in);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
|
||||
mp_obj_type_t *self = self_in;
|
||||
|
||||
@ -218,6 +218,14 @@ STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, cons
|
||||
|
||||
mp_obj_instance_t *o = mp_obj_new_instance(self_in, num_native_bases);
|
||||
|
||||
// This executes only "__new__" part of obejection creation.
|
||||
// TODO: This won't work will for classes with native bases.
|
||||
// TODO: This is hack, should be resolved along the lines of
|
||||
// https://github.com/micropython/micropython/issues/606#issuecomment-43685883
|
||||
if (n_args == 1 && *args == MP_OBJ_SENTINEL) {
|
||||
return o;
|
||||
}
|
||||
|
||||
// look for __new__ function
|
||||
mp_obj_t init_fn[2] = {MP_OBJ_NULL};
|
||||
mp_obj_class_lookup(NULL, self, MP_QSTR___new__, offsetof(mp_obj_type_t, make_new), init_fn);
|
||||
|
21
tests/basics/class_new.py
Normal file
21
tests/basics/class_new.py
Normal file
@ -0,0 +1,21 @@
|
||||
class A:
|
||||
|
||||
@staticmethod
|
||||
def __new__(cls):
|
||||
print("A.__new__")
|
||||
return super(cls, A).__new__(cls)
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def meth(self):
|
||||
pass
|
||||
|
||||
#print(A.__new__)
|
||||
#print(A.__init__)
|
||||
|
||||
a = A()
|
||||
|
||||
#print(a.meth)
|
||||
#print(a.__init__)
|
||||
#print(a.__new__)
|
20
tests/basics/object_new.py
Normal file
20
tests/basics/object_new.py
Normal file
@ -0,0 +1,20 @@
|
||||
# object.__new__(cls) is the only way in Python to allocate empty
|
||||
# (non-initialized) instance of class.
|
||||
# See e.g. http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html
|
||||
# TODO: Find reference in CPython docs
|
||||
|
||||
class Foo:
|
||||
|
||||
def __init__(self):
|
||||
print("in __init__")
|
||||
self.attr = "something"
|
||||
|
||||
|
||||
o = object.__new__(Foo)
|
||||
#print(o)
|
||||
print(hasattr(o, "attr"))
|
||||
print(isinstance(o, Foo))
|
||||
o.__init__()
|
||||
#print(dir(o))
|
||||
print(hasattr(o, "attr"))
|
||||
print(o.attr)
|
Loading…
Reference in New Issue
Block a user