Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method replacement at runtime not updating Private attributes

I understood how to replace methods at run time in Python by going through these links.[ Link1 , Link2 , & Link3].

When I replaced a "update_private_variable" method of class A, its getting replaced but its not updating the private variable.

import types

class A:
    def __init__(self):
        self.__private_variable = None
        self.public_variable = None

    def update_private_variable(self):
        self.__private_variable = "Updated in A"

    def update_public_variable(self):
        self.public_variable = "Updated in A"

    def get_private_variable(self):
        return self.__private_variable

class B:
    def __init__(self):
        self.__private_variable = None
        self.public_variable = None

    def update_private_variable(self):
        self.__private_variable = "Updated in B"

    def update_public_variable(self):
        self.public_variable = "Updated in B"

When calling the method without replacement:

a_instance  = A()
a_instance.update_private_variable()
print(a_instance.get_private_variable())
#prints "Updated in A"   

When calling the method after replacement:

a_instance  = A()
a_instance.update_private_variable =  types.MethodType(B.update_private_variable, a_instance)
a_instance.update_private_variable()
print(a_instance.get_private_variable()) 
#prints None

Whereas replacing and calling a method which updates public variable, works fine

a_instance  = A()
a_instance.update_public_variable = types.MethodType(B.update_public_variable, a_instance)
a_instance.update_public_variable()
print(a_instance.public_variable) 
#prints 'Updated in B'

Is there any other way to replace method of an instance at runtime, so that private attributes gets updated by invoking replaced method?

like image 360
user3262851 Avatar asked Nov 11 '15 10:11

user3262851


1 Answers

The idea behind name mangling is to protect base-class variables from being messed with by sub-classes; in other words, you shouldn't use it if you think sub-classes will have a good reason to modify those same variables.

Having said that, if you are already well down that path and are unable (or unwilling) to change it now, you can still get by, but it will be ugly and brittle:

class B:

    def update_private_variable(self):
        self._A__private_variable = "Updated in B"

As you can see, you have to prefix the name-mangled variable with an _ and the name of the class the variable is mangled in. Some of the consequences:

  • if you change the name of the class, you must change the name in all references to it
  • you cannot easily use the same update_private_variable method (since you have to somehow indicate the target class... I suppose you could pass the target class in to the method, but that's just more ugliness)
like image 164
Ethan Furman Avatar answered Sep 28 '22 09:09

Ethan Furman