12
class A(object):
    def __get(self):
        pass

    def _m(self):
        return self.__get()


class B(A):
    def _m(self):
        return str(self.__get())

print(A()._m())
print(B()._m())

Why print(A()._m()) prints None, but print(B()._m()) raises AttributeError: 'B' object has no attribute '_B__get'?

I thought that double underscore prevents method overriding.

If __get is private then why does the following work?

class A(object):
    def __get(self):
        pass

    def _m(self):
        return self.__get()


class B(A):
    pass

print(A()._m())
print(B()._m())

Why does this code doesn't raise AttributeError and prints None two times?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Paul R
  • 2,631
  • 3
  • 38
  • 72
  • 2
    [Name mangling](https://docs.python.org/3/tutorial/classes.html#private-variables). Your call to `self.__get()` in `B` is really calling `self._B__get()`, which does not exist. Unless you want this behavior, don't use leading double underscores. – kindall Jul 24 '17 at 19:57
  • Check out [what is the meaning of a single and a double underscore before an object name](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-a-single-and-a-double-underscore-before-an-object-name?rq=1) and some of the linked questions as there are some detailed explanations. – LinkBerest Jul 24 '17 at 19:59
  • Re your update: Because you are calling __get from a method defined in class A. That's perfectly legal in any language that supports the concept of private -- in fact that is the most common use case of private methods. – Dale Wilson Jul 25 '17 at 15:17

2 Answers2

12

Leading double underscore names are private (meaning not available to derived classes)

This is not foolproof. It is implemented by mangling the name. Python Documentation says:

Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, so it can be used to define class-private instance and class variables, methods, variables stored in globals, and even variables stored in instances. private to this class on instances of other classes.

Thus __get is actually mangled to _A__get in class A. When class B attempts to reference __get, it gets mangled to _B__get which doesn't match.

In other words __plugh defined in class Xyzzy means "unless you are running as class Xyzzy, thou shalt not touch the __plugh."

Dale Wilson
  • 9,166
  • 3
  • 34
  • 52
  • 2
    _"Leading double underscore names are `private` (meaning not available to derived classes)"_ Please don't do this. There's noting called private in Python, those names are (pseudoprivate) and not private. – GIZ Jul 24 '17 at 20:04
  • 5
    @direprobs The PURPOSE of the leading underscores is to hide the symbols from everone except the defining class. In MANY other languages this concept is referred to a being "private". Hence I used a single word for the concept that should be well recognized. Also I explained the implementation details and mentioned the lack of foolproofness. How else would you suggest conveying the concept? – Dale Wilson Jul 24 '17 at 20:08
  • 2
    That's the problem. The word private would suggest private like it's in Java for example, the variable cannot be accessed from outside the class. You said the variable won't be available to the derived class which is absolutely wrong. – GIZ Jul 24 '17 at 20:12
  • 2
    Note that the official python documentation I quoted calls this concept -- um -- 'class-private' – Dale Wilson Jul 24 '17 at 20:13
  • It's _suggested_ that anything with a double-underscore-prefix is made private, but it's NOT enforced, which is exactly the point of @direprobs. I.e. if anything from the outside (or a derived class) _can_ reach it, then it's not really private, is it? It's been made difficult, but not impossible. – klaar Nov 23 '22 at 09:15
3

For __methodName() member function of class A:

  • To call this member function from outside of class A, you can only call _A__methodName() (trying to call __methodName() will generate an error)

  • To call this member function inside class A, you can use both _A__methodName() and __methodName()

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
Zhihui Shao
  • 377
  • 3
  • 5