Search code examples
pythonoopname-mangling

How does name mangling work when accessing `__attr` inside the class?


I know what data mangling in Python is in general and what its purpose is, but there is one subtle aspect I would like to clarify.

Let's say we have a class:

class P:
    def __init__(self):
        self.x = 10
        self.__y = 20
    
    def get_y(self):
        return self.__y

p = P(); p.__dict__ now has the key _P__y so this is where the data mangling occurred.

My question is, though, how do we access the attribute inside get_y given that there is no __y key in __dict__?

I have a faint guess that there is some magic going on in __getattribute__ and then, after getting AttributeError, in __getattr__.

This confusion makes me think that I don't have a 100% understanding of what __init__ does under the hood.


Solution

  • Name mangling is performed by the compiler, not at runtime. Specifically, in CPython, all the generated byte code assumes that the name of the attribute is _P__y, whenever __y occurs as an attribute in the class statement or a function defined inside the class statement.

    >>> import dis
    >>> dis.dis(P)
    Disassembly of __init__:
      3           0 LOAD_CONST               1 (10)
                  2 LOAD_FAST                0 (self)
                  4 STORE_ATTR               0 (x)
    
      4           6 LOAD_CONST               2 (20)
                  8 LOAD_FAST                0 (self)
                 10 STORE_ATTR               1 (_P__y)
                 12 LOAD_CONST               0 (None)
                 14 RETURN_VALUE
    
    Disassembly of get_y:
      7           0 LOAD_FAST                0 (self)
                  2 LOAD_ATTR                0 (_P__y)
                  4 RETURN_VALUE