Question is at the end
What am I trying to do is :
Now, here is some code:
from types import MethodType
def add_property(instance, name, method):
cls = type(instance)
cls = type(cls.__name__, (cls,), {})
cls.__perinstance = True
instance.__class__ = cls
setattr(cls, name, property(method))
def add_variable(instance, name, init_value = 0 ):
setattr(type(instance), name, init_value)
class Simulation:
def __init__(self):
self.finished = False
self.__hidden = -10
def someloop(self):
while not self.finished:
self.__private_method()
def __private_method(self):
pass
def public_method(self):
pass
def mocked_method(self):
print(type(self))
print(self.__dict__)
print(self.__hidden)
def finished(self):
print("Execute finished",type(self))
self.public_method()
self.mocked_update()
return True
simulation = Simulation()
add_property(simulation, "finished", finished)
add_variable(simulation, "count_finished", 0)
simulation.mocked_update = MethodType(mocked_method, simulation)
simulation.someloop()
What code produced (those prints):
Execute finished '<class '__main__.Simulation'>
<class '__main__.Simulation'>
{'finished': False, '_Simulation__hidden': -10, 'mocked_update': <bound method mocked_method of <__main__.Simulation object at 0x030D2F10>>}
(...)
AttributeError: 'Simulation' object has no attribute '__hidden'
As you can see self is what it should be (simulation class), it was properly injected and yet it doesn't work. In case you are wondering :
print(self._Simulation__hidden)
obviously works inside mocked_update.
Hence my question : Is there any chance for me to access this variable using self?
Motivation
Since there was a question in the comments section:
This does not serve any real purpose, it is just an experiment.
The name mangling of "private" members is strictly done within class definitions. To achieve the desired purpose, which is to have self.__hidden
translated to self._Simulation_hidden
you need simply define it within an appropriately named class.
For example:
def make_mocked_method():
class Simulation:
# this is your code, but now its inside a class stanza so '__' will be mangled
def mocked_method(self):
print(type(self))
print(self.__dict__)
print(self.__hidden)
return Simulation.mocked_method
Now mocked_method
will access the desired attribute correctly:
simulation.mocked_update = MethodType(make_mocked_method(), simulation)
simulation.someloop()
gives:
<class '__main__.Simulation'>
{'finished': False, 'mocked_update': <bound method make_mocked_method.<locals>.Simulation.mocked_method of <__main__.Simulation object at 0x101c00a58>>, '_Simulation__hidden': -10}
-10
This relies on us hard coding the name of the class we're adding the method to (Simulation
). To avoid that we can instead use an exec
:
def make_mocked_method(cls):
txt = """class {}:
def mocked_method(self):
print(type(self))
print(self.__dict__)
print(self.__hidden)
""".format(cls.__name__)
ns = {}
exec(txt, ns)
return ns[cls.__name__].mocked_method
Unfortunately here the function we wish to add must be defined as text, it can't be some already defined arbitrary function object. (That might possibly be solved by using inspect
to find its source and then recompiling that source within a class stanza using exec
(and judicious choice of globals
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With