diff options
author | Paul Sokolovsky <pfalcon@users.sourceforge.net> | 2014-05-22 00:32:00 +0300 |
---|---|---|
committer | Paul Sokolovsky <pfalcon@users.sourceforge.net> | 2014-05-22 00:32:00 +0300 |
commit | 806ea1f6ca2b1b50bb4634be6c39ad83d8af7e89 (patch) | |
tree | 6ff486c9fc6e76cf2e6b984d01a1f28b55432149 | |
parent | 0c937fa25a1a78274ba974a5c1546c0a01106c30 (diff) | |
download | micropython-806ea1f6ca2b1b50bb4634be6c39ad83d8af7e89.tar.gz micropython-806ea1f6ca2b1b50bb4634be6c39ad83d8af7e89.zip |
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.
-rw-r--r-- | py/objobject.c | 13 | ||||
-rw-r--r-- | py/objtype.c | 12 | ||||
-rw-r--r-- | tests/basics/class_new.py | 21 | ||||
-rw-r--r-- | tests/basics/object_new.py | 20 |
4 files changed, 64 insertions, 2 deletions
diff --git a/py/objobject.c b/py/objobject.c index 9175572b2d..7e2a35a52f 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -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); diff --git a/py/objtype.c b/py/objtype.c index 5da49a0452..1d4f90819b 100644 --- a/py/objtype.c +++ b/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); diff --git a/tests/basics/class_new.py b/tests/basics/class_new.py new file mode 100644 index 0000000000..7fedcab6c2 --- /dev/null +++ b/tests/basics/class_new.py @@ -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__) diff --git a/tests/basics/object_new.py b/tests/basics/object_new.py new file mode 100644 index 0000000000..6131ed337e --- /dev/null +++ b/tests/basics/object_new.py @@ -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) |