8000 py: Implement __dict__ for class by touilleMan · Pull Request #2843 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

py: Implement __dict__ for class #2843

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

touilleMan
Copy link

Based on #1757 PR

@dpgeorge
Copy link
Member
dpgeorge commented Feb 7, 2017

Thanks for the PR.

Please can you give some background on why you needed this feature?

Also, it would be much simpler to just return self->locals_dict directly, instead of making a copy.

@touilleMan
Copy link
Author

I'm using MicroPython to provide Python as a script language for the Godot game engine.

Basically Godot engine works with a gui where you drop nodes, which you can connect to a script class.

from godot import exposed, export
from godot.bindings import Node2D

@exposed
class Player(Node2D):
    name = export(str, default=Samuel”)

    def _ready(self):
        pass

Loading this module will result from the Godot point of view of making available the Player class, which says the extended node should provide a name field in the gui editor for the user to customize this value.

To implement this, I should iterate over all the class fields and retrieve the ones which are instance of export.
It's quite possible I'll end up doing this at C level anyway, but given this is a (C)Python feature and it is already available for the class instances, I guess it's good to improve MicroPython compatibility anyway :-)

Also, it would be much simpler to just return self->locals_dict directly, instead of making a copy.

That's what instance's __dict__ implementation is doing (it is stated this way in the faq about the differences with CPython).

By the way I fixed my patch to support the case where locals_dict is defined to NULL.

@pfalcon
Copy link
Contributor
pfalcon commented Feb 7, 2017

Thanks for the detailed description of your usecase, it's really helpful to know how people use MicroPython! And thanks for selecting MicroPython as your embedding engine, that's one of the area we'd like to have more traction, but lack resources. But we'd really like people selecting us as their Python implementation not because we're doing it like CPython, but because we're doing it differently (because otherwise, using CPython is the most obvious way, and we won't be able to compete with CPython even if we could, but we don't have any agenda like that). This is described in more detail in https://github.com/micropython/micropython/wiki/ContributorGuidelines , and should be insightful read.

To implement this, I should iterate over all the class fields and retrieve the ones which are instance of export.

You can, without any patching and fully compatibly with CPython:

class Foo:

    a = 1
    b = 2.0

    def meth(self):
        pass


print(dir(Foo))
for f in dir(Foo):
    val = getattr(Foo, f)
    print(f, val, type(val))

@touilleMan
Copy link
Author

And thanks for selecting MicroPython as your embedding engine

Thanks for writting MicroPython then 😃

You can, without any patching and fully compatibly with CPython:

Problem is using dir will get me not only the class attributes but also it parents' (in my usecase parents' exported attribute are already provided by the inheritance so I don't want to shadow them and mess the binding)

@touilleMan
Copy link
Author

btw I don't understand why travis flag the build is considered as failed given the tests seems to have passed...

@stinos
Copy link
Contributor
stinos commented Feb 11, 2017

Check the build log in Travis:

../py/objtype.c: In function ‘type_attr’:

../py/objtype.c:833:35: error: comparison between pointer and integer [-Werror]

             if (self->locals_dict != MP_OBJ_NULL) {

                                   ^

../py/objtype.c:834:17: error: passing argument 1 of ‘mp_obj_dict_get_map’ makes integer from pointer without a cast [-Werror]

                 mp_map_t *map = mp_obj_dict_get_map(self->locals_dict);

                 ^

In file included from ../py/objtype.h:29:0,

                 from ../py/objtype.c:34:

../py/obj.h:741:11: note: expected ‘mp_obj_t’ but argument is of type ‘struct _mp_obj_dict_t *’

 mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in);

           ^

cc1: all warnings being treated as errors

make[1]: *** [build-nanbox/py/objtype.o] Error 1

make[1]: Leaving directory `/home/travis/build/micropython/micropython/unix'

make: *** [nanbox] Error 2

make: Leaving directory `/home/travis/build/micropython/micropython/unix'

The command "make -C unix nanbox" exited with 2.

@touilleMan
Copy link
Author

@stinos thanks for the help !

Now everything is fine 😄

py/objtype.c Outdated
mp_obj_dict_store(attr_dict, map->table[i].key, map->table[i].value);
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't you simply do attr_dict = self->locals_dict (as long as locals_dict is not NULL)? It's not 100% the same as CPython because you can edit the returned dict and it'll modify the class, but it's much simpler.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was to stay close to #1757 code, beside not copying locals_dict means you can modify it only if it is not null, which is pretty strange from the Python point of view (e.g. sometime you can modify __dict__, sometime the modification is not taken into account...)
Anyway I've simplify my implementation to follow you're advice. I you prefer the first solution in the end, just tell me and I'll revert ;-)

@touilleMan
Copy link
Author

@dpgeorge Updated following your advices

@pfalcon
Copy link
Contributor
pfalcon commented May 3, 2017

Let me be straight: I'm -1 on this. And the reason is right there - in the submitter's own words:

Problem is using dir will get me not only the class attributes but also it parents' (in my usecase parents' exported attribute are already provided by the inheritance so I don't want to shadow them and mess the binding)

So, how __dict__ works is actually an implementation detail. Relying that it will provide only own class attributes is not well grounded. Actually, even relying that it exists is not very grounded, and MicroPython makes that very clear by not providing. One exciting area for future uPy development is making it much more efficient by making it much more static. Then there will be no any __dict__'s at all. We aren't yet there because we're fully in grunt work of closing the accidental gaps in functionality we have. But if in teh meantime we'll add features going against the future exciting things we could do with uPy, we'll simply never get there. So again, -1 (for this year, can revisit next one).

@dpgeorge
Copy link
Member
dpgeorge commented May 4, 2021

This was implemented in 28370c0

@dpgeorge dpgeorge closed this May 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0