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*
>
_______________________________________________
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/IS5NJ7U5IXRPXOVVGQPO652X3Z7CF2QM/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to