DEV Community

tutu10
tutu10

Posted on

Private copy of method in Python base class

There is an example of code in Python documentation as follows:
Mapping:
def init(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update #private copy of original update () method

In the last line of code is the comment #private copy of original update(). According to the literature, this is supposed to create a private copy of the update method in the base class in case an update method is created in a sub class.

Does anyone have any insight on the significance of doing this?

Top comments (1)

Collapse
 
rhymes profile image
rhymes

Hi tutu10, I guess you're referring at Classes -> Private variables in the tutorial.

This is the piece of Python code nicely formatted for readability:



class Mapping:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update = update   # private copy of original update() method

class MappingSubclass(Mapping):

    def update(self, keys, values):
        # provides new signature for update()
        # but does not break __init__()
        for item in zip(keys, values):
            self.items_list.append(item)

It's an odd example but I'll try to explain it.

The concept of private in Python doesn't exist, there's no keyword or encapsulation mechanism to make sure that nothing internally or externally can change the behavior of your class.

The convention, as it says in the tutorial, is to use a double underscore in front of the name of the variable to take advantage of "name mangling", in which each class transforms the __method() into _CLASSNAME__method()

In the example, the class Mapping has two update methods:

In [2]: dir(Mapping)
Out[2]:
['_Mapping__update', ...,  'update']

If you look closely the __init__ method of the base class calls __update which in reality is called _Mapping__update. Then you have a subclass that changes the behavior of update().

MappingSubclass subclass also has two update methods (one inherited from Mapping and the other redefined in its body):

In [2]: dir(MappingSubclass)
Out[2]:
['_Mapping__update', ...,  'update']

So, when MappingSubclass() is instantiated, it calls its init method, which in this case is inherited from Mapping, which calls _Mapping__update (the private version) but not update(), the public version.

It's a behavior that I've honestly never used intentionally because of how non explicit it is (and Python is all about being as explicit as possible) but it's there, in case you're building a complicated set of classes through inheritance I guess.

If it's not clear, let me know :)