Inheritance of Private and Protected Methods in Python

Inheritance of private and protected methods in Python

Python has no privacy model, there are no access modifiers like in C++, C# or Java. There are no truly 'protected' or 'private' attributes.

Names with a leading double underscore and no trailing double underscore are mangled to protect them from clashes when inherited. Subclasses can define their own __private() method and these will not interfere with the same name on the parent class. Such names are considered class private; they are still accessible from outside the class but are far less likely to accidentally clash.

Mangling is done by prepending any such name with an extra underscore and the class name (regardless of how the name is used or if it exists), effectively giving them a namespace. In the Parent class, any __private identifier is replaced (at compilation time) by the name _Parent__private, while in the Child class the identifier is replaced by _Child__private, everywhere in the class definition.

The following will work:

class Child(Parent):
def foo(self):
self._protected()

def bar(self):
self._Parent__private()

See Reserved classes of identifiers in the lexical analysis documentation:

__*
Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes.

and the referenced documentation on names:

Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier __spam occurring in a class named Ham will be transformed to _Ham__spam. This transformation is independent of the syntactical context in which the identifier is used.

Don't use class-private names unless you specifically want to avoid having to tell developers that want to subclass your class that they can't use certain names or risk breaking your class. Outside of published frameworks and libraries, there is little use for this feature.

The PEP 8 Python Style Guide has this to say about private name mangling:

If your class is intended to be subclassed, and you have attributes
that you do not want subclasses to use, consider naming them with
double leading underscores and no trailing underscores. This invokes
Python's name mangling algorithm, where the name of the class is
mangled into the attribute name. This helps avoid attribute name
collisions should subclasses inadvertently contain attributes with the
same name.

Note 1: Note that only the simple class name is used in the mangled
name, so if a subclass chooses both the same class name and attribute
name, you can still get name collisions.

Note 2: Name mangling can make certain uses, such as debugging and
__getattr__(), less convenient. However the name mangling algorithm
is well documented and easy to perform manually.

Note 3: Not everyone likes name mangling. Try to balance the need to
avoid accidental name clashes with potential use by advanced callers.

How to represent protected methods in Python classes?

Just use names starting with a single underscore.

A protected method is a implementation detail that you want to share with subclasses, so such methods are not part of the public API. Anything not part of the public API is best named with an initial underscore.

In other words, 'protected' should be treated just the same as 'private'. Protected methods only need to exist in a language with a strict privacy model where making such implementation details private would preclude sharing such methods with subclasses. Python has no such problem.

Whatever you do, do not use a leading double underscore; such names are considered class private and are namespaced to the class that defines them (they are renamed by the compiler by prefixing _ClassName in front), to ensure that subclasses don't accidentally overwrite them.

inheriting private variable in python

when you create var with double underscore, its just a notation use to indicate it as private variable, python do name mangling on the variable name itself to prevent normal way access to it.

However, its still not the real private variable like C/C++. You can still access the so called python "private var" with syntax below

var = __myvar
# access with _<class name>__myvar

From PEP,

  • _single_leading_underscore : weak "internal use" indicator. E.g. from M import * does not import objects whose name starts with an
    underscore.
  • __double_leading_underscore : when naming a class attribute, invokes name mangling (inside class FooBar, __boo becomes _FooBar__boo

For your case, change your dog class toString method to below then it should works

def toString(self):
return "{} is {} cm and {} weight and say {} and belongs to {}.".format(self._animal__name, self._animal__height,
self._animal__weight, self._animal__sound,
self.__owner) # __owner remains because its not inherit from class animal

another option is to change your animal class variable to single underscore _ if you don't really need double underscore __

Python3: Class inheritance and private fields

Python doesn't really have private variables, there are two conventions:

  • Variables prefixed with underscore (_var) are used to let you and other people know that it's intended to be private
  • Variables prefixed with two undersores (__var) are also mangled by python interpreter and also are prefixed by class name, but they are still accessible like self._Superclass__var in your example

See also the documentation.

There is one more issue in your code - you are using class variables, not instance variables (this is what usually called static class variables in other languages).

Check this example:

class Superclass:
var = 1

def getVar(self):
print(self.var)

my_object = Superclass()
my_object2 = Superclass()
my_object.getVar() # outputs 1
my_object2.getVar() # outputs 1

Superclass.var = 321 # this value is share across all instances
my_object.getVar() # outputs 321
my_object2.getVar() # outputs 321

And when you are doing self.var = xxx assignments in your methods, you just hide the class-level variable and add the new instance-level variable with same name.

See also the documentation: https://docs.python.org/3.6/tutorial/classes.html#class-and-instance-variables

Getting parent private or protected values from the child class

As you have noted in the question, you can access the parent attribute by explicitly using the mangled form of its name in the child class:

def ChildMethodWhichUsingParentField(self):
return self._Parent__field

This is the only simple answer to your direct question.

However, if you have control over the Parent class, this would be a very bad design. You should not use a double-underscore attribute name for something that another class class will ever use (and really you probably shouldn't use it even if you don't expect any such use). Use a single underscore (_field) instead. This "documents" that the attribute is intended to be private (e.g. not part of a class's public API), without enabling name mangling. That way, if you find later than another class does need to access the variable it can. Python doesn't enforce privacy (not even when name mangling is used), so you'll always need to rely upon other code behaving nicely.

Name mangling is really only intended for use in situations where you need to avoid name collisions. For instance, a proxy object might use mangled names for its own attributes so that it can present an interface that is an exact replica of another object's interface (which may not be known ahead of time). Or a mixin class might use name mangling for its variables since it can't know for sure what attribute names will be used in the (possibly many) other classes that will be inherited along side it. It can also be useful if you're adding an attribute for your own use to other objects (not self) and want to avoid overwriting their existing attributes by mistake.

Protected method in python

Python does not support access protection as C++/Java/C# does. Everything is public. The motto is, "We're all adults here." Document your classes, and insist that your collaborators read and follow the documentation.

The culture in Python is that names starting with underscores mean, "don't use these unless you really know you should." You might choose to begin your "protected" methods with underscores. But keep in mind, this is just a convention, it doesn't change how the method can be accessed.

Names beginning with double underscores (__name) are mangled, so that inheritance hierarchies can be built without fear of name collisions. Some people use these for "private" methods, but again, it doesn't change how the method can be accessed.

The best strategy is to get used to a model where all the code in a single process has to be written to get along.

Protected access in Python - how?

Member access allowance in Python works by "negotiation" and "treaties", not by force.

In other words, the user of your class is supposed to leave their hands off things which are not their business, but you cannot enforce that other than my using _xxx identifiers making absolutely clear that their access is (normally) not suitable.

Making a method private in a python subclass

Python is distributed as source. The very idea of a private method makes very little sense.

The programmer who wants to extend B, frustrated by a privacy issue, looks at the source for B, copies and pastes the source code for method into the subclass C.

What have you gained through "privacy"? The best you can hope for is to frustrate your potential customers into copying and pasting.

At worst, they discard your package because they can't extend it.

And yes, all open source is extended in one way or another. You can't foresee everything and every use to which you code will be put. Preventing some future use is hard to do when the code is distributed as source.

See How do I protect Python code?


Edit On "idiot-proof" code.

First, python is distributed as source 90% of the time. So, any idiot who downloads, installs, and then refuses to read the API guide and calls the methods out of order still has the source to figure out what went wrong.

We have three classes of idiots.

  • People who refuse to read the API guide (or skim it and ignore the relevant parts) and call the methods out of order in spite of the documentation. You can try to make something private, but it won't help because they'll do something else wrong -- and complain about it. [I won't name names, but I've worked with folks who seem to spend a lot of time calling the API's improperly. Also, you'll see questions like this on SO.]

    You can only help them with a working code sample they can cut and paste.

  • People who are confused by API's and call the methods every different way you can imagine (and some you can't.) You can try to make something private, but they'll never get the API.

    You can only help them by providing the working code sample; even then, they'll cut and paste it incorrectly.

  • People who reject your API and want to rewrite it to make it "idiot proof".

    You can provide them a working code sample, but they don't like your API and will insist on rewriting it. They'll tell you that your API is crazy and they've improved on it.

    You can engage these folks in an escalating arms race of "idiot-proofing". Everything you put together they take apart.

At this point, what has privacy done for you? Some people will refuse to understand it; some people are confused by it; and some people want to work around it.

How about public, and let the folks you're calling "idiots" learn from your code?

Private Inheritance in Python

Python doesn't do the public/private/protected inheritance of c++.

It's somewhat a feature of python that you can access anything. If you want strong encapsulation you have to look at other languages.



Related Topics



Leave a reply



Submit