On Thu, Jun 20, 2019 at 10:28 PM nate lust <natel...@linux.com> wrote: > > There is nothing more humbling than sending nonsense out to an entire mailing > list. It will teach me to stop an process my steam of consciousness > critically instead of just firing off a message. You were right that I was > not at all considering how python variables must of course work (both > assignment and lookup). Your message was quite thorough, I hope it was out of > a sense of teaching and not frustration. If the latter I am sorry to be the > cause. > > Thinking about things the right way around, I dug in to the interpreter an > hacked something up to add an assignment overload dunder method. A diff > against python 3.7 can be found here: > https://gist.github.com/natelust/063f60a4c2c8ad0d5293aa0eb1ce9514 > > There are other supporting changes, but the core idea is just that the type > struct (typeobject.c) now has one more field (I called it tp_setself) that > under normal circumstances is just 0. Then in the insertdict function > (dictobject.c) (which does just what it sounds), post looking up the old > value, and pre setting anything new, I added a block to check if tp_setself > is defined on the type of the old value. If it is this means the user defined > a __setself__ method on a type and it is called with the value that was to be > assigned causing whatever side effects the user chose for that function, and > the rest of insertdict body is never run. > > This is by no means pull request level of coding (Plenty of clean up, tests > to run, and to see how this works in nestings etc.), but is a proof of > concept. Out of a sense of transparency I will make note that there is an > issue when __repr__ is called in the interpreter. Tt is causing insertdict to > be called which could lead to an infinite recursion. This is reason for the > if old_value != value check in the diff, as it prevents the recursion. > However it would probably be better to not let the user build infinite cycles > anyway. > > This has a runtime penalty (on all executed python sets) of a type stuct > field lookup, a pointer offset on the struct (looking up the tp_setself > field), and a comparison to null on all python code, which is to say not much > at all. A runtime side effect is that the type struct grows in size by the > width of a pointer. As other type fields have been added for things like > async, I am guessing this is not a large issue. > > There is of course a runtime cost added to whatever is done in the > __setself__ method, but that is something a user would expect since they are > adding the method. > > The question about confusion reading code with this behavior still remains, > i.e. this might be very surprising using a library that defines this. On this > point I see the argument both ways and not really have an opinion. In some > ways it is surprising that you can overload other operators but not > assignment (like people might be familiar with from other languages). People > don't seem to have an expectation that + always works the same way on any > given library code, however python has long had the standing assignment > behavior so it could be a surprise to have a change now. > > Below is how this runs on the python I have built on my system with the above > patch: > > Python 3.7.4rc1+ (heads/3.7-dirty:7b2a913bd8, Jun 20 2019, 14:43:10) > [GCC 7.4.0] on linux > Type "help", "copyright", "credits" or "license" for more information. > >>> class Foo: > def __init__(self, o): > self.o = o > def __setself__(self, v): > self.v = v > > >>> f = Foo(5) > >>> print(f) > <__main__.Foo object at 0x7f486bb8d300> > >>> print(f.o) > 5 > >>> print(f.v) > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > AttributeError: 'Foo' object has no attribute 'v' > >>> f = "hello world" > >>> print(f.v) > hello world > >>> print(f) > <__main__.Foo object at 0x7f486bb8d300> > >>> > >>> class Bar: > def __init__(self, o): > self.o = o > > >>> > >>> b = Bar(5) > >>> print(b) > <__main__.Bar object at 0x7f486bb8d6f0> > >>> print(b.o) > 5 > >>> b = "hello world" > >>> print(b) > hello world > >>>
WoW ... I like it :) and this patch is going to be a good tutorial for me to further dive into CPython. This is more than 10K words to say "it is possible at least". Thanks nate. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/NWC56FBRMQ3NFRUPIDXVO7DG6VVFPJJF/ Code of Conduct: http://python.org/psf/codeofconduct/