Python "protected" attributes

Viewed 73747

How do I access a private attribute of a parent class from a subclass (without making it public)?

9 Answers

My understanding of Python convention is

  • _member is protected
  • __member is private

Options for if you control the parent class

  • Make it protected instead of private since that seems like what you really want
  • Use a getter (@property def _protected_access_to_member...) to limit the protected access

If you don't control it

  • Undo the name mangling. If you dir(object) you will see names something like _Class__member which is what Python does to leading __ to "make it private". There isn't truly private in python. This is probably considered evil.

if the variable name is "__secret" and the class name is "MyClass" you can access it like this on an instance named "var"

var._MyClass__secret

The convention to suggest/emulate protection is to name it with a leading underscore: self._protected_variable = 10

Of course, anybody can modify it if it really wants.

I think this code is a little clearer than Steve's. Steve's answer was most helpful for what I am trying to do, so thank you! I tested this with python 2.7 and python 3.6.

#! /usr/bin/python
#
# From https://stackoverflow.com/questions/797771/python-protected-attributes
from __future__ import print_function
import sys

class Stock(object):

    def __init__(self, stockName):

        # '_' is just a convention and does nothing
        self.__stockName  = stockName   # private now


    @property # when you do Stock.name, it will call this function
    def name(self):
        print("In the getter, __stockName is %s" % self.__stockName, file=sys.stderr)
        return self.__stockName

    @name.setter # when you do Stock.name = x, it will call this function
    def name(self, name):
        print("In the setter, name is %s will become %s" % ( self.__stockName, name), file=sys.stderr)
        self.__stockName = name

if __name__ == "__main__":
    myStock = Stock("stock111")

    try:
        myStock.__stockName  # It is private. You can't access it.
    except AttributeError as a:
        print("As expect, raised AttributeError", str(a), file=sys.stderr )
    else:
        print("myStock.__stockName did did *not* raise an AttributeError exception")


    #Now you can myStock.name
    myStock.name = "Murphy"
    N = float(input("input to your stock: " + str(myStock.name)+" ? "))
    print("The value of %s is %s" % (myStock.name, N) )

Make an accessor method, unless I am missing something:

def get_private_attrib(self):
  return self.__privateWhatever

Code modified from geeksforgeeks

# program to illustrate protected
# data members in a class 
  
  
# Defining a class
class Geek: 
    # private
    __name = "R2J"
    # protected data members 
    _roll = 1706256
    def __init__(self, value):
        value1 = value
        self.value2 = value
    # public member function 
    def displayNameAndRoll(self): 
  
        # accessing protected data members 
        print("Name: ", self.__name) 
        print("Roll: ", self._roll) 
  
  
# creating objects of the class         
obj = Geek(1)
obj.__name = 'abc'
obj._roll = 12345

# calling public member 
# functions of the class 
obj.displayNameAndRoll() 

Note that I can modifies without setter the protected attribute, but not the private.

Name:  R2J
Roll:  12345

OBS: running in python 3.8

There is a process of name mangling when you instantiate a non public attribute. In order to access the attribute outside of the class you need to "un-mangle".

Example: Class creation

class Object:
    def __init__(self, name):
        self.__name = name

Create instance:

obj = Object('test')

Access non public attribute (un-mangle):

print(obj._Object__name)
Related