Search code examples
pythonpython-3.xname-mangling

Issues with Name Mangling Example


I haven't done OOP in Python for a while, so I was doing a quick review of a few features that I'd forgotten how to use. When I arrived at name mangling in the Python Tutorial (https://docs.python.org/3/tutorial/classes.html#private-variables-and-class-local-references), I copied the example so I could play around with it, and it didn't work! I went over it again to make sure I hadn't entered any typos, and then copied and pasted it, but it told me I was passing the wrong number of arguments. I've either made an incredibly stupid mistake or something bizarre has happened. Does anyone have insight into why this happened? I'm using the latest version: 3.6.5.

Just so you can verify I entered everything correctly, here's my attempt to name mangle:

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)

def main():
    foo = MappingSubclass(['a'], ['b'])

if __name__ == "__main__":
    main()

and here is the exception raised:

Traceback (most recent call last):
  File "C:/Users/Hanni/OneDrive/Documents/Programs/Python/temp.py", line 24,     in <module>
    main()
  File "C:/Users/Hanni/OneDrive/Documents/Programs/Python/temp.py", line 21, in main
    foo = MappingSubclass(['a'], ['b'])
TypeError: __init__() takes 2 positional arguments but 3 were given

Solution

  • So every function in a class has self as the first parameter. This parameter is automatically filled as a reference to the instance of the object. When you call

    foo = MappingSubclass(['a'], ['b'])
    

    You are really calling:

    __init__(foo, ['a'], ['b'])
    

    self is not an argument that you fill in when calling class functions, it is stored as a reference to the instance of the class you are referring to

    Since you defined init to take only two arguments, self and iterable, and you provided three arguments, you get an error.