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.pyThe 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.