diff --git a/py/builtin.c b/py/builtin.c
index 1e022becbd0e3025077d589bd981ce44bec5e8b3..fe9757fdf34eb754d6ba47ee6a014d3f75281255 100644
--- a/py/builtin.c
+++ b/py/builtin.c
@@ -152,7 +152,6 @@ STATIC mp_obj_t mp_builtin_dir(uint n_args, const mp_obj_t *args) {
     // TODO make this function more general and less of a hack
 
     mp_map_t *map = NULL;
-    const mp_method_t *meth = NULL;
     if (n_args == 0) {
         // make a list of names in the local name space
         map = rt_locals_get();
@@ -164,9 +163,6 @@ STATIC mp_obj_t mp_builtin_dir(uint n_args, const mp_obj_t *args) {
         } else if (type->locals_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(type->locals_dict, &dict_type)) {
             map = mp_obj_dict_get_map(type->locals_dict);
         }
-        if (type->methods != NULL) {
-            meth = type->methods;
-        }
     }
 
     mp_obj_t dir = mp_obj_new_list(0, NULL);
@@ -177,11 +173,7 @@ STATIC mp_obj_t mp_builtin_dir(uint n_args, const mp_obj_t *args) {
             }
         }
     }
-    if (meth != NULL) {
-        for (; meth->name != MP_QSTR_NULL; meth++) {
-            mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(meth->name));
-        }
-    }
+
     return dir;
 }
 
diff --git a/py/map.h b/py/map.h
index afebfda6ec2428a701c33946d99425ef1ef20385..692ae92e3858f5b4fbe5cebc6e0ef51d4e06b527 100644
--- a/py/map.h
+++ b/py/map.h
@@ -24,6 +24,11 @@ typedef enum _mp_map_lookup_kind_t {
     MP_MAP_LOOKUP_FIRST = 4,
 } mp_map_lookup_kind_t;
 
+typedef struct _mp_obj_dict_t {
+    mp_obj_base_t base;
+    mp_map_t map;
+} mp_obj_dict_t;
+
 int get_doubling_prime_greater_or_equal_to(int x);
 void mp_map_init(mp_map_t *map, int n);
 void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table);
diff --git a/py/obj.h b/py/obj.h
index 1c22e956b88f97750eada72b1ccd691002fbb91c..12f8cabf48455565efa27b48098cff8de615265a 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -59,6 +59,21 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
 #define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, n_args_max, (mp_fun_var_t)fun_name)
 #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, (mp_fun_kw_t)fun_name)
 
+// This macro is used to define constant dict objects
+// You can put "static" in front of the definition to make it local
+
+#define MP_DEFINE_CONST_DICT(dict_name, table_name) \
+    const mp_obj_dict_t dict_name = { \
+        .base = {&dict_type}, \
+        .map = { \
+            .all_keys_are_qstrs = 1, \
+            .table_is_fixed_array = 1, \
+            .used = sizeof(table_name) / sizeof(mp_map_elem_t), \
+            .alloc = sizeof(table_name) / sizeof(mp_map_elem_t), \
+            .table = (mp_map_elem_t*)table_name, \
+        }, \
+    }
+
 // These macros are used to declare and define constant staticmethond and classmethod objects
 // You can put "static" in front of the definitions to make them local
 
@@ -160,8 +175,6 @@ struct _mp_obj_type_t {
     mp_buffer_p_t buffer_p;
     mp_stream_p_t stream_p;
 
-    const mp_method_t *methods;
-
     // these are for dynamically created types (classes)
     mp_obj_t bases_tuple;
     mp_obj_t locals_dict;
diff --git a/py/objarray.c b/py/objarray.c
index 9d795c1bffce0442a27753785d7d21453713bdcd..eed21d9463b37d19fd5b60cd6ea31bc77b457366 100644
--- a/py/objarray.c
+++ b/py/objarray.c
@@ -149,11 +149,12 @@ STATIC machine_int_t array_get_buffer(mp_obj_t o_in, buffer_info_t *bufinfo, int
     return 0;
 }
 
-STATIC const mp_method_t array_type_methods[] = {
-    { MP_QSTR_append, &array_append_obj },
-    { MP_QSTR_NULL, NULL }, // end-of-list sentinel
+STATIC const mp_map_elem_t array_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_append), (mp_obj_t)&array_append_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);
+
 const mp_obj_type_t mp_type_array = {
     { &mp_type_type },
     .name = MP_QSTR_array,
@@ -163,8 +164,8 @@ const mp_obj_type_t mp_type_array = {
     .unary_op = array_unary_op,
     .binary_op = array_binary_op,
     .store_item = array_store_item,
-    .methods = array_type_methods,
     .buffer_p = { .get_buffer = array_get_buffer },
+    .locals_dict = (mp_obj_t)&array_locals_dict,
 };
 
 STATIC mp_obj_array_t *array_new(char typecode, uint n) {
diff --git a/py/objdict.c b/py/objdict.c
index 14d120a779d947764dc80b009bb94c0decd1c386..190d901055c9bc27ef0504d2e7a986ca843e14cb 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -7,14 +7,9 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime0.h"
 #include "runtime.h"
-#include "map.h"
-
-typedef struct _mp_obj_dict_t {
-    mp_obj_base_t base;
-    mp_map_t map;
-} mp_obj_dict_t;
 
 STATIC mp_obj_t mp_obj_new_dict_iterator(mp_obj_dict_t *dict, int cur);
 STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in);
@@ -343,7 +338,6 @@ STATIC const mp_obj_type_t dict_view_it_type = {
     { &mp_type_type },
     .name = MP_QSTR_iterator,
     .iternext = dict_view_it_iternext,
-    .methods = NULL,            /* set operations still to come */
 };
 
 STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in) {
@@ -423,21 +417,22 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values);
 /******************************************************************************/
 /* dict constructors & public C API                                           */
 
-STATIC const mp_method_t dict_type_methods[] = {
-    { MP_QSTR_clear, &dict_clear_obj },
-    { MP_QSTR_copy, &dict_copy_obj },
-    { MP_QSTR_fromkeys, &dict_fromkeys_obj },
-    { MP_QSTR_get, &dict_get_obj },
-    { MP_QSTR_items, &dict_items_obj },
-    { MP_QSTR_keys, &dict_keys_obj },
-    { MP_QSTR_pop, &dict_pop_obj },
-    { MP_QSTR_popitem, &dict_popitem_obj },
-    { MP_QSTR_setdefault, &dict_setdefault_obj },
-    { MP_QSTR_update, &dict_update_obj },
-    { MP_QSTR_values, &dict_values_obj },
-    { MP_QSTR_NULL, NULL }, // end-of-list sentinel
+STATIC const mp_map_elem_t dict_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&dict_clear_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)&dict_copy_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_fromkeys), (mp_obj_t)&dict_fromkeys_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_get), (mp_obj_t)&dict_get_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_items), (mp_obj_t)&dict_items_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_keys), (mp_obj_t)&dict_keys_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_pop), (mp_obj_t)&dict_pop_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_popitem), (mp_obj_t)&dict_popitem_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_setdefault), (mp_obj_t)&dict_setdefault_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_update), (mp_obj_t)&dict_update_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_values), (mp_obj_t)&dict_values_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(dict_locals_dict, dict_locals_dict_table);
+
 const mp_obj_type_t dict_type = {
     { &mp_type_type },
     .name = MP_QSTR_dict,
@@ -446,7 +441,7 @@ const mp_obj_type_t dict_type = {
     .unary_op = dict_unary_op,
     .binary_op = dict_binary_op,
     .getiter = dict_getiter,
-    .methods = dict_type_methods,
+    .locals_dict = (mp_obj_t)&dict_locals_dict,
 };
 
 mp_obj_t mp_obj_new_dict(int n_args) {
diff --git a/py/objgenerator.c b/py/objgenerator.c
index f440923ee6bf3b88e6e66e1d0632b6d7414ff780..9f609ce509e6895202057e6b6d40320d328dfa00 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -6,6 +6,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "bc.h"
 #include "objgenerator.h"
@@ -192,20 +193,21 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) {
 
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close);
 
-STATIC const mp_method_t gen_type_methods[] = {
-    { MP_QSTR_close, &gen_instance_close_obj },
-    { MP_QSTR_send, &gen_instance_send_obj },
-    { MP_QSTR_throw, &gen_instance_throw_obj },
-    { MP_QSTR_NULL, NULL }, // end-of-list sentinel
+STATIC const mp_map_elem_t gen_instance_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&gen_instance_close_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&gen_instance_send_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_throw), (mp_obj_t)&gen_instance_throw_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table);
+
 const mp_obj_type_t gen_instance_type = {
     { &mp_type_type },
     .name = MP_QSTR_generator,
     .print = gen_instance_print,
     .getiter = gen_instance_getiter,
     .iternext = gen_instance_iternext,
-    .methods = gen_type_methods,
+    .locals_dict = (mp_obj_t)&gen_instance_locals_dict,
 };
 
 mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args) {
diff --git a/py/objlist.c b/py/objlist.c
index afc4f3cf855b1cda98de2b55f226ee3af602be78..6677a8f8ce89c19f172a3b6f4dd556539358578d 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -328,21 +328,22 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(list_remove_obj, list_remove);
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(list_reverse_obj, list_reverse);
 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(list_sort_obj, 0, mp_obj_list_sort);
 
-STATIC const mp_method_t list_type_methods[] = {
-    { MP_QSTR_append, &list_append_obj },
-    { MP_QSTR_clear, &list_clear_obj },
-    { MP_QSTR_copy, &list_copy_obj },
-    { MP_QSTR_count, &list_count_obj },
-    { MP_QSTR_extend, &list_extend_obj },
-    { MP_QSTR_index, &list_index_obj },
-    { MP_QSTR_insert, &list_insert_obj },
-    { MP_QSTR_pop, &list_pop_obj },
-    { MP_QSTR_remove, &list_remove_obj },
-    { MP_QSTR_reverse, &list_reverse_obj },
-    { MP_QSTR_sort, &list_sort_obj },
-    { MP_QSTR_NULL, NULL }, // end-of-list sentinel
+STATIC const mp_map_elem_t list_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_append), (mp_obj_t)&list_append_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&list_clear_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)&list_copy_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_count), (mp_obj_t)&list_count_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_extend), (mp_obj_t)&list_extend_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_index), (mp_obj_t)&list_index_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_insert), (mp_obj_t)&list_insert_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_pop), (mp_obj_t)&list_pop_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&list_remove_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_reverse), (mp_obj_t)&list_reverse_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_sort), (mp_obj_t)&list_sort_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(list_locals_dict, list_locals_dict_table);
+
 const mp_obj_type_t list_type = {
     { &mp_type_type },
     .name = MP_QSTR_list,
@@ -351,7 +352,7 @@ const mp_obj_type_t list_type = {
     .unary_op = list_unary_op,
     .binary_op = list_binary_op,
     .getiter = list_getiter,
-    .methods = list_type_methods,
+    .locals_dict = (mp_obj_t)&list_locals_dict,
 };
 
 STATIC mp_obj_list_t *list_new(uint n) {
diff --git a/py/objset.c b/py/objset.c
index 250d1324722d7991903f24ecf219179e91b52bcc..e6071e5385e3fb82e79be27e83e3a75a30f66762 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -423,27 +423,28 @@ STATIC mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
 /* set constructors & public C API                                            */
 
 
-STATIC const mp_method_t set_type_methods[] = {
-    { MP_QSTR_add, &set_add_obj },
-    { MP_QSTR_clear, &set_clear_obj },
-    { MP_QSTR_copy, &set_copy_obj },
-    { MP_QSTR_discard, &set_discard_obj },
-    { MP_QSTR_difference, &set_diff_obj },
-    { MP_QSTR_difference_update, &set_diff_update_obj },
-    { MP_QSTR_intersection, &set_intersect_obj },
-    { MP_QSTR_intersection_update, &set_intersect_update_obj },
-    { MP_QSTR_isdisjoint, &set_isdisjoint_obj },
-    { MP_QSTR_issubset, &set_issubset_obj },
-    { MP_QSTR_issuperset, &set_issuperset_obj },
-    { MP_QSTR_pop, &set_pop_obj },
-    { MP_QSTR_remove, &set_remove_obj },
-    { MP_QSTR_symmetric_difference, &set_symmetric_difference_obj },
-    { MP_QSTR_symmetric_difference_update, &set_symmetric_difference_update_obj },
-    { MP_QSTR_union, &set_union_obj },
-    { MP_QSTR_update, &set_update_obj },
-    { MP_QSTR_NULL, NULL }, // end-of-list sentinel
+STATIC const mp_map_elem_t set_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_add), (mp_obj_t)&set_add_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&set_clear_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_copy), (mp_obj_t)&set_copy_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_discard), (mp_obj_t)&set_discard_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_difference), (mp_obj_t)&set_diff_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_difference_update), (mp_obj_t)&set_diff_update_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_intersection), (mp_obj_t)&set_intersect_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_intersection_update), (mp_obj_t)&set_intersect_update_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_isdisjoint), (mp_obj_t)&set_isdisjoint_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_issubset), (mp_obj_t)&set_issubset_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_issuperset), (mp_obj_t)&set_issuperset_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_pop), (mp_obj_t)&set_pop_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&set_remove_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_symmetric_difference), (mp_obj_t)&set_symmetric_difference_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_symmetric_difference_update), (mp_obj_t)&set_symmetric_difference_update_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_union), (mp_obj_t)&set_union_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_update), (mp_obj_t)&set_update_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(set_locals_dict, set_locals_dict_table);
+
 const mp_obj_type_t set_type = {
     { &mp_type_type },
     .name = MP_QSTR_set,
@@ -451,7 +452,7 @@ const mp_obj_type_t set_type = {
     .make_new = set_make_new,
     .binary_op = set_binary_op,
     .getiter = set_getiter,
-    .methods = set_type_methods,
+    .locals_dict = (mp_obj_t)&set_locals_dict,
 };
 
 mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items) {
diff --git a/py/objstr.c b/py/objstr.c
index d8b391d4463a26ed13cab5630b3730a43b1f417f..6812516b4356c05ee210ed417e8755a6db26737f 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -7,6 +7,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime0.h"
 #include "runtime.h"
 
@@ -693,21 +694,22 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
 
-STATIC const mp_method_t str_type_methods[] = {
-    { MP_QSTR_find, &str_find_obj },
-    { MP_QSTR_rfind, &str_rfind_obj },
-    { MP_QSTR_join, &str_join_obj },
-    { MP_QSTR_split, &str_split_obj },
-    { MP_QSTR_startswith, &str_startswith_obj },
-    { MP_QSTR_strip, &str_strip_obj },
-    { MP_QSTR_format, &str_format_obj },
-    { MP_QSTR_replace, &str_replace_obj },
-    { MP_QSTR_count, &str_count_obj },
-    { MP_QSTR_partition, &str_partition_obj },
-    { MP_QSTR_rpartition, &str_rpartition_obj },
-    { MP_QSTR_NULL, NULL }, // end-of-list sentinel
+STATIC const mp_map_elem_t str_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&str_find_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_rfind), (mp_obj_t)&str_rfind_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_join), (mp_obj_t)&str_join_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_split), (mp_obj_t)&str_split_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_startswith), (mp_obj_t)&str_startswith_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_strip), (mp_obj_t)&str_strip_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&str_format_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_replace), (mp_obj_t)&str_replace_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_count), (mp_obj_t)&str_count_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_partition), (mp_obj_t)&str_partition_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_rpartition), (mp_obj_t)&str_rpartition_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table);
+
 const mp_obj_type_t str_type = {
     { &mp_type_type },
     .name = MP_QSTR_str,
@@ -715,8 +717,8 @@ const mp_obj_type_t str_type = {
     .make_new = str_make_new,
     .binary_op = str_binary_op,
     .getiter = mp_obj_new_str_iterator,
-    .methods = str_type_methods,
     .buffer_p = { .get_buffer = str_get_buffer },
+    .locals_dict = (mp_obj_t)&str_locals_dict,
 };
 
 // Reuses most of methods from str
@@ -727,7 +729,7 @@ const mp_obj_type_t bytes_type = {
     .make_new = bytes_make_new,
     .binary_op = str_binary_op,
     .getiter = mp_obj_new_bytes_iterator,
-    .methods = str_type_methods,
+    .locals_dict = (mp_obj_t)&str_locals_dict,
 };
 
 // the zero-length bytes
diff --git a/py/objtuple.c b/py/objtuple.c
index 334cf0562e55e62dec61912f20c06cef4450bbf8..eb3d8259a6cffa2d583545bcd2ad2f06138013bd 100644
--- a/py/objtuple.c
+++ b/py/objtuple.c
@@ -6,6 +6,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime0.h"
 #include "runtime.h"
 #include "objtuple.h"
@@ -165,12 +166,13 @@ STATIC mp_obj_t tuple_index(uint n_args, const mp_obj_t *args) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(tuple_index_obj, 2, 4, tuple_index);
 
-STATIC const mp_method_t tuple_type_methods[] = {
-    { MP_QSTR_count, &tuple_count_obj },
-    { MP_QSTR_index, &tuple_index_obj },
-    { MP_QSTR_NULL, NULL }, // end-of-list sentinel
+STATIC const mp_map_elem_t tuple_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_count), (mp_obj_t)&tuple_count_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_index), (mp_obj_t)&tuple_index_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(tuple_locals_dict, tuple_locals_dict_table);
+
 const mp_obj_type_t tuple_type = {
     { &mp_type_type },
     .name = MP_QSTR_tuple,
@@ -179,7 +181,7 @@ const mp_obj_type_t tuple_type = {
     .unary_op = tuple_unary_op,
     .binary_op = tuple_binary_op,
     .getiter = tuple_getiter,
-    .methods = tuple_type_methods,
+    .locals_dict = (mp_obj_t)&tuple_locals_dict,
 };
 
 // the zero-length tuple
diff --git a/py/objtype.c b/py/objtype.c
index ceec78ea3719a2e34211588a5a7297a871ec0caa..f0ded1aff906788b064edb3c13ff476654272c55 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -38,6 +38,7 @@ STATIC mp_obj_t mp_obj_class_lookup(const mp_obj_type_t *type, qstr attr) {
             if (elem != NULL) {
                 return elem->value;
             }
+            /*
         } else if (type->methods != NULL) {
             // search methods (the const set of methods)
 
@@ -46,6 +47,7 @@ STATIC mp_obj_t mp_obj_class_lookup(const mp_obj_type_t *type, qstr attr) {
                     return (mp_obj_t)meth->fun;
                 }
             }
+            */
         }
 
         // attribute not found, keep searching base classes
diff --git a/py/runtime.c b/py/runtime.c
index 247a78fe1a2e09c5d0d891e7d5e26dbbfbe2b868..1f4a524b700f89e3745f296c5e0974556c473d2a 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -845,25 +845,24 @@ STATIC void rt_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) {
         } else if (type->load_attr == NULL) {
             // generic method lookup if type didn't provide a specific one
             // this is a lookup in the object (ie not class or type)
-            const mp_method_t *meth = type->methods;
-            if (meth != NULL) {
-                for (; meth->name != MP_QSTR_NULL; meth++) {
-                    if (meth->name == attr) {
-                        // check if the methods are functions, static or class methods
-                        // see http://docs.python.org/3.3/howto/descriptor.html
-                        if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_staticmethod)) {
-                            // return just the function
-                            dest[0] = ((mp_obj_static_class_method_t*)meth->fun)->fun;
-                        } else if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_classmethod)) {
-                            // return a bound method, with self being the type of this object
-                            dest[0] = ((mp_obj_static_class_method_t*)meth->fun)->fun;
-                            dest[1] = mp_obj_get_type(base);
-                        } else {
-                            // return a bound method, with self being this object
-                            dest[0] = (mp_obj_t)meth->fun;
-                            dest[1] = base;
-                        }
-                        break;
+            if (type->locals_dict != NULL) {
+                assert(MP_OBJ_IS_TYPE(type->locals_dict, &dict_type)); // Micro Python restriction, for now
+                mp_map_t *locals_map = mp_obj_dict_get_map(type->locals_dict);
+                mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
+                if (elem != NULL) {
+                    // check if the methods are functions, static or class methods
+                    // see http://docs.python.org/3.3/howto/descriptor.html
+                    if (MP_OBJ_IS_TYPE(elem->value, &mp_type_staticmethod)) {
+                        // return just the function
+                        dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
+                    } else if (MP_OBJ_IS_TYPE(elem->value, &mp_type_classmethod)) {
+                        // return a bound method, with self being the type of this object
+                        dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
+                        dest[1] = mp_obj_get_type(base);
+                    } else {
+                        // return a bound method, with self being this object
+                        dest[0] = (mp_obj_t)elem->value;
+                        dest[1] = base;
                     }
                 }
             }
diff --git a/stm/adc.c b/stm/adc.c
index 07067875792c56983764b54d75778ae73a17a2c8..acdaa97dae275200fa305428ae786c3ad0ef05ca 100644
--- a/stm/adc.c
+++ b/stm/adc.c
@@ -6,6 +6,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "adc.h"
 
 /* ADC defintions */
@@ -323,19 +324,20 @@ static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_t
 static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
 static MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref);
 
-static const mp_method_t adc_all_methods[] = {
-    { MP_QSTR_read_channel,   &adc_all_read_channel_obj},
-    { MP_QSTR_read_core_temp, &adc_all_read_core_temp_obj},
-    { MP_QSTR_read_core_vbat, &adc_all_read_core_vbat_obj},
-    { MP_QSTR_read_core_vref, &adc_all_read_core_vref_obj},
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t adc_all_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_channel), (mp_obj_t)  &adc_all_read_channel_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_temp), (mp_obj_t)&adc_all_read_core_temp_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vbat), (mp_obj_t)&adc_all_read_core_vbat_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vref), (mp_obj_t)&adc_all_read_core_vref_obj},
 };
 
+STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table);
+
 static const mp_obj_type_t adc_all_type = {
     { &mp_type_type },
     .name = MP_QSTR_ADC,
     .print = adc_all_print,
-    .methods = adc_all_methods,
+    .locals_dict = (mp_obj_t)&adc_all_locals_dict,
 };
 
 mp_obj_t pyb_ADC_all(mp_obj_t resolution) {
@@ -380,16 +382,17 @@ static mp_obj_t adc_read(mp_obj_t self_in) {
 
 static MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
 
-static const mp_method_t adc_methods[] = {
-    { MP_QSTR_read, &adc_read_obj},
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t adc_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
 };
 
+STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
+
 static const mp_obj_type_t adc_type = {
     { &mp_type_type },
     .name = MP_QSTR_ADC,
     .print = adc_print,
-    .methods = adc_methods,
+    .locals_dict = (mp_obj_t)&adc_locals_dict,
 };
 
 mp_obj_t pyb_ADC(mp_obj_t pin_name_obj) {
diff --git a/stm/audio.c b/stm/audio.c
index 5523087ec889959842ea26de546d1a205fe4501c..22f635a5b70f6f063d1c9c4bbedf15f74019af99 100644
--- a/stm/audio.c
+++ b/stm/audio.c
@@ -193,18 +193,19 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_audio_triangle_obj, pyb_audio_triangle);
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_audio_dac_obj, pyb_audio_dac);
 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_audio_dma_obj, 3, pyb_audio_dma);
 
-STATIC const mp_method_t pyb_audio_methods[] = {
-    { MP_QSTR_noise, &pyb_audio_noise_obj },
-    { MP_QSTR_triangle, &pyb_audio_triangle_obj },
-    { MP_QSTR_dac, &pyb_audio_dac_obj },
-    { MP_QSTR_dma, &pyb_audio_dma_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t pyb_audio_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_noise), (mp_obj_t)&pyb_audio_noise_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_triangle), (mp_obj_t)&pyb_audio_triangle_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_dac), (mp_obj_t)&pyb_audio_dac_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_dma), (mp_obj_t)&pyb_audio_dma_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(pyb_audio_locals_dict, pyb_audio_locals_dict_table);
+
 STATIC const mp_obj_type_t pyb_audio_type = {
     { &mp_type_type },
     .name = MP_QSTR_,
-    .methods = pyb_audio_methods,
+    .locals_dict = (mp_obj_t)&pyb_audio_locals_dict,
 };
 
 STATIC const pyb_audio_t pyb_audio_channel_1 = {{&pyb_audio_type}, DAC_Channel_1, DMA1_Stream5};
diff --git a/stm/exti.c b/stm/exti.c
index 1484b622eca99177bb4a613083990d4aac84bc41..5b8c694a88790b4f4e8a642489ef91202b25c6f1 100644
--- a/stm/exti.c
+++ b/stm/exti.c
@@ -9,6 +9,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "nlr.h"
 
@@ -226,14 +227,15 @@ static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_enable_obj,  exti_obj_enable);
 static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_disable_obj, exti_obj_disable);
 static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_swint_obj,   exti_obj_swint);
 
-static const mp_method_t exti_methods[] = {
-    { MP_QSTR_line,  &exti_obj_line_obj },
-    { MP_QSTR_enable,  &exti_obj_enable_obj },
-    { MP_QSTR_disable,  &exti_obj_disable_obj },
-    { MP_QSTR_swint,  &exti_obj_swint_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t exti_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_line), (mp_obj_t) &exti_obj_line_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t) &exti_obj_enable_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t) &exti_obj_disable_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_swint), (mp_obj_t) &exti_obj_swint_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(exti_locals_dict, exti_locals_dict_table);
+
 static mp_obj_t exti_regs(void) {
     printf("EXTI_IMR   %08lx\n", EXTI->IMR);
     printf("EXTI_EMR   %08lx\n", EXTI->EMR);
@@ -317,7 +319,7 @@ const mp_obj_type_t exti_obj_type = {
     { &exti_meta_obj_type },
     .name = MP_QSTR_Exti,
     .print = exti_obj_print,
-    .methods = exti_methods,
+    .locals_dict = (mp_obj_t)&exti_locals_dict,
 };
 
 void exti_init(void) {
diff --git a/stm/file.c b/stm/file.c
index e56b05faeb2c65200c61fc65292d989eada41077..208ce804b43a7ba50c8b0651e0d5361e054584f2 100644
--- a/stm/file.c
+++ b/stm/file.c
@@ -5,6 +5,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "file.h"
 #include "ff.h"
 
@@ -52,18 +53,19 @@ static MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close);
 
 // TODO gc hook to close the file if not already closed
 
-static const mp_method_t file_methods[] = {
-    { MP_QSTR_read, &file_obj_read_obj },
-    { MP_QSTR_write, &file_obj_write_obj },
-    { MP_QSTR_close, &file_obj_close_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t file_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&file_obj_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&file_obj_write_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&file_obj_close_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(file_locals_dict, file_locals_dict_table);
+
 static const mp_obj_type_t file_obj_type = {
     { &mp_type_type },
     .name = MP_QSTR_File,
     .print = file_obj_print,
-    .methods = file_methods,
+    .locals_dict = (mp_obj_t)&file_locals_dict,
 };
 
 mp_obj_t pyb_io_open(mp_obj_t o_filename, mp_obj_t o_mode) {
diff --git a/stm/i2c.c b/stm/i2c.c
index 4d726c9593d0aaec032ab2f6a92ffdfda85e0cba..b3d06df1478c9b2ed4268db6c0d76ffcbbdbe49e 100644
--- a/stm/i2c.c
+++ b/stm/i2c.c
@@ -7,6 +7,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 
 typedef enum {
     PYB_I2C_1 = 0,
@@ -325,20 +326,21 @@ static MP_DEFINE_CONST_FUN_OBJ_1(i2c_obj_read_obj, i2c_obj_read);
 static MP_DEFINE_CONST_FUN_OBJ_1(i2c_obj_readAndStop_obj, i2c_obj_readAndStop);
 static MP_DEFINE_CONST_FUN_OBJ_1(i2c_obj_stop_obj, i2c_obj_stop);
 
-static const mp_method_t i2c_methods[] = {
-    { MP_QSTR_start, &i2c_obj_start_obj },
-    { MP_QSTR_write, &i2c_obj_write_obj },
-    { MP_QSTR_read, &i2c_obj_read_obj },
-    { MP_QSTR_readAndStop, &i2c_obj_readAndStop_obj },
-    { MP_QSTR_stop, &i2c_obj_stop_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t i2c_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_start), (mp_obj_t)&i2c_obj_start_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&i2c_obj_write_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&i2c_obj_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_readAndStop), (mp_obj_t)&i2c_obj_readAndStop_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&i2c_obj_stop_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(i2c_locals_dict, i2c_locals_dict_table);
+
 static const mp_obj_type_t i2c_obj_type = {
     { &mp_type_type },
     .name = MP_QSTR_I2C,
     .print = i2c_obj_print,
-    .methods = i2c_methods,
+    .locals_dict = (mp_obj_t)&i2c_locals_dict,
 };
 
 // create the I2C object
diff --git a/stm/led.c b/stm/led.c
index ceae49ca73c3604b5cff7a6017295593d060bde7..bfb98f9b5868b74916b93993705b072f5ce4d2a8 100644
--- a/stm/led.c
+++ b/stm/led.c
@@ -6,6 +6,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "led.h"
 #include "pin.h"
 #include "build/pins.h"
@@ -109,18 +110,19 @@ static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on);
 static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off);
 static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle);
 
-static const mp_method_t led_methods[] = {
-    { MP_QSTR_on, &led_obj_on_obj },
-    { MP_QSTR_off, &led_obj_off_obj },
-    { MP_QSTR_toggle, &led_obj_toggle_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t led_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)&led_obj_on_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&led_obj_off_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_toggle), (mp_obj_t)&led_obj_toggle_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table);
+
 static const mp_obj_type_t led_obj_type = {
     { &mp_type_type },
     .name = MP_QSTR_Led,
     .print = led_obj_print,
-    .methods = led_methods,
+    .locals_dict = (mp_obj_t)&led_locals_dict,
 };
 
 static mp_obj_t pyb_Led(mp_obj_t led_id) {
diff --git a/stm/pin.c b/stm/pin.c
index 4bdbfcb16b2ec8ac3ff00ef86fc16157bd6eb4fc..6b97d2f7c1c26fa9faec77ec862810e8d454cf2a 100644
--- a/stm/pin.c
+++ b/stm/pin.c
@@ -7,6 +7,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 
 #include "pin.h"
 
@@ -34,18 +35,19 @@ static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_name_obj, pin_obj_name);
 static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_port_obj, pin_obj_port);
 static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_pin_obj, pin_obj_pin);
 
-static const mp_method_t pin_methods[] = {
-    { MP_QSTR_name, &pin_obj_name_obj },
-    { MP_QSTR_port, &pin_obj_port_obj },
-    { MP_QSTR_pin, &pin_obj_pin_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t pin_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_name), (mp_obj_t)&pin_obj_name_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_port), (mp_obj_t)&pin_obj_port_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_pin), (mp_obj_t)&pin_obj_pin_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table);
+
 const mp_obj_type_t pin_obj_type = {
     { &mp_type_type },
     .name = MP_QSTR_Pin,
     .print = pin_obj_print,
-    .methods = pin_methods,
+    .locals_dict = (mp_obj_t)&pin_locals_dict,
 };
 
 void pin_af_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
diff --git a/stm/sdcard.c b/stm/sdcard.c
index 0898c42a5751afa909c5771a425681782b08793e..566fe70d53a92da9a1f178e91cccc39ceada770d 100644
--- a/stm/sdcard.c
+++ b/stm/sdcard.c
@@ -9,6 +9,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "sdcard.h"
 
@@ -194,17 +195,18 @@ static mp_obj_t sd_read(mp_obj_t self, mp_obj_t block_num) {
 
 static MP_DEFINE_CONST_FUN_OBJ_2(sd_read_obj, sd_read);
 
-static const mp_method_t sdcard_methods[] = {
-    { MP_QSTR_present, &sd_present_obj },
-    { MP_QSTR_power, &sd_power_obj },
-    { MP_QSTR_read, &sd_read_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t sdcard_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_present), (mp_obj_t)&sd_present_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_power), (mp_obj_t)&sd_power_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&sd_read_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(sdcard_locals_dict, sdcard_locals_dict_table);
+
 static const mp_obj_type_t sdcard_type = {
     { &mp_type_type },
     .name = MP_QSTR_SDcard,
-    .methods = sdcard_methods,
+    .locals_dict = (mp_obj_t)&sdcard_locals_dict,
 };
 
 const mp_obj_base_t pyb_sdcard_obj = {&sdcard_type};
diff --git a/stm/servo.c b/stm/servo.c
index cd6370b126642827b67472b2774e86ca465fa60f..176081e1ad06a4f85e6d86dd55cbc3b2ae21f3f6 100644
--- a/stm/servo.c
+++ b/stm/servo.c
@@ -8,6 +8,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "servo.h"
 
 // PWM
@@ -146,16 +147,17 @@ STATIC mp_obj_t servo_obj_angle(mp_obj_t self_in, mp_obj_t angle) {
 
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(servo_obj_angle_obj, servo_obj_angle);
 
-STATIC const mp_method_t servo_methods[] = {
-    { MP_QSTR_angle, &servo_obj_angle_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t servo_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_angle), (mp_obj_t)&servo_obj_angle_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(servo_locals_dict, servo_locals_dict_table);
+
 STATIC const mp_obj_type_t servo_obj_type = {
     { &mp_type_type },
     .name = MP_QSTR_Servo,
     .print = servo_obj_print,
-    .methods = servo_methods,
+    .locals_dict = (mp_obj_t)&servo_locals_dict,
 };
 
 STATIC mp_obj_t pyb_Servo(mp_obj_t servo_id) {
diff --git a/stm/usart.c b/stm/usart.c
index 41a53c2fe89ef543db6685682c90c23d541aaca3..27c40fd841885ab67261fbdc4ec3825b03a6a529 100644
--- a/stm/usart.c
+++ b/stm/usart.c
@@ -7,6 +7,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "usart.h"
 
 pyb_usart_t pyb_usart_global_debug = PYB_USART_NONE;
@@ -235,19 +236,20 @@ static MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_rx_char_obj, usart_obj_rx_char);
 static MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_char_obj, usart_obj_tx_char);
 static MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_str_obj, usart_obj_tx_str);
 
-STATIC const mp_method_t usart_methods[] = {
-    { MP_QSTR_status, &usart_obj_status_obj },
-    { MP_QSTR_recv_chr, &usart_obj_rx_char_obj },
-    { MP_QSTR_send_chr, &usart_obj_tx_char_obj },
-    { MP_QSTR_send, &usart_obj_tx_str_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t usart_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&usart_obj_status_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_recv_chr), (mp_obj_t)&usart_obj_rx_char_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_send_chr), (mp_obj_t)&usart_obj_tx_char_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&usart_obj_tx_str_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(usart_locals_dict, usart_locals_dict_table);
+
 STATIC const mp_obj_type_t usart_obj_type = {
     { &mp_type_type },
     .name = MP_QSTR_Usart,
     .print = usart_obj_print,
-    .methods = usart_methods,
+    .locals_dict = (mp_obj_t)&usart_locals_dict,
 };
 
 STATIC mp_obj_t pyb_Usart(mp_obj_t usart_id, mp_obj_t baudrate) {
diff --git a/stmhal/accel.c b/stmhal/accel.c
index 15782419b7683d0156a4e22deebafdede084af8a..f4fd5469bd9fb23b47f592742d77905bbbacbb02 100644
--- a/stmhal/accel.c
+++ b/stmhal/accel.c
@@ -8,6 +8,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "i2c.h"
 #include "accel.h"
@@ -158,20 +159,21 @@ STATIC mp_obj_t pyb_accel_write(mp_obj_t self_in, mp_obj_t reg, mp_obj_t val) {
 
 MP_DEFINE_CONST_FUN_OBJ_3(pyb_accel_write_obj, pyb_accel_write);
 
-STATIC const mp_method_t pyb_accel_methods[] = {
-    { MP_QSTR_x, &pyb_accel_x_obj },
-    { MP_QSTR_y, &pyb_accel_y_obj },
-    { MP_QSTR_z, &pyb_accel_z_obj },
-    { MP_QSTR_tilt, &pyb_accel_tilt_obj },
-    { MP_QSTR_filtered_xyz, &pyb_accel_filtered_xyz_obj },
-    { MP_QSTR_read, &pyb_accel_read_obj },
-    { MP_QSTR_write, &pyb_accel_write_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t pyb_accel_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_x), (mp_obj_t)&pyb_accel_x_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_y), (mp_obj_t)&pyb_accel_y_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_z), (mp_obj_t)&pyb_accel_z_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_tilt), (mp_obj_t)&pyb_accel_tilt_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_filtered_xyz), (mp_obj_t)&pyb_accel_filtered_xyz_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&pyb_accel_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_accel_write_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(pyb_accel_locals_dict, pyb_accel_locals_dict_table);
+
 const mp_obj_type_t pyb_accel_type = {
     { &mp_type_type },
     .name = MP_QSTR_Accel,
     .make_new = pyb_accel_make_new,
-    .methods = pyb_accel_methods,
+    .locals_dict = (mp_obj_t)&pyb_accel_locals_dict,
 };
diff --git a/stmhal/adc.c b/stmhal/adc.c
index 7d0d3da99b911222f273e1caaf05df02d77fb570..f05e7823dd4f4a57314db14fd51e90f5318a5eb7 100644
--- a/stmhal/adc.c
+++ b/stmhal/adc.c
@@ -7,6 +7,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "adc.h"
 #include "pin.h"
 #include "build/pins.h"
@@ -163,17 +164,18 @@ STATIC mp_obj_t adc_read(mp_obj_t self_in) {
 
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
 
-STATIC const mp_method_t adc_methods[] = {
-    { MP_QSTR_read, &adc_read_obj},
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t adc_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
 };
 
+STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
+
 const mp_obj_type_t pyb_adc_type = {
     { &mp_type_type },
     .name = MP_QSTR_ADC,
     .print = adc_print,
     .make_new = adc_make_new,
-    .methods = adc_methods,
+    .locals_dict = (mp_obj_t)&adc_locals_dict,
 };
 
 /******************************************************************************/
@@ -320,19 +322,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_t
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref);
 
-STATIC const mp_method_t adc_all_methods[] = {
-    { MP_QSTR_read_channel,   &adc_all_read_channel_obj},
-    { MP_QSTR_read_core_temp, &adc_all_read_core_temp_obj},
-    { MP_QSTR_read_core_vbat, &adc_all_read_core_vbat_obj},
-    { MP_QSTR_read_core_vref, &adc_all_read_core_vref_obj},
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t adc_all_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_channel), (mp_obj_t)  &adc_all_read_channel_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_temp), (mp_obj_t)&adc_all_read_core_temp_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vbat), (mp_obj_t)&adc_all_read_core_vbat_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vref), (mp_obj_t)&adc_all_read_core_vref_obj},
 };
 
+STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table);
+
 STATIC const mp_obj_type_t adc_all_type = {
     { &mp_type_type },
     .name = MP_QSTR_ADC,
     .print = adc_all_print,
-    .methods = adc_all_methods,
+    .locals_dict = (mp_obj_t)&adc_all_locals_dict,
 };
 
 STATIC mp_obj_t pyb_ADC_all(mp_obj_t resolution) {
diff --git a/stmhal/dac.c b/stmhal/dac.c
index bc86e07bdf5793f1e8df5a9495018e94380fcc05..caf8beeecbc45e2bf559a2cab96422ec2625462d 100644
--- a/stmhal/dac.c
+++ b/stmhal/dac.c
@@ -260,20 +260,21 @@ mp_obj_t pyb_dac_dma(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
 
 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_dac_dma_obj, 3, pyb_dac_dma);
 
-STATIC const mp_method_t pyb_dac_methods[] = {
-    { MP_QSTR_noise, &pyb_dac_noise_obj },
-    { MP_QSTR_triangle, &pyb_dac_triangle_obj },
-    { MP_QSTR_write, &pyb_dac_write_obj },
-    { MP_QSTR_dma, &pyb_dac_dma_obj },
+STATIC const mp_map_elem_t pyb_dac_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_noise), (mp_obj_t)&pyb_dac_noise_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_triangle), (mp_obj_t)&pyb_dac_triangle_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_dac_write_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_dma), (mp_obj_t)&pyb_dac_dma_obj },
     // TODO add function that does double buffering:
     //  dma2(freq, buf1, buf2, callback)
     //  where callback is called when the buffer has been drained
-    { MP_QSTR_NULL, NULL },
 };
 
+STATIC MP_DEFINE_CONST_DICT(pyb_dac_locals_dict, pyb_dac_locals_dict_table);
+
 const mp_obj_type_t pyb_dac_type = {
     { &mp_type_type },
     .name = MP_QSTR_DAC,
     .make_new = pyb_dac_make_new,
-    .methods = pyb_dac_methods,
+    .locals_dict = (mp_obj_t)&pyb_dac_locals_dict,
 };
diff --git a/stmhal/exti.c b/stmhal/exti.c
index 41f8e378a8ae2f7adf522eb6bd056413e41955b0..fddeeba84a6b01c30d2478360c29bda054b5dcf7 100644
--- a/stmhal/exti.c
+++ b/stmhal/exti.c
@@ -8,6 +8,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "nlr.h"
 
@@ -228,14 +229,15 @@ static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_enable_obj,  exti_obj_enable);
 static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_disable_obj, exti_obj_disable);
 static MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_swint_obj,   exti_obj_swint);
 
-static const mp_method_t exti_methods[] = {
-    { MP_QSTR_line,  &exti_obj_line_obj },
-    { MP_QSTR_enable,  &exti_obj_enable_obj },
-    { MP_QSTR_disable,  &exti_obj_disable_obj },
-    { MP_QSTR_swint,  &exti_obj_swint_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t exti_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_line), (mp_obj_t) &exti_obj_line_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t) &exti_obj_enable_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t) &exti_obj_disable_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_swint), (mp_obj_t) &exti_obj_swint_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(exti_locals_dict, exti_locals_dict_table);
+
 static mp_obj_t exti_regs(void) {
     printf("EXTI_IMR   %08lx\n", EXTI->IMR);
     printf("EXTI_EMR   %08lx\n", EXTI->EMR);
@@ -320,7 +322,7 @@ const mp_obj_type_t exti_obj_type = {
     { &exti_meta_obj_type },
     .name = MP_QSTR_Exti,
     .print = exti_obj_print,
-    .methods = exti_methods,
+    .locals_dict = (mp_obj_t)&exti_locals_dict,
 };
 
 void exti_init(void) {
diff --git a/stmhal/file.c b/stmhal/file.c
index 210d26803d45abdaa7b3633efd8ebfd7f1f45607..219d58ddb3747155bd2de9417d04f47b094a13d2 100644
--- a/stmhal/file.c
+++ b/stmhal/file.c
@@ -4,6 +4,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "file.h"
 #include "ff.h"
 
@@ -51,18 +52,19 @@ static MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close);
 
 // TODO gc hook to close the file if not already closed
 
-static const mp_method_t file_methods[] = {
-    { MP_QSTR_read, &file_obj_read_obj },
-    { MP_QSTR_write, &file_obj_write_obj },
-    { MP_QSTR_close, &file_obj_close_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t file_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&file_obj_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&file_obj_write_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&file_obj_close_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(file_locals_dict, file_locals_dict_table);
+
 static const mp_obj_type_t file_obj_type = {
     { &mp_type_type },
     .name = MP_QSTR_File,
     .print = file_obj_print,
-    .methods = file_methods,
+    .locals_dict = (mp_obj_t)&file_locals_dict,
 };
 
 STATIC mp_obj_t pyb_io_open(mp_obj_t o_filename, mp_obj_t o_mode) {
diff --git a/stmhal/help.c b/stmhal/help.c
index a1c81c824fbbd6ebca4692f0cc2459ad57c4624b..7dc7226b2cb0dfc158f92d1314d2fd30ac421f89 100644
--- a/stmhal/help.c
+++ b/stmhal/help.c
@@ -72,12 +72,6 @@ STATIC mp_obj_t pyb_help(uint n_args, const mp_obj_t *args) {
                 }
             }
         }
-
-        if (type->methods != NULL) {
-            for (const mp_method_t *meth = type->methods; meth->name != MP_QSTR_NULL; meth++) {
-                pyb_help_print_info_about_object(MP_OBJ_NEW_QSTR(meth->name), (mp_obj_t)meth->fun);
-            }
-        }
     }
 
     return mp_const_none;
diff --git a/stmhal/i2c.c b/stmhal/i2c.c
index 91cb17b33ed59bfe71c398f4a693e691dec6609f..9bf7799f4066b5fed852a9b70bb8568446decd18 100644
--- a/stmhal/i2c.c
+++ b/stmhal/i2c.c
@@ -8,6 +8,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "i2c.h"
 
@@ -169,16 +170,17 @@ STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args) {
 
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_i2c_mem_write_obj, 4, 4, pyb_i2c_mem_write);
 
-STATIC const mp_method_t pyb_i2c_methods[] = {
-    { MP_QSTR_is_ready, &pyb_i2c_is_ready_obj },
-    { MP_QSTR_mem_read, &pyb_i2c_mem_read_obj },
-    { MP_QSTR_mem_write, &pyb_i2c_mem_write_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_is_ready), (mp_obj_t)&pyb_i2c_is_ready_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_mem_read), (mp_obj_t)&pyb_i2c_mem_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_mem_write), (mp_obj_t)&pyb_i2c_mem_write_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
+
 const mp_obj_type_t pyb_i2c_type = {
     { &mp_type_type },
     .name = MP_QSTR_I2C,
     .make_new = pyb_i2c_make_new,
-    .methods = pyb_i2c_methods,
+    .locals_dict = (mp_obj_t)&pyb_i2c_locals_dict,
 };
diff --git a/stmhal/led.c b/stmhal/led.c
index 989ce3897f38d4ce22ee89c06f596873c37e7dcc..13dc81d18ebd466fc273d564e7ef2e472c24df15 100644
--- a/stmhal/led.c
+++ b/stmhal/led.c
@@ -8,6 +8,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "led.h"
 #include "pin.h"
@@ -256,18 +257,19 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off);
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle);
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(led_obj_intensity_obj, 1, 2, led_obj_intensity);
 
-STATIC const mp_method_t led_methods[] = {
-    { MP_QSTR_on, &led_obj_on_obj },
-    { MP_QSTR_off, &led_obj_off_obj },
-    { MP_QSTR_toggle, &led_obj_toggle_obj },
-    { MP_QSTR_intensity, &led_obj_intensity_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t led_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)&led_obj_on_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&led_obj_off_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_toggle), (mp_obj_t)&led_obj_toggle_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_intensity), (mp_obj_t)&led_obj_intensity_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table);
+
 const mp_obj_type_t pyb_led_type = {
     { &mp_type_type },
     .name = MP_QSTR_Led,
     .print = led_obj_print,
     .make_new = led_obj_make_new,
-    .methods = led_methods,
+    .locals_dict = (mp_obj_t)&led_locals_dict,
 };
diff --git a/stmhal/sdcard.c b/stmhal/sdcard.c
index 5392b02731e462ca90a9358c9c0d4ad5674ea13a..5620aef5b4b179b5fb4f2add9fa57e2c91fd39d9 100644
--- a/stmhal/sdcard.c
+++ b/stmhal/sdcard.c
@@ -6,6 +6,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "sdcard.h"
 
@@ -232,17 +233,18 @@ static mp_obj_t sd_read(mp_obj_t self, mp_obj_t block_num) {
 
 static MP_DEFINE_CONST_FUN_OBJ_2(sd_read_obj, sd_read);
 
-static const mp_method_t sdcard_methods[] = {
-    { MP_QSTR_present, &sd_present_obj },
-    { MP_QSTR_power, &sd_power_obj },
-    { MP_QSTR_read, &sd_read_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t sdcard_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_present), (mp_obj_t)&sd_present_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_power), (mp_obj_t)&sd_power_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&sd_read_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(sdcard_locals_dict, sdcard_locals_dict_table);
+
 static const mp_obj_type_t sdcard_type = {
     { &mp_type_type },
     .name = MP_QSTR_SDcard,
-    .methods = sdcard_methods,
+    .locals_dict = (mp_obj_t)&sdcard_locals_dict,
 };
 
 const mp_obj_base_t pyb_sdcard_obj = {&sdcard_type};
diff --git a/stmhal/servo.c b/stmhal/servo.c
index 17722dc6cdfd5902aa304bbb31e95c4549c160d8..ad33db75c242cca09d2025855240d8839d9546b1 100644
--- a/stmhal/servo.c
+++ b/stmhal/servo.c
@@ -7,6 +7,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "servo.h"
 
 // this servo driver uses hardware PWM to drive servos on PA0, PA1, PA2, PA3 = X1, X2, X3, X4
@@ -205,15 +206,16 @@ STATIC mp_obj_t pyb_servo_angle(uint n_args, const mp_obj_t *args) {
 
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_angle_obj, 1, 3, pyb_servo_angle);
 
-STATIC const mp_method_t pyb_servo_methods[] = {
-    { MP_QSTR_angle, &pyb_servo_angle_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t pyb_servo_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_angle), (mp_obj_t)&pyb_servo_angle_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(pyb_servo_locals_dict, pyb_servo_locals_dict_table);
+
 const mp_obj_type_t pyb_servo_type = {
     { &mp_type_type },
     .name = MP_QSTR_Servo,
     .print = pyb_servo_print,
     .make_new = pyb_servo_make_new,
-    .methods = pyb_servo_methods,
+    .locals_dict = (mp_obj_t)&pyb_servo_locals_dict,
 };
diff --git a/stmhal/usart.c b/stmhal/usart.c
index d3a54f9d845446e995cc7e217f4d73194890a328..daf8a9e1fc945808c438fd473aa77526ba552b69 100644
--- a/stmhal/usart.c
+++ b/stmhal/usart.c
@@ -8,6 +8,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "usart.h"
 
 struct _pyb_usart_obj_t {
@@ -209,18 +210,19 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_rx_char_obj, usart_obj_rx_char);
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_char_obj, usart_obj_tx_char);
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_str_obj, usart_obj_tx_str);
 
-STATIC const mp_method_t usart_methods[] = {
-    { MP_QSTR_status, &usart_obj_status_obj },
-    { MP_QSTR_recv_chr, &usart_obj_rx_char_obj },
-    { MP_QSTR_send_chr, &usart_obj_tx_char_obj },
-    { MP_QSTR_send, &usart_obj_tx_str_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t usart_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&usart_obj_status_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_recv_chr), (mp_obj_t)&usart_obj_rx_char_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_send_chr), (mp_obj_t)&usart_obj_tx_char_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&usart_obj_tx_str_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(usart_locals_dict, usart_locals_dict_table);
+
 const mp_obj_type_t pyb_usart_type = {
     { &mp_type_type },
     .name = MP_QSTR_Usart,
     .print = usart_obj_print,
     .make_new = usart_obj_make_new,
-    .methods = usart_methods,
+    .locals_dict = (mp_obj_t)&usart_locals_dict,
 };
diff --git a/unix/ffi.c b/unix/ffi.c
index ef9c6ea9d2976e38b62a399628de1dc9a8bf1fe8..a25e54b54a0139869497665bf514f3c6aa2f577d 100644
--- a/unix/ffi.c
+++ b/unix/ffi.c
@@ -9,6 +9,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "binary.h"
 
@@ -216,19 +217,20 @@ static mp_obj_t ffimod_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
     return o;
 }
 
-static const mp_method_t ffimod_type_methods[] = {
-        { "func", &ffimod_func_obj },
-        { "var", &ffimod_var_obj },
-        { "close", &ffimod_close_obj },
-        { NULL, NULL },
+static const mp_map_elem_t ffimod_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_func), (mp_obj_t) &ffimod_func_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_var), (mp_obj_t) &ffimod_var_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t) &ffimod_close_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(ffimod_locals_dict, ffimod_locals_dict_table);
+
 static const mp_obj_type_t ffimod_type = {
     { &mp_type_type },
     .name = MP_QSTR_ffimod,
     .print = ffimod_print,
     .make_new = ffimod_make_new,
-    .methods = ffimod_type_methods,
+    .locals_dict = (mp_obj_t)&ffimod_locals_dict,
 };
 
 // FFI function
diff --git a/unix/file.c b/unix/file.c
index d711ace4f18faccc0097b9027b040f37cf1c4024..f037b6f7eaf8d5f7d96b6b16ab0eb33c69c309f5 100644
--- a/unix/file.c
+++ b/unix/file.c
@@ -9,6 +9,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "runtime.h"
 #include "stream.h"
 
@@ -105,16 +106,17 @@ static mp_obj_t fdfile_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
     return fdfile_new(fd);
 }
 
-static const mp_method_t rawfile_type_methods[] = {
-    { MP_QSTR_fileno, &fdfile_fileno_obj },
-    { MP_QSTR_read, &mp_stream_read_obj },
-    { MP_QSTR_readall, &mp_stream_readall_obj },
-    { MP_QSTR_readline, &mp_stream_unbuffered_readline_obj},
-    { MP_QSTR_write, &mp_stream_write_obj },
-    { MP_QSTR_close, &fdfile_close_obj },
-    { MP_QSTR_NULL, NULL },
+STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_fileno), (mp_obj_t)&fdfile_fileno_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&fdfile_close_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
+
 static const mp_obj_type_t rawfile_type = {
     { &mp_type_type },
     .name = MP_QSTR_io_dot_FileIO,
@@ -126,7 +128,7 @@ static const mp_obj_type_t rawfile_type = {
         .read = fdfile_read,
         .write = fdfile_write,
     },
-    .methods = rawfile_type_methods,
+    .locals_dict = (mp_obj_t)&rawfile_locals_dict,
 };
 
 // Factory function for I/O stream classes
diff --git a/unix/main.c b/unix/main.c
index e8452fd8cc86ea8c3d6b1732ddd60b8cb8b01f9a..6b25988759656a543a50baa30cdbc26cfac3ee77 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -15,6 +15,7 @@
 #include "lexerunix.h"
 #include "parse.h"
 #include "obj.h"
+#include "map.h"
 #include "parsehelper.h"
 #include "compile.h"
 #include "runtime0.h"
@@ -191,17 +192,18 @@ static mp_obj_t test_set(mp_obj_t self_in, mp_obj_t arg) {
 static MP_DEFINE_CONST_FUN_OBJ_1(test_get_obj, test_get);
 static MP_DEFINE_CONST_FUN_OBJ_2(test_set_obj, test_set);
 
-static const mp_method_t test_methods[] = {
-    { MP_QSTR_get, &test_get_obj },
-    { MP_QSTR_set, &test_set_obj },
-    { MP_QSTR_NULL, NULL },
+static const mp_map_elem_t test_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_get), (mp_obj_t)&test_get_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&test_set_obj },
 };
 
+STATIC MP_DEFINE_CONST_DICT(test_locals_dict, test_locals_dict_table);
+
 static const mp_obj_type_t test_type = {
     { &mp_type_type },
     .name = MP_QSTR_Test,
     .print = test_print,
-    .methods = test_methods,
+    .locals_dict = (mp_obj_t)&test_locals_dict,
 };
 
 mp_obj_t test_obj_new(int value) {
diff --git a/unix/socket.c b/unix/socket.c
index 85e59b2848de09e54f8707d83281a7d47c27ce7b..31255442825cf2109ed17a9f701cdb10bb07e668 100644
--- a/unix/socket.c
+++ b/unix/socket.c
@@ -15,6 +15,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "map.h"
 #include "objtuple.h"
 #include "objarray.h"
 #include "runtime.h"
@@ -217,28 +218,29 @@ static mp_obj_t socket_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
     return socket_new(fd);
 }
 
-static const mp_method_t microsocket_type_methods[] = {
-    { MP_QSTR_fileno, &socket_fileno_obj },
-    { MP_QSTR_makefile, &mp_identity_obj },
-    { MP_QSTR_read, &mp_stream_read_obj },
-    { MP_QSTR_readall, &mp_stream_readall_obj },
-    { MP_QSTR_readline, &mp_stream_unbuffered_readline_obj},
-    { MP_QSTR_write, &mp_stream_write_obj },
-    { MP_QSTR_connect, &socket_connect_obj },
-    { MP_QSTR_bind, &socket_bind_obj },
-    { MP_QSTR_listen, &socket_listen_obj },
-    { MP_QSTR_accept, &socket_accept_obj },
-    { MP_QSTR_recv, &socket_recv_obj },
-    { MP_QSTR_send, &socket_send_obj },
-    { MP_QSTR_setsockopt, &socket_setsockopt_obj },
-    { MP_QSTR_close, &socket_close_obj },
+static const mp_map_elem_t microsocket_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_fileno), (mp_obj_t)&socket_fileno_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&mp_identity_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
 #if MICROPY_SOCKET_EXTRA
-    { MP_QSTR_recv, &mp_stream_read_obj },
-    { MP_QSTR_send, &mp_stream_write_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&mp_stream_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&mp_stream_write_obj },
 #endif
-    { MP_QSTR_NULL, NULL },
 };
 
+STATIC MP_DEFINE_CONST_DICT(microsocket_locals_dict, microsocket_locals_dict_table);
+
 static const mp_obj_type_t microsocket_type = {
     { &mp_type_type },
     .name = MP_QSTR_socket,
@@ -250,7 +252,7 @@ static const mp_obj_type_t microsocket_type = {
         .read = socket_read,
         .write = socket_write,
     },
-    .methods = microsocket_type_methods,
+    .locals_dict = (mp_obj_t)&microsocket_locals_dict,
 };
 
 static mp_obj_t mod_socket_htons(mp_obj_t arg) {