Accessing private variables in an injected method - python

Question at the end

What am I trying to do:

  • Enter the property in the created object and set it instead of the variable (success)
  • The input method (let me call it METHOD) for the created object, the object did not have such a method before (success)
  • Call another public method from a property using self (success)
  • Call a method from a property using self (success)
  • Get private class variable from METHOD method with self ( failure )

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 is created (these fingerprints):

 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, the self is what it should be (modeling class), it was correctly entered, but still it does not work. If you are interested:

 print(self._Simulation__hidden) 

obviously works inside mocked_update.

Therefore, my question is: Do I have a chance to access this variable using self?

Motivation

As the question arose in the comments section:

This does not serve any real purpose; it is just an experiment.

+6
source share
1 answer

The definition of the private member name is strictly done in the class definitions. To achieve the desired goal, which should have self.__hidden translated into self._Simulation_hidden , you just need to define it in the class with the corresponding name.

For instance:

 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 correctly access the desired attribute:

 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 

Expansion

It is up to us to hard code the name of the class to which we add the ( Simulation ) method. To avoid this, we can use exec instead:

 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 that we want to add must be defined as text, it cannot be some arbitrary function object already defined. (Perhaps this can be solved using inspect to find its source, and then recompile this source in the class stanza using exec (and a reasonable choice of globals ).

+3
source

Source: https://habr.com/ru/post/1014477/


All Articles