Private functions and inheritance

  • Thread starter Bruno Desthuilliers
  • Start date
B

Bruno Desthuilliers

Maciej Bliziński a écrit :
(snip the rest - already answered by at least 3 persons).
I
don't want to expose the __bar() function outside, but on the other
hand i want to defer its implementation to a subclass. It seems like I
need to make it public, doesn't it?

First, keep in mind that that Python *does not* have any notion of
(languaged enforced) access restriction. All that the __name thingie
does is to mangle the name with the class name, so A.bar become
A._A__bar. This can be useful. Sometimes. Perhaps. (FWIW, I think I've
used it once in seven years and I'm not sure it was really necessary
after all).

Now there's a strong convention which says that _names prefixed by a
single underscore are implementation stuff, and that anyone messing with
implementation stuff implicitely accepts all the possible consequences.
 
G

Guest

Hello,

I've come across something that I don't quite understand about
Python's inheritance. Consider the following code snippet:

class A(object):
def call_bar(self): return self.bar()
def call___bar(self): return self.__bar()
def __bar(self): return "A::__bar()"
def bar(self): return "A::bar()"

class B(A):
def __bar(self): return "B::__bar()"
def bar(self): return "B::bar()"

b = B()
print "calling B::call_bar():", b.call_bar()
print "calling B::call___bar():", b.call___bar()

The result is:

calling B::call_bar(): B::bar()
calling B::call___bar(): A::__bar()

In the latter case, it calls the base class' implementation. It
probably goes along with Python's spec, but I found it surprising. I
don't want to expose the __bar() function outside, but on the other
hand i want to defer its implementation to a subclass. It seems like I
need to make it public, doesn't it?
 
B

Bjoern Schliessmann

Maciej said:
calling B::call_bar(): B::bar()
calling B::call___bar(): A::__bar()

(BTW, there is no :: operator in Python. It should be, e. g.,
B.bar().)
In the latter case, it calls the base class' implementation. It
probably goes along with Python's spec, but I found it surprising.

__-prepended names are dynamically mangled to include the class
name. Hence, B.__bar doesn't overwrite A.__bar in B.
I don't want to expose the __bar() function outside,

In principle, you do. Always. Public or Private is just convention
in Python. Even __-prepended names can be accessed from outside.

Couldn't find it in the docs though. Quite inconcise.

Regards,


Björn
 
D

Diez B. Roggisch

Maciej said:
Hello,

I've come across something that I don't quite understand about
Python's inheritance. Consider the following code snippet:

class A(object):
def call_bar(self): return self.bar()
def call___bar(self): return self.__bar()
def __bar(self): return "A::__bar()"
def bar(self): return "A::bar()"

class B(A):
def __bar(self): return "B::__bar()"
def bar(self): return "B::bar()"

b = B()
print "calling B::call_bar():", b.call_bar()
print "calling B::call___bar():", b.call___bar()

The result is:

calling B::call_bar(): B::bar()
calling B::call___bar(): A::__bar()

In the latter case, it calls the base class' implementation. It
probably goes along with Python's spec, but I found it surprising. I
don't want to expose the __bar() function outside, but on the other
hand i want to defer its implementation to a subclass. It seems like I
need to make it public, doesn't it?

Yep. Just use a single underscore, and that's it. The reason why this
doesn't work as expected is that the name-mangling introduced by the
leading double underscores is purely a lexical scope based mechanism.

Diez
 
N

Neil Cerutti

Hello,

I've come across something that I don't quite understand about
Python's inheritance. Consider the following code snippet:

class A(object):
def call_bar(self): return self.bar()
def call___bar(self): return self.__bar()
def __bar(self): return "A::__bar()"
def bar(self): return "A::bar()"
class B(A):
def __bar(self): return "B::__bar()"
def bar(self): return "B::bar()"

b = B()
print "calling B::call_bar():", b.call_bar()
print "calling B::call___bar():", b.call___bar()

The result is:

calling B::call_bar(): B::bar()
calling B::call___bar(): A::__bar()

the __* naming convention for class private attributes is
intended to "help ensure" that attribute names of derived classes
cannot conflict with private attribute names in any base classes.
I.e., you should not use that naming convention when you *intend*
to override it in a derived class. If you do use the __* naming
convention, use it only for attributes that should not be
overrided or accessed by derived classes.

the weasel words from the documentation (which I put in quotes)
are there because the feature doesn't work (in all cases).
 

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top