A bite of Python
The part of the article about an issue with name mangling of private fields is somehow misleading.<p>The feature is just some syntactic sugar.<p>When within a class, private fields such as:<p><pre><code>    class Foo:
        def __init__(self):
            self.__bar
</code></pre>
are accessible from within other methods of class Foo as `self.__bar`. But that&#x27;s just syntactic sugar, the real name of `self.__bar` is `self._Foo__bar`.<p>So from the outside &quot;world&quot;, including `hasattr()`, you can still access `self.__bar` as `Foo()._Foo__bar`.<p><pre><code>    &gt;&gt;&gt; class Foo():
    ...   def __init__(self):
    ...     self.__bar = &#x27;hello&#x27;
    ...   def show(self):
    ...     print(1, self.__bar)
    ...     print(2, getattr(self, &#x27;__bar&#x27;))
    ... 
    &gt;&gt;&gt; foo = Foo()
    &gt;&gt;&gt; foo._Foo__bar
    True
    &gt;&gt;&gt; foo.show()
    1 hello
    Traceback (most recent call last):
      File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
      File &quot;&lt;stdin&gt;&quot;, line 6, in show
    AttributeError: &#x27;Foo&#x27; object has no attribute &#x27;__bar&#x27;
    &gt;&gt;&gt; foo.__bar = &#x27;world&#x27;
    &gt;&gt;&gt; foo.show()
    1 hello
    2 world
</code></pre>
In the end, when `x.__private` is setup outside of the class definition, obviously, it&#x27;s a new member as its name differs from the internal name `__private` (which really is `_X__private`).<p>From within the code doing `getattr(&#x27;X&#x27;, &#x27;__private&#x27;)` will return the `__private` setup from outside the class, and `getattr(&#x27;X&#x27;, &#x27;_X__private&#x27;)` the one defined from within the class.<p>The whole point of that feature is to ensure that members  defined within a class that are not part of the public API are left untouched when that class get subclassed, to avoid unexpected behaviours.<p>Here&#x27;s an example of why this has been designed:<p><pre><code>  &gt;&gt;&gt; class A:
  ...   def __init__(self):
  ...     self.__internal = &quot;this is a&quot;
  ...   def show(self):
  ...     print(1, &quot;A&quot;, self.__internal)
  ... 
  &gt;&gt;&gt; class B(A):
  ...   def __init__(self):
  ...     super(B, self).__init__()
  ...     self.__internal = &quot;this is b&quot;
  ...   def show(self):
  ...     super(B, self).show()
  ...     print(2, &quot;B&quot;, self._A__internal)
  ...     print(3, &quot;B&quot;, self.__internal)
  ... 
  &gt;&gt;&gt; B().show()
  1 A this is a
  2 B this is a
  3 B this is b
  &gt;&gt;&gt; 
</code></pre>
There&#x27;s nothing that should be surprising or asymmetrical to anybody who&#x27;ve read the python documentation, and use that feature appropriately. It&#x27;s maybe a weird feature, but it&#x27;s still a coherent and homogeneous behaviour and actually adding more safety to codes.<p>Documentation references:<p><pre><code>  * https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;faq&#x2F;programming.html#i-try-to-use-spam-and-i-get-an-error-about-someclassname-spam
  * https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;reference&#x2F;expressions.html#atom-identifiers</code></pre>