Encapsulation in Python
In Python, encapsulation refers to the bundling of data (attributes) and methods (functions) that operate on the
data into a single unit, typically a class. It also restricts direct access to some components, which helps protect
the integrity of the data and ensures proper usage.
Encapsulation is the process of hiding the internal state of an object and requiring all interactions to be
performed through an object's methods.
Python achieves encapsulation through public, protected and private attributes.
Encapsulation in Python
Why do we need Encapsulation in Python
Protects data from unauthorized access and accidental modification.
Controls data updates using getter/setter methods with validation.
Enhances modularity by hiding internal implementation details.
Simplifies maintenance through centralized data handling logic.
Reflects real-world scenarios like restricting direct access to a bank account balance.
How Encapsulation Works:
Data Hiding: The variables (attributes) are kept private or protected, meaning they are not accessible
directly from outside the class. Instead, they can only be accessed or modified through the methods.
Access through Methods: Methods act as the interface through which external code interacts with the data
stored in the variables. For instance, getters and setters are common methods used to retrieve and update the
value of a private variable.
Control and Security: By encapsulating the variables and only allowing their manipulation via methods,
the class can enforce rules on how the variables are accessed or modified, thus maintaining control and
security over the data.
Example of Encapsulation
Encapsulation in Python is like having a bank account system where your account balance (data) is kept private.
You can't directly change your balance by accessing the account database. Instead, the bank provides you with
methods (functions) like deposit and withdraw to modify your balance safely.
Private Data (Balance): Your balance is stored securely. Direct access from outside is not allowed,
ensuring the data is protected from unauthorized changes.
Public Methods (Deposit and Withdraw): These are the only ways to modify your balance. They check if
your requests (like withdrawing money) follow the rules (e.g., you have enough balance) before allowing
changes.
Access Specifiers in Python
Types of Access Modifiers
Public Members
Public members are accessible from anywhere, both inside and outside the class. These are the default members
in Python.
Example:
class Public:
def __init__(self):
[Link] = "John" # Public attribute
def display_name(self):
print([Link]) # Public method
obj = Public()
obj.display_name() # Accessible
print([Link]) # Accessible
Explanation:
Public Attribute (name): This attribute is declared without any underscore prefixes. It is accessible from
anywhere, both inside and outside of the class.
Public Method (display_name): This method is also accessible from any part of the code. It directly
accesses the public attribute and prints its value.
Object (obj): An instance of Public is created, and the display_name method is called, demonstrating how
public attributes and methods can be accessed directly.
Note: The __init__ method is a constructor and runs as soon as an object of a class is instantiated.
Protected members
Protected members are identified with a single underscore (_). They are meant to be accessed only within the
class or its subclasses.
Example:
class Protected:
def __init__(self):
self._age = 30 # Protected attribute
class Subclass(Protected):
def display_age(self):
print(self._age) # Accessible in subclass
obj = Subclass()
obj.display_age()
Explanation:
Protected Attribute (_age): This attribute is prefixed with a single underscore, which by convention,
suggests that it should be treated as a protected member. It's not enforced by Python but indicates that it
should not be accessed outside of this class and its subclasses.
Subclass: Here, a subclass inherits from Protected. Within this subclass, we can still access the
protected attribute _age.
Method (display_age): This method within the subclass accesses the protected attribute and prints its
value. This shows that protected members can be accessed within the class and its subclasses.
Private members
Private members are identified with a double underscore (__) and cannot be accessed directly from outside the
class. Python uses name mangling to make private members inaccessible by renaming them internally.
Note: Python's private and protected members can be accessed outside the class through python name
mangling.
class Private:
def __init__(self):
self.__salary = 50000 # Private attribute
def salary(self):
return self.__salary # Access through public method
obj = Private()
print([Link]()) # Works
#print(obj.__salary) # Raises AttributeError
Explanation:
Private Attribute (__salary): This attribute is prefixed with two underscores, which makes it a private
member. Python enforces privacy by name mangling, which means it renames the attribute in a way that
makes it hard to access from outside the class.
Method (salary): This public method provides the only way to access the private attribute from outside the
class. It safely returns the value of __salary.
Direct Access Attempt: Trying to access the private attribute directly (obj.__salary) will result in an
AttributeError, showing that direct access is blocked. This is Python's way of enforcing encapsulation at a
language level.
Access Modifiers in Python : Public, Private and Protected
Last Updated : 12 Jul, 2025
Prerequisites: Underscore (_) in Python, Private Variables in Python
Encapsulation is one of the four principles used in Object Oriented Paradigm. It is used to bind and hide data to
the class. Data hiding is also referred as Scoping and the accessibility of a method or a field of a class can be
changed by the developer. The implementation of scoping is different for different programming language. For
example, statically typed, compiled language has direct support to scoping with the help of keywords which are
mentioned when the method or field is declared. However Python does not have such keywords since it is a
scripting language, and it is interpreted instead of being compiled. Mainly, Access Modifiers can be categorized
as Public, Protected and Private in a class.
Python uses the '_' symbol to determine the access control for a specific data member or a member function of a
class. Access specifiers in Python have an important role to play in securing data from unauthorized access and
in preventing it from being exploited. But it is not like other languages like Java and C++ since Python uses the
concept of Name Mangling for achieving data hiding.
A Class in Python has three types of access modifiers:
Public Access Modifier: Theoretically, public methods and fields can be accessed directly by any class.
Protected Access Modifier: Theoretically, protected methods and fields can be accessed within the same
class it is declared and its subclass.
Private Access Modifier: Theoretically, private methods and fields can be only accessed within the same
class it is declared.
We are mentioning "Theoretically" because python doesn't follow the textbook definition of such specifications.
Instead, it depends on the programmer/organization as well as a unique feature of python called as name
mangling using which we can mimic the actual security provided by access modifiers.
Public Access Modifier:
The members of a class that are declared public are easily accessible from any part of the program. All data
members and member functions of a class are public by default.
# program to illustrate public access modifier in a class
class Geek:
# constructor
def __init__(self, name, age):
# public data members
[Link] = name
[Link] = age
# public member function
def displayAge(self):
# accessing public data member
print("Age: ", [Link])
# creating object of the class
obj = Geek("R2J", 20)
# finding all the fields and methods which are present inside obj
print("List of fields and methods inside obj:", dir(obj))
# accessing public data member
print("Name:", [Link])
# calling public member function of the class
[Link]()
Output
List of fields and methods inside obj: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'displayAge', 'geekAge', 'geekName']
Name: R2J
Age: 20
We are using dir() function to list down all the member variables and functions of the Geeks object which can
be accessed. We can clearly see geekName, geekAge, displayAge and other inbuilt methods such as __str__,
__sizeof__, etc. In the above program, geekName and geekAge are supposed to be public data members and
displayAge() method is a public member function of the class Geek. These data members of the class Geek can
be accessed from anywhere in the program since they are present in the list returned by dir() as it is.
Protected Access Modifier:
The members of a class that are declared protected are only accessible within the class where it is declared and
its subclass. To implement protected field or method, the developer follows a specific convention mostly by
adding prefix to the variable or function name. Popularly, a single underscore "_" is used to describe a protected
data member or method of the class. Note that the python interpreter does not treat it as protected data like other
languages, it is only denoted for the programmers since they would be trying to access it using plain name
instead of calling it using the respective prefix. For example,
# program to illustrate protected access modifier in a class
# super class
class Student:
# protected data members
_name = None
_roll = None
_branch = None
# constructor
def __init__(self, name, roll, branch):
self._name = name
self._roll = roll
self._branch = branch
# protected member function
def _displayRollAndBranch(self):
# accessing protected data members
print("Roll:", self._roll)
print("Branch:", self._branch)
# derived class
class Geek(Student):
# constructor
def __init__(self, name, roll, branch):
Student.__init__(self, name, roll, branch)
# public member function
def displayDetails(self):
# accessing protected data members of super class
print("Name:", self._name)
# accessing protected member functions of super class
self._displayRollAndBranch()
stu = Student("Alpha", 1234567, "Computer Science")
print(dir(stu))
# protected members and methods can be still accessed
print(stu._name)
stu._displayRollAndBranch()
# Throws error
# print([Link])
# [Link]()
# creating objects of the derived class
obj = Geek("R2J", 1706256, "Information Technology")
print("")
print(dir(obj))
# calling public member functions of the class
[Link]()
Output
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass_
_', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_branch', '_displayRollAndBranch', '_name', '_roll']
Alpha
Roll: 1234567
Branch: Computer Science
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__weakref__', '_branch', '_displayRollAndBranch', '_name', '_roll', 'displayDetails']
Name: R2J
Roll: 1706256
Branch: Information Technology
In the above program, _name, _roll, and _branch are protected data members and _displayRollAndBranch()
method is a protected method of the super class Student. The displayDetails() method is a public member
function of the class Geek which is derived from the Student class, the displayDetails() method in Geek class
accesses the protected data members of the Student class.
However, we can still access protected members of Student class directly by specifying the correct name of field
and method i.e. adding underscore before them since it was declared by that name. We can also see that these
declared fields and methods can be called since they are present in the list returned by the dir() function. If we
try to access the using plain names such as [Link] and [Link](), we get error since they
are not saved by that name. Underscores are mainly used since other characters like "$", "-", "&", etc. cannot be
present in variable or function name.
Private Access Modifier:
The members of a class that are declared private are accessible within the class only, private access modifier is
the most secure access modifier. Data members of a class are declared private by adding a double underscore
'__' symbol before the data member of that class.
# program to illustrate private access modifier in a class
class Geek:
# private members
__name = None
__roll = None
__branch = None
# constructor
def __init__(self, name, roll, branch):
self.__name = name
self.__roll = roll
self.__branch = branch
# private member function
def __displayDetails(self):
# accessing private data members
print("Name:", self.__name)
print("Roll:", self.__roll)
print("Branch:", self.__branch)
# public member function
def accessPrivateFunction(self):
# accessing private member function
self.__displayDetails()
# creating object
obj = Geek("R2J", 1706256, "Information Technology")
print(dir(obj))
print("")
# Throws error
# obj.__name
# obj.__roll
# obj.__branch
# obj.__displayDetails()
# To access private members of a class
print(obj._Geek__name)
print(obj._Geek__roll)
print(obj._Geek__branch)
obj._Geek__displayDetails()
print("")
# calling public member function of the class
[Link]()
Output
'_Geek__branch', '_Geek__displayDetails', '_Geek__name', '_Geek__roll', '__class__', '__delattr__', '__dict__',
'__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'accessPrivateFunction']
R2J
1706256
Information Technology
Name: R2J
Roll: 1706256
Branch: Information Technology
Name: R2J
Roll: 1706256
Branch: Information Technology
In the above program, __name, __roll and __branch are private members, __displayDetails() method is a private
member function (these can only be accessed within the class) and accessPrivateFunction() method is a public
member function of the class Geek which can be accessed from anywhere within the program. The
accessPrivateFunction() method accesses the private members of the class Geek.
However, we can still access private members of a class outside the class. We cannot directly call obj.__name,
obj.__age, obj.__branch, and obj.__displayDetails() because they throw errors. We can notice that in the list of
callable fields and methods, __name is saved as _Geek__name, __age is saved as _Geek__age, __branch is
saved as _Geek__branch and __displayDetails() is saved as _Geek__displayDetails(). This conversion is called
as name mangling, where the python interpreter automatically converts any member preceded with two
underscores to _<class name>__<member name>. Hence, we can still call all the supposedly private data
members of a class using the above convention.
Below is a program to illustrate the use of all the above three access modifiers (public, protected, and
private) of a class in Python:
# program to illustrate access modifiers of a class
# super class
class Super:
# public data member
var1 = None
# protected data member
_var2 = None
# private data member
__var3 = None
# constructor
def __init__(self, var1, var2, var3):
self.var1 = var1
self._var2 = var2
self.__var3 = var3
# public member function
def displayPublicMembers(self):
# accessing public data members
print("Public Data Member:", self.var1)
# protected member function
def _displayProtectedMembers(self):
# accessing protected data members
print("Protected Data Member:", self._var2)
# private member function
def __displayPrivateMembers(self):
# accessing private data members
print("Private Data Member:", self.__var3)
# public member function
def accessPrivateMembers(self):
# accessing private member function
self.__displayPrivateMembers()
# derived class
class Sub(Super):
# constructor
def __init__(self, var1, var2, var3):
Super.__init__(self, var1, var2, var3)
# public member function
def accessProtectedMembers(self):
# accessing protected member functions of super class
self._displayProtectedMembers()
# creating objects of the derived class
obj = Sub("Geeks", 4, "Geeks!")
# calling public member functions of the class
[Link]()
[Link]()
[Link]()
print()
# Can also be accessed using
obj._displayProtectedMembers()
obj._Super__displayPrivateMembers()
print()
# Object can access protected member
print("Object is accessing protected member:", obj._var2)
print("Object is accessing private member:", obj._Super__var3)
# object can not access private member, so it will generate Attribute error
# print(obj.__var3)
Output
Public Data Member: Geeks
Protected Data Member: 4
Private Data Member: Geeks!
Protected Data Member: 4
Private Data Member: Geeks!
Object is accessing protected member: 4
Object is accessing private member: Geeks!
In the above program, the accessProtectedMembers() method is a public member function of the
class Sub accesses the _displayProtectedMembers() method which is protected member function of the class
Super and the accessPrivateMembers() method is a public member function of the class Super which accesses
the __displayPrivateMembers() method which is a private member function of the class Super. Also note that all
these access modifiers are not strict like other languages such as C++, Java, C#, etc. since they can still be
accessed if they are called by their original or mangled names.
Private Variables in Python
Last Updated : 16 Jul, 2024
Prerequisite: Underscore in Python
In Python, there is no existence of “Private” instance variables that cannot be accessed except inside an object.
However, a convention is being followed by most Python code and coders i.e., a name prefixed with an
underscore, For e.g. _geek should be treated as a non-public part of the API or any Python code, whether it is a
function, a method, or a data member. While going through this we would also try to understand the concept of
various forms of trailing underscores, for e.g., for _ in range(10), __init__(self).
Mangling and how it works
In Python, there is something called name mangling, which means that there is limited support for a valid use-
case for class-private members basically to avoid name clashes of names with names defined by subclasses. Any
identifier of the form __geek (at least two leading underscores or at most one trailing underscore) is replaced
with _classname__geek, where classname is the current class name with a leading underscore(s) stripped. As
long as it occurs within the definition of the class, this mangling is done. This is helpful for letting subclasses
override methods without breaking intraclass method calls.
Let's look at this example and try to find out how this underscore works:
# Python code to illustrate how mangling works
class Map:
def __init__(self, iterate):
[Link] = []
self.__geek(iterate)
def geek(self, iterate):
for item in iterate:
[Link](item)
# private copy of original geek() method
__geek = geek
class MapSubclass(Map):
# provides new signature for geek() but
# does not break __init__()
def geek(self, key, value):
for i in zip(keys, value):
[Link](i)
The mangling rules are designed mostly to avoid accidents but it is still possible to access or modify a variable
that is considered private. This can even be useful in special circumstances, such as in the debugger.
_Single Leading Underscores
So basically one underline at the beginning of a method, function, or data member means you shouldn't access
this method because it's not part of the API. Let's look at this snippet of code:
# Python code to illustrate
# how single underscore works
def _get_errors(self):
if self._errors is None:
self.full_clean()
return self._errors
errors = property(_get_errors)
The snippet is taken from the Django source code (django/forms/[Link]). This suggests that errors are
property, and it's also a part of the API, but the method, _get_errors, is "private", so one shouldn't access it.
__Double Leading Underscores
Two underlines, in the beginning, cause a lot of confusion. This is about syntax rather than a convention. double
underscore will mangle the attribute names of a class to avoid conflicts of attribute names between classes. For
example:
# Python code to illustrate how double
# underscore at the beginning works
class Geek:
def _single_method(self):
pass
def __double_method(self): # for mangling
pass
class Pyth(Geek):
def __double_method(self): # for mangling
pass
__Double leading and Double trailing underscores__
There's another case of double leading and trailing underscores. We follow this while using special variables or
methods (called “magic method”) such as__len__, __init__. These methods provide special syntactic features to
the names. For example, __file__ indicates the location of the Python file, __eq__ is executed when a == b
expression is executed.
Example:
# Python code to illustrate double leading and
# double trailing underscore works
class Geek:
# '__init__' for initializing, this is a
# special method
def __init__(self, ab):
[Link] = ab
# custom special method. try not to use it
def __custom__(self):
pass
Private Methods in Python
Last Updated : 12 Jul, 2025
Encapsulation is one of the fundamental concepts in object-oriented programming (OOP) in Python. It describes
the idea of wrapping data and the methods that work on data within one unit. This puts restrictions on accessing
variables and methods directly and can prevent the accidental modification of data. A class is an example of
encapsulation as it encapsulates all the data that is member functions, variables, etc. Now, there can be some
scenarios in which we need to put restrictions on some methods of the class so that they can neither be accessed
outside the class nor by any subclasses. To implement this private methods come into play.
Private functions in Python
Consider a real-life example, a car engine, which is made up of many parts like spark plugs, valves, pistons, etc.
No user uses these parts directly, rather they just know how to use the parts which use them. This is what private
methods are used for. It is used to hide the inner functionality of any class from the outside world. Private
methods are those methods that should neither be accessed outside the class nor by any base class. In Python,
there is no existence of Private methods that cannot be accessed except inside a class. However, to define a
private method prefix the member name with the double underscore “__”. Note: The __init__ method is
a constructor and runs as soon as an object of a class is instantiated.
# Creating a Base class
class Base:
# Declaring public method
def fun(self):
print("Public method")
# Declaring private method
def __fun(self):
print("Private method")
# Creating a derived class
class Derived(Base):
def __init__(self):
# Calling constructor of
# Base class
Base.__init__(self)
def call_public(self):
# Calling public method of base class
print("\nInside derived class")
[Link]()
def call_private(self):
# Calling private method of base class
self.__fun()
# Driver code
obj1 = Base()
# Calling public method
[Link]()
obj2 = Derived()
obj2.call_public()
# Uncommenting obj1.__fun() will
# raise an AttributeError
# Uncommenting obj2.call_private()
# will also raise an AttributeError
Output:
Public method
Inside derived class
Public method
Traceback (most recent call last):
File "/home/[Link]", line 43, in
obj1.__fun()
AttributeError: 'Base' object has no attribute '__fun'
Traceback (most recent call last):
File "/home/[Link]", line 46, in
obj2.call_private()
File "/home/[Link]", line 32, in call_private
self.__fun()
AttributeError: 'Derived' object has no attribute '_Derived__fun'
The above example shows that private methods of the class can neither be accessed outside the class nor by any
base class. However, private methods can be accessed by calling the private methods via public methods.
Example:
# Creating a class
class A:
# Declaring public method
def fun(self):
print("Public method")
# Declaring private method
def __fun(self):
print("Private method")
# Calling private method via
# another method
def Help(self):
[Link]()
self.__fun()
# Driver's code
obj = A()
[Link]()
Output:
Public method
Private method
Name mangling
Python provides a magic wand that can be used to call private methods outside the class also, it is known as
name mangling. It means that any identifier of the form __geek (at least two leading underscores or at most one
trailing underscore) is replaced with _classname__geek, where the class name is the current class name with a
leading underscore(s) stripped.
Example:
# Creating a class
class A:
# Declaring public method
def fun(self):
print("Public method")
# Declaring private method
def __fun(self):
print("Private method")
# Driver's code
obj = A()
# Calling the private member
# through name mangling
obj._A__fun()
Output:
Private method
Protected variable in Python
Last Updated : 12 Jul, 2025
Prerequisites: Underscore ( _ ) in Python A Variable is an identifier that we assign to a memory location which
is used to hold values in a computer program. Variables are named locations of storage in the program. Based on
access specification, variables can be public, protected and private in a class. Protected variables are those data
members of a class that can be accessed within the class and the classes derived from that class. In Python, there
is no existence of “Public” instance variables. However, we use underscore '_' symbol to determine the access
control of a data member in a class. Any member prefixed with an underscore should be treated as a non-public
part of the API or any Python code, whether it is a function, a method or a data member. Example 1:
# program to illustrate protected
# data members in a class
# Defining a class
class Geek:
# protected data members
_name = "R2J"
_roll = 1706256
# 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()
# calling public member
# functions of the class
[Link]()
Output:
Name: R2J
Roll: 1706256
Example 2: During Inheritance
# program to illustrate protected
# data members in a class
# super class
class Shape:
# constructor
def __init__(self, length, breadth):
self._length = length
self._breadth = breadth
# public member function
def displaySides(self):
# accessing protected data members
print("Length: ", self._length)
print("Breadth: ", self._breadth)
# derived class
class Rectangle(Shape):
# constructor
def __init__(self, length, breadth):
# Calling the constructor of
# Super class
Shape.__init__(self, length, breadth)
# public member function
def calculateArea(self):
# accessing protected data members of super class
print("Area: ", self._length * self._breadth)
# creating objects of the
# derived class
obj = Rectangle(80, 50)
# calling derived member
# functions of the class
[Link]()
# calling public member
# functions of the class
[Link]()
Output:
Length: 80
Breadth: 50
Area: 4000
In the above example, the protected variables _length and _breadth of the super class Shape are accessed within
the class by a member function displaySides() and can be accessed from class Rectangle which is derived from
the Shape class. The member function calculateArea() of class Rectangle accesses the protected data
members _length and _breadth of the super class Shape to calculate the area of the rectangle.