17 ms·
The part of the article about an issue with name mangling of private fields is somehow misleading. The feature is just some syntactic sugar. When within a cla
by guyzmo 10y ago
The part of the article about an issue with name mangling of private fields is somehow misleading.
The feature is just some syntactic sugar.
When within a class, private fields such as:
class Foo:
def __init__(self):
self.__bar
are accessible from within other methods of class Foo as `self.__bar`. But that's just syntactic sugar, the real name of `self.__bar` is `self._Foo__bar`.
So from the outside "world", including `hasattr()`, you can still access `self.__bar` as `Foo()._Foo__bar`.
>>> class Foo():
... def __init__(self):
... self.__bar = 'hello'
... def show(self):
... print(1, self.__bar)
... print(2, getattr(self, '__bar'))
...
>>> foo = Foo()
>>> foo._Foo__bar
True
>>> foo.show()
1 hello
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in show
AttributeError: 'Foo' object has no attribute '__bar'
>>> foo.__bar = 'world'
>>> foo.show()
1 hello
2 world
In the end, when `x.__private` is setup outside of the class definition, obviously, it's a new member as its name differs from the internal name `__private` (which really is `_X__private`).
From within the code doing `getattr('X', '__private')` will return the `__private` setup from outside the class, and `getattr('X', '_X__private')` the one defined from within the class.
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.
Here's an example of why this has been designed:
>>> class A:
... def __init__(self):
... self.__internal = "this is a"
... def show(self):
... print(1, "A", self.__internal)
...
>>> class B(A):
... def __init__(self):
... super(B, self).__init__()
... self.__internal = "this is b"
... def show(self):
... super(B, self).show()
... print(2, "B", self._A__internal)
... print(3, "B", self.__internal)
...
>>> B().show()
1 A this is a
2 B this is a
3 B this is b
>>>
There's nothing that should be surprising or asymmetrical to anybody who've read the python documentation, and use that feature appropriately. It's maybe a weird feature, but it's still a coherent and homogeneous behaviour and actually adding more safety to codes.
Documentation references:
* https://docs.python.org/3/faq/programming.html#i-try-to-use-spam-and-i-get-an-error-about-someclassname-spam
* https://docs.python.org/3/reference/expressions.html#atom-identifiers
- majewsky 10y agoTwo spaces indentation will give you the proper rendering for code snippets.
- mkesper 10y ago"Private" fields and methods should use one underscore. Two underscores are for name mangling issues and __method__ is for "magic" methods.
- guyzmo 10y agoWell, private fields are all members starting with an underscore and that are not publicised in the documentation. /That/ includes double underscores mangled members and and "magic" methods.
- zardeh 10y agoI'd say that private methods are double underscored, and protected methods are single underscored, since the goal of the __ is to prevent child classes from being able to use the parent implementation via self.__meth.
- xapata 10y agoNot prevented from being able to use, but from accidentally using or overriding the parent's. The child can still use the mangled name.
- marklgr 10y ago