Python "protected" attributes
Question:
How do I access a private attribute of a parent class from a subclass (without making it public)?
Answers:
Make an accessor method, unless I am missing something:
def get_private_attrib(self):
return self.__privateWhatever
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.
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.
Using @property
and @name.setter
to do what you want
e.g
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):
return self.__stockName
@name.setter # when you do Stock.name = x, it will call this function
def name(self, name):
self.__stockName = name
if __name__ == "__main__":
myStock = Stock("stock111")
myStock.__stockName # It is private. You can't access it.
#Now you can myStock.name
N = float(raw_input("input to your stock: " + str(myStock.name)+" ? "))
Two philosophies of protection
Some language designers subscribe to the following assumption:
“Many programmers are irresponsible, dim-witted, or both.”
These language designers will feel tempted to protect programmers from each other by introducing a private
specifier into their language.
Shortly later they recognize that this is often too inflexible and introduce protected
as well.
Language designers such as Python’s Guido van Rossum, in contrast, assume that programmers are responsible adults and capable of good judgment (perhaps not always, but typically).
They find that everybody should be able to access the elements of a program if there is a need to do that, so that the language does not get in the way of doing the right thing.
(The only programming language that can reliably get in the way of doing the wrong thing is the NULL language)
Therefore, _myfield
in Python means something like “The designer of this module is doing some non-obvious stuff with this attribute, so please do not modify it and stay away from even reading it if you can — suitable ways to access relevant information have been provided (or so we hope).”
In case you are not able to stay away from accessing _myfield
(such as in special cases in a subclass), you simply access it.
No one seems to answer the original question
how to access a private attribute of a parent class from a subclass
So here’s a simple use case, demonstrating two options – accessing parent class __private variables and using @property decorator:
class Family:
def __init__(self, name):
self.__family_name = name
@property
def name(self):
return self.__family_name
class Child(Family):
def __init__(self, first_name, last_name):
super(Child, self).__init__(last_name)
self.__child_name = first_name
@property
def name(self):
return (self.__child_name, super(Child, self).name)
if __name__ == '__main__':
my_child = Child("Albert", "Einstein")
# print (my_child.__child_name) # AttributeError - trying to access private attribute '__child_name'
# print (my_child.__family_name) # AttributeError - trying to access private attribute '__family_name'
print (my_child._Child__child_name) # Prints "Albert" - By accessing __child_name of Child sub-class
print (my_child._Family__family_name) # Prints "Einstein" - By accessing __family_name in Family super-class
print (" ".join(my_child.name)) # Prints "Albert Einstein" - By using @property decorators in Child and Family
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) )
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)
How do I access a private attribute of a parent class from a subclass (without making it public)?
Make an accessor method, unless I am missing something:
def get_private_attrib(self):
return self.__privateWhatever
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.
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.
Using @property
and @name.setter
to do what you want
e.g
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):
return self.__stockName
@name.setter # when you do Stock.name = x, it will call this function
def name(self, name):
self.__stockName = name
if __name__ == "__main__":
myStock = Stock("stock111")
myStock.__stockName # It is private. You can't access it.
#Now you can myStock.name
N = float(raw_input("input to your stock: " + str(myStock.name)+" ? "))
Two philosophies of protection
Some language designers subscribe to the following assumption:
“Many programmers are irresponsible, dim-witted, or both.”
These language designers will feel tempted to protect programmers from each other by introducing a private
specifier into their language.
Shortly later they recognize that this is often too inflexible and introduce protected
as well.
Language designers such as Python’s Guido van Rossum, in contrast, assume that programmers are responsible adults and capable of good judgment (perhaps not always, but typically).
They find that everybody should be able to access the elements of a program if there is a need to do that, so that the language does not get in the way of doing the right thing.
(The only programming language that can reliably get in the way of doing the wrong thing is the NULL language)
Therefore, _myfield
in Python means something like “The designer of this module is doing some non-obvious stuff with this attribute, so please do not modify it and stay away from even reading it if you can — suitable ways to access relevant information have been provided (or so we hope).”
In case you are not able to stay away from accessing _myfield
(such as in special cases in a subclass), you simply access it.
No one seems to answer the original question
how to access a private attribute of a parent class from a subclass
So here’s a simple use case, demonstrating two options – accessing parent class __private variables and using @property decorator:
class Family:
def __init__(self, name):
self.__family_name = name
@property
def name(self):
return self.__family_name
class Child(Family):
def __init__(self, first_name, last_name):
super(Child, self).__init__(last_name)
self.__child_name = first_name
@property
def name(self):
return (self.__child_name, super(Child, self).name)
if __name__ == '__main__':
my_child = Child("Albert", "Einstein")
# print (my_child.__child_name) # AttributeError - trying to access private attribute '__child_name'
# print (my_child.__family_name) # AttributeError - trying to access private attribute '__family_name'
print (my_child._Child__child_name) # Prints "Albert" - By accessing __child_name of Child sub-class
print (my_child._Family__family_name) # Prints "Einstein" - By accessing __family_name in Family super-class
print (" ".join(my_child.name)) # Prints "Albert Einstein" - By using @property decorators in Child and Family
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) )
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)