I created a discussion topic located here https://discuss.python.org/t/a-proposal-and-implementation-to-add-assignment-and-load-overloading/1905
On Tue, Jun 25, 2019 at 6:41 PM nate lust <natel...@linux.com> wrote: > I am happy to move this discussion to where ever is appropriate. I won't > get to it in the next few hours (bed time for my kid) so if you would like > feel free to move discussion there, and I guess I can watch this email > thread for if you do. Otherwise I will do it when I am free. > Nate > > On Tue, Jun 25, 2019, 6:36 PM Juancarlo Añez <apal...@gmail.com> wrote: > >> Nate, >> >> I find this mightily interesting! I think it's worth discussing at length. >> >> Is there any chance you'll want to move the discussion to the richer >> context here? https://discuss.python.org/c/ideas >> >> Regards, >> >> On Tue, Jun 25, 2019 at 5:00 PM nate lust <natel...@linux.com> wrote: >> >>> This message is related to two previous threads, but was a sufficiently >>> evolved to warrant a new topic. >>> >>> I am proposing that two new magic methods be added to python that will >>> control assignment and loading of class >>> instances. This means that if an instance is bound to a variable name, >>> any attempts to rebind that name will >>> result in a call to the __setself__ (name negotiable) of the instance >>> already bound to that name. Likewise >>> when a class instance bound to a name is loaded by the interpreter, if >>> present, the __getself__ method of that >>> instance will be called and its result will be returned instead. I have >>> been internally calling these cloaking >>> variables as they "cloak" the underlying instance, parallelling the idea >>> of shadowing. Feel free to suggest >>> better names. >>> >>> >>> On first read, that may be surprising, but it extends a behavior pattern >>> that already exists for things like >>> properties (and generically descriptors) to object instances themselves. >>> Similar caveats and behaviors will >>> apply here as well. >>> >>> A working implementation built against python 3.7 can be found here: >>> https://github.com/natelust/cpython/tree/cloakingVars. This is not pull >>> ready quality code, but the diffs may >>> be interesting to read. >>> >>> An example for what is possible for this new behavior are instance level >>> properties as seen in the demo at the >>> end of this message. >>> >>> These changes have minimal impact on the runtime of existing code, and >>> require no modifications to existing >>> syntax other than the use of the names __setself__ and __getself__. >>> >>> A more detailed write-up with more examples can be found at >>> https://github.com/natelust/CloakingVarWriteup/blob/master/writeup.md, >>> with the example executable demo here: >>> https://github.com/natelust/CloakingVarWriteup/blob/master/examples.py >>> >>> The demos include: >>> * Variables which keep track of their assignment history, with ability >>> to rollback (possibly useful with try >>> except blocks) >>> * Variables which write out their value to disk when assigned to >>> * An implementation of context variables using only this new framework >>> (does not implement tokens, but could >>> be added) >>> * const variables that can be used to protect module level 'constants' >>> * Instance properties (reproduced below) that allow dynamically adding >>> properties >>> * An implementation of templated expression, to defer the addition of >>> many arrays to a single for loop, >>> saving possibly expensive python iterations. >>> >>> I am sure the community can come up with many more interesting ideas. >>> >>> class InstanceProperty: >>> >>> def __init__(self, wrapped, getter, setter=None): >>> self.wrapped = wrapped >>> self.getter = getter >>> self.setter = setter >>> >>> def __getself__(self): >>> return self.getter(self.wrapped) >>> >>> def __setself__(self, value): >>> if self.setter: >>> return self.setter(self.wrapped, value) >>> >>> >>> class MachineState: >>> def __init__(self): >>> self._fields = {} >>> >>> def add_input(self, name, start): >>> def getter(slf): >>> return slf._fields[name] >>> >>> def setter(slf, value): >>> ''' >>> the state of a machine part can only be above zero or below >>> 100 >>> ''' >>> if value < 0: >>> value = 0 >>> if value > 100: >>> value = 100 >>> slf._fields[name] = value >>> setter(self, start) >>> inst_prop = InstanceProperty(self, getter, setter) # noqa: F841 >>> # Need to directly assign the instance property, or decloak it. >>> setattr(self, name, getcloaked('inst_prop')) >>> >>> >>> machine = MachineState() >>> >>> for letter, start in zip(['a', 'b', 'c'], [-1, 0, 1]): >>> machine.add_input(letter, start) >>> >>> print(f"machine.a is {machine.a}") >>> print(f"machine.b is {machine.b}") >>> print(f"machine.c is {machine.c}") >>> >>> # Assign a value that is too high >>> machine.c = 200 >>> >>> print(f"machine.c is {machine.c}") >>> # Omited from this proposal but present in the linked documentation are >>> # tools for getting the underlying variables, and or rebinding them. >>> >>> On Fri, Jun 21, 2019 at 9:34 PM nate lust <natel...@linux.com> wrote: >>> >>>> It probably doesn't, this was just something I typed up on the fly, so >>>> is unlikely the end result would be what you see above if it was actually >>>> implemented. >>>> >>>> The only way around that that I can think of now would be if there was >>>> two functions, an impl_dictget that actually did the lookup that type could >>>> use (and possibly getattr and the like) which would be called in the normal >>>> dict get which would just return if the type did not define __getself__ and >>>> would call it and return the result if it did. >>>> >>>> This is not at all dissimilar to how dict setting works now >>>> >>>> On Fri, Jun 21, 2019, 9:27 PM Chris Angelico <ros...@gmail.com> wrote: >>>> >>>>> On Sat, Jun 22, 2019 at 11:19 AM nate lust <natel...@linux.com> wrote: >>>>> > Typing this out though does make me think of an interesting idea. If >>>>> there was something like __getself__ in addition to __setself__, you could >>>>> implement things like MyInt. __getself__ would look something like: >>>>> > >>>>> > class MyInt: >>>>> > def __init__(self, value): >>>>> > self.value = value >>>>> > def __getself__(self): >>>>> > return self.value >>>>> > def __setself__(self, value): >>>>> > raise ValueError("Cant set MyInt") >>>>> > x = MyInt(2) >>>>> > print(x) -> 2 >>>>> > type(x) -> MyInt >>>>> > >>>>> > Now I have not really thought through how this would work, if it >>>>> could work... >>>>> >>>>> How does print know to call getself, but type know not to? >>>>> >>>>> ChrisA >>>>> _______________________________________________ >>>>> 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/3734V62OHMJN3736PKWQ7IZ533TPM23J/ >>>>> Code of Conduct: http://python.org/psf/codeofconduct/ >>>>> >>>> >>> >>> -- >>> Nate Lust, PhD. >>> Astrophysics Dept. >>> Princeton University >>> _______________________________________________ >>> 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/TMU3MJCDVNAHMJQAJUBIHRJXXLYMWSRH/ >>> Code of Conduct: http://python.org/psf/codeofconduct/ >>> >> >> >> -- >> Juancarlo *Añez* >> > -- Nate Lust, PhD. Astrophysics Dept. Princeton University
_______________________________________________ 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/LSCLXMT46HEAFUSDAQ6HAOGCBV7UEHLM/ Code of Conduct: http://python.org/psf/codeofconduct/