Private, protected and public in Python
A lot of folks learn object-oriented programming with languages like C++ and Java. And while they learn, they’re told repeatedly, that encapsulation is a key principle of the object-oriented paradigm, and that they should take advantage of it whenever they can. Sure, until you get down with Python.
In C++ and Java, the access modifiers are built into the language. However, there’s no such a thing
as public
, protected
and private
in Python. That might be a little
confusing, but it’s possible to write object-oriented code regardless. In this post, we’ll
take look at how do just that.
Python doesn’t have any mechanisms that would effectively restrict you from accessing a variable or calling a member method. All of this is a matter of culture and convention.
Public
All member variables and methods are public by default in Python. When you want to make your member public, you simply do nothing. Here’s an example:
class Cup:
def __init__(self):
self.color = None
self.content = None
def fill(self, beverage):
self.content = beverage
def empty(self):
self.content = None
And here’s what you can do with an instance of Cup
:
redCup = Cup()
redCup.color = "red"
redCup.content = "tea"
redCup.empty()
redCup.fill("coffee")
All of this is good and acceptable, because all the attributes and methods are public.
Protected
Protected members (in C++ and Java) are accessible only from within the class and it’s subclasses. How to accomplish this in Python? By following a convention. When you prefix the name of your member with a single underscore, you’re telling others “don’t touch this, unless you’re a subclass”. See the example below:
class Cup:
def __init__(self):
self.color = None
self._content = None # protected variable
def fill(self, beverage):
self._content = beverage
def empty(self):
self._content = None
It’s the same example as before, but the content of the cup is now protected. This doesn’t change anything: you’ll still be able to access the variable from outside the class. But if you see something like this in a pull request:
cup = Cup()
cup._content = "tea"
You can politely explain to the author that the variable is protected, and that they should not access or change it from the outside of the class.
Private
Declaring your data member private means that nobody should be able to
access it from outside the class, i.e. strong
you can’t touch this policy.
Python supports a technique called name mangling.
This feature turns every member name prefixed with at least two underscores
and suffixed with at most one underscore into _<className><memberName>
at run time.
So how to make your member private? Let’s have a look at the example below:
class Cup:
def __init__(self, color):
self._color = color # protected variable
self.__content = None # private variable
def fill(self, beverage):
self.__content = beverage
def empty(self):
self.__content = None
Our cup now can only be filled and emptied by using the fill()
and empty()
methods. Note that if you try accessing __content
from the outside, you’ll get
an error. However, you can still get around that like this:
redCup = Cup("red")
redCup._Cup__content = "tea"
When you see this in a PR, you should probably have a stern talking-to with the author.