21

Consider a class with a "private" method such as:

class Foo(object):
    def __init__(self):
        self.__method()
    def __method(self):
        print('42')

When I try to subclass Foo and override method __method, it can be seen that Foo.__method is still called, instead of MoreFoo.__method.

class MoreFoo(Foo):
    def __method(self):
        print('41')

>>> MoreFoo()
42
<__main__.MoreFoo object at 0x7fb726197d90>

What would be the way to override such a method?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ernest A
  • 7,526
  • 8
  • 34
  • 40
  • 1
    http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python – tacaswell Feb 15 '13 at 15:47
  • Out of interest, where did you get the idea that this was equivalent to a private variable? It's a really bad misconception, and I see it all the time with no idea where it comes from. – Gareth Latty Feb 15 '13 at 15:47
  • 3
    @Lattyware -- I think it comes from the section on the docs called "Private Variables and Class-local References". It goes on to say that there are no private variables ... but that the double underscoring thing is the closest you can get -- "Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, ..." – mgilson Feb 15 '13 at 15:50

3 Answers3

40

The point of using the double-underscore name convention is to prevent subclasses from (accidentally) overriding the method.

If you have to override it anyway, someone made a serious class design error. You can do it still, by naming your object just so:

def _Foo__method(self):

where you prefix the method name with one more underscore and the defining classname (so in this case prefixed with _Foo). The process of renaming methods and attributes with a double underscore is called private name mangling.

If you want to define a 'private' method that is still overridable in a subclass, you generally stick to names with one underscore instead (def _method(self):).

Due to its dynamic nature, almost nothing in Python is truly private; with a little introspection almost anything can be reached.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
16

A double underscore prefix invokes name mangling. It is not equivalent to a private method and is specifically designed to avoid being overridden by subclasses (and in this case, the method name becomes _Foo__method).

If you have an implementation detail, prefix it with a single underscore. This is the universally accepted sign for Python methods that are not to be used externally. There is no enforcement of this, because that's not the way Python functions.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
  • I am aware it's not really private, this is why I wrote private between quotation marks. – Ernest A Feb 15 '13 at 15:56
  • @ErnestA It's not just that it's *not really* private, it's that it is in no way similar or comparable - it fills a completely different role. – Gareth Latty Feb 15 '13 at 16:02
  • I was under the impression that it was OK to call methods that start with 2 underscores "private". Maybe it's not. In this case sorry for using the wrong terminology. – Ernest A Feb 15 '13 at 16:05
  • @ErnestA It doesn't really make much sense to call something by a name completely dissimilar to what it is. It just causes confusion, as shown in your question. You don't need to be sorry, it's just that referring to it as private will make your life harder as it will mislead you. – Gareth Latty Feb 15 '13 at 16:07
  • 1
    It's not "completely dissimilar" to private variables. __ signals the author's intent, name mangling adds a barrier to override, but then have at it. – tdelaney Feb 15 '13 at 16:26
  • 1
    @tdelaney Yes, but `_` singals the author's intent that it's an implementation detail. `__` signals that they thing subclasses might accidentally mess with their internals. Totally different. Describing it as private only confuses and misleads. – Gareth Latty Feb 15 '13 at 16:29
6

I believe that you would do something like:

class MoreFoo(Foo):
    def _Foo__method(self):
        print('41')

as documented.

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.

But the designers of the original class were of the opinion that you shouldn't need to do something like this as making it difficult to override with subclassing is the whole point of the double underscores to begin with:

Name mangling is helpful for letting subclasses override methods without breaking intraclass method calls.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Technically this should work, but it masks the more serious problem of misuse of the double underscore in the first place. – Andrew Gorcester Feb 15 '13 at 15:46
  • @AndrewGorcester -- Sure. I'm not saying that this is a good idea. – mgilson Feb 15 '13 at 15:47
  • Thanks. I didn't write the original class. I just want to override one of its methods that happens to begin with two underscores. – Ernest A Feb 15 '13 at 15:59
  • @ErnestA -- Fair enough. I changed it to say that the designers of the original class wouldn't want you to do it ;-). You can do whatever you want though -- As the idiom goes: "We're all consenting adults here" – mgilson Feb 15 '13 at 16:01