How to access private variables in child classes?

Here is the code:

class Animal(object): def __init__(self,age): self.age = age self.__type = 'animal' def __show(self): print('meow') def show1(self): self.__show() class Cat(Animal): def __init__(self,age): super().__init__(age) def show_type(self): print(self.__type) Kitty = Cat(3) Kitty.show1() #работает нормально - печатает meow, как и должен Kitty.show_type() #не работает ругается: AttributeError: 'Cat' object has no attribute '_Cat__type' 

How to do it correctly, to be able to access private variables through child classes?

3 answers 3

The quick answer called @zed in his comments:
to access a field named with two underscores, you can use its real name, which in Python is obtained as follows: _<class_name><field_name> , i.e. in your case it will be the _Animal__type string.

Another thing is that this method is not quite suitable for your case.


In your case, it would be more correct to use the field name with one underscore (if you need to hide it), since this field should be accessible to the heir classes. In this case, the methods will work correctly:

 class Animal(object): def __init__(self,age): self.age = age self._type = 'animal' def __show(self): print('meow') def show1(self): self.__show() class Cat(Animal): def __init__(self,age): super().__init__(age) def show_type(self): print(self._type) Kitty = Cat(3) Kitty.show1() # meow Kitty.show_type() # animal 

Fields that have two underscores in the name (not special) have a rather narrow scope, so in most cases it is enough to use one underline in case the field is not desirable to use from outside the class or use the name without the underline if the field is safe to use anywhere (you can use the @property decorator to create read-only fields).

    1. If the variable is preceded by '__', then the result is a new field indicating the class name. In your case, this is _Animal_type. This is done in order to avoid personal conflicts in the subsidiary and base classes, so p.2
    2. Before creating access from children, you need to think about 2 questions "Why did I create this field with two underscores?" and "What did I want to protect myself from?"
    3. In fact, in Python, there are no public \ protected \ private variables and methods. Python programmers instruct other programmers to use only underscores for using variables and methods. Ahead of one underscore, they say, "I can change this code at any time without notifying about it in the certificate and I will be right! Use at your own peril and risk"

      How to access private variables in child classes?

      The correct answer is: you should NOT access the private ( __ ) attributes of other classes.

      If you think that in your case it is absolutely necessary to refer to such attributes, then you should change the corresponding parent classes to provide explicit, documented access.

      Also, programmers who come from languages ​​with a specific OOP model (C ++, Java), which places great emphasis on the visibility of attributes (private, protected, public), can be abused by __ in Python. Perhaps __ were redundant from the start.

      Finally, the worst solution is to find out the name distortion scheme that your version of Python uses and manually create the appropriate names for access:

       >>> class C: ... def __init__(self): ... self.__x = 'x' ... >>> c = C() >>> c.__x Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'C' object has no attribute '__x' >>> import dis >>> dis.dis(C.__init__) 3 0 LOAD_CONST 1 ('x') 3 LOAD_FAST 0 (self) 6 STORE_ATTR 0 (_C__x) 9 LOAD_CONST 0 (None) 12 RETURN_VALUE >>> c._C__x 'x' 

      Studying the _Py_Mangle() source code found an interesting feature: the initial underscore characters are removed from the class name, that is, the _C__x name remains the same for the C , _C , __C , etc. classes.