Page 1 of 1

Assigning to an objects __dict__: TypeError

Posted: Fri Oct 09, 2020 6:26 pm
by scy
Hi there!

I’m currently trying out several things to work around MicroPython not supporting __setattr__ on ESP32. One of them requires writing to an instance’s __dict__. However, neither updating an existing value nor creating a new one works:

Code: Select all

class Foo:
    def __init__(self):
        self.a = 123

f = Foo()

print(f.__dict__)  # {'a': 123}
print(type(f.__dict__))  # <class 'dict'>
f.__dict__['a'] = 456  # "TypeError:"
f.__dict__['b'] = 456  # "TypeError:"
The resulting TypeError has no associated message. Searching the forums brought me to a thread where someone tried to subclass dict and got the same message, but that’s not quite what I’m trying to do here.

Why am I not using setattr() instead? Because the attribute I’m trying to set is using a custom descriptor (that’s my workaround for the missing __setattr__), and using setattr() would lead to infinite recursion.

If you’re interested, my descriptor attempt is designed to try to manually invoke the __setattr__ method. It basically works like this:

Code: Select all

class ViaSetAttr:

    def __init__(self, name):
        self.name = name

    def __get__(self, obj, type=None):
        return obj.__dict__[self.name]

    def __set__(self, obj, value):
        obj.__setattr__(self.name, value)

class Foo:

    def __setattr__(self, name, value):
        # This shall basically behave like cPython's __setattr__.
        # However, since it's not called by MicroPython, the special descriptor calls it manually.

# This programmatically creates new attributes on the Foo class and saves me
# some repetitive typing. It's not the issue.
for name in ['some', 'properties', 'that', 'should', 'go', 'through', 'setattr']:
    setattr(Foo, name, ViaSetAttr(name))
And yes, I might instead use @property and define getters and setters, but since I need to only catch the write operations, not the reads, this will lead to quite some overhead that I had hoped to avoid.

Is there a way I can write to __dict__? If not, is there a workaround that will not lead to infinite recursion with my custom descriptor?

Re: Assigning to an objects __dict__: TypeError

Posted: Sun Oct 11, 2020 4:12 pm
by pythoncoder
I assume you've read the differences doc. That discusses descriptors. Adafruit make extensive use of descriptors in their CircuitPython libraries so you may get some ideas from there.

The differences doc also has this statement:
Instance __dict__ support is optional (disabled in many ports) and read-only, so foo.__dict__['bar'] = 23 or foo.__dict__.update({'bar': 23}) does not work. #1757 #2139

Re: Assigning to an objects __dict__: TypeError

Posted: Sun Oct 11, 2020 5:46 pm
by scy
pythoncoder wrote:
Sun Oct 11, 2020 4:12 pm
I assume you've read the differences doc.
Oh! No, in fact I did not, thanks for pointing me to it. I’ve just read the MicroPython differences from CPython page in the docs on the website, didn’t even know that there was additional content in the GitHub wiki.

That definitely explains it, and it has links to the relevant issues, thank you very much :)

Since __setattr__ support looks like it’s coming soon and I’ve rewritten my code to use properties anyway (which bloats up the number of lines, but works), I’ll just wait for that to arrive.

Re: Assigning to an objects __dict__: TypeError

Posted: Mon Oct 12, 2020 10:54 am
by pythoncoder
I don't know if your code is performance critical, but properties are deprecated for high performance applications because they are near the bottom of the search tree. Of course in many cases this is not an issue.

Re: Assigning to an objects __dict__: TypeError

Posted: Tue Oct 20, 2020 6:25 am
by jimmo
scy wrote:
Sun Oct 11, 2020 5:46 pm
Since __setattr__ support looks like it’s coming soon and I’ve rewritten my code to use properties anyway (which bloats up the number of lines, but works), I’ll just wait for that to arrive.
I don't think there's any __setattr__ changes currently in the pipeline? However there was a big improvement in v1.13 (released last month, but the code was added in December last year -- see https://github.com/micropython/micropython/pull/5404)

Re: Assigning to an objects __dict__: TypeError

Posted: Tue Oct 20, 2020 8:37 am
by scy
jimmo wrote:
Tue Oct 20, 2020 6:25 am
I don't think there's any __setattr__ changes currently in the pipeline?
I don’t know, but #6427 unix/mpconfigport: Enable MICROPY_PY_DELATTR_SETATTR looks to me as if the flag to enable the current __setattr__ implementation, that is currently only active for the STM32 port, might be switched on for other ports soon.

And yes, of course building your own version with that flag enabled is an option already, but it’s more inconvenient for most of us.

Re: Assigning to an objects __dict__: TypeError

Posted: Tue Oct 20, 2020 10:18 pm
by jimmo
scy wrote:
Tue Oct 20, 2020 8:37 am
I don’t know, but #6427 unix/mpconfigport: Enable MICROPY_PY_DELATTR_SETATTR looks to me as if the flag to enable the current __setattr__ implementation, that is currently only active for the STM32 port, might be switched on for other ports soon.
Ah cool, sorry I didn't realise this wasn't enabled everywhere. That PR is now merged. ESP32 should be enabled shortly too (#6560).