Python
Python Basics
- Introduction to Python and Its History
- Python Syntax and Indentation
- Python Variables and Data Types
- Dynamic and Strong Typing
- Comments and Docstrings
- Taking User Input (input())
- Printing Output (print())
- Python Operators (Arithmetic, Logical, Comparison)
- Type Conversion and Casting
- Escape Characters and Raw Strings
Data Structures in Python
- Lists
- Dictionaries
- Dictionary Comprehensions
- Strings and String Manipulation
- Tuples
- Python Sets: Unordered Collections
- List Comprehensions and Generator Expressions
- Set Comprehensions
- String Formatting
- Indexing and Slicing
Control Flow and Loops
- Conditional Statements: if, elif, and else
- Loops and Iteration
- While Loops
- Nested Loops
- Loop Control Statements
- Iterators and Iterables
- List, Dictionary, and Set Iterations
Functions and Scope
- Defining and Calling Functions (`def`)
- Function Arguments (`*args`, `**kwargs`)
- Default Arguments and Keyword Arguments
- Lambda Functions
- Global and Local Scope
- Function Return Values
- Recursion in Python
Object-Oriented Programming (OOP)
- Object-Oriented Programming
- Classes and Objects
- the `__init__()` Constructor
- Instance Variables and Methods
- Class Variables and `@classmethod`
- Encapsulation and Data Hiding
- Inheritance and Subclasses
- Method Overriding and super()
- Polymorphism
- Magic Methods and Operator Overloading
- Static Methods
- Abstract Classes and Interfaces
Python Programs
- Array : Find median in an integer array
- Array : Find middle element in an integer array
- Array : Find out the duplicate in an array
- Array : Find print all subsets in an integer array
- Program : Array : Finding missing number between from 1 to n
- Array : Gap and Island problem
- Python Program stock max profit
- Reverse words in Python
- Python array duplicate program
- Coin change problem in python
- Python Write fibonacci series program
- Array : find all the pairs whose sum is equal to a given number
- Find smallest and largest number in array
- Iterate collections
- List comprehensions
- Program: Calculate Pi in Python
- String Formatting in Python
đ Encapsulation and Data Hiding in Python (_protected
, __private
)
One of the key pillars of object-oriented programming (OOP) is encapsulation. If youâve heard of the phrase âDonât touch what you shouldnât,â you already get the gist. Encapsulation helps protect the internal state of an object by restricting direct access to some of its attributes or methods.
In Python, encapsulation is achieved using access specifiers like _protected
and __private
, even though Python doesnât enforce strict access control like languages such as Java or C++. Instead, Python relies on conventions and name mangling to manage access levels.
In this guide, weâll explore:
- What encapsulation is
- The concept of data hiding
- Pythonâs naming conventions (
_
and__
) - Practical examples of using encapsulation
- Why and when to use it
đȘ What is Encapsulation?
Encapsulation is the practice of bundling data (variables) and methods (functions) that operate on that data into a single unitâtypically a class. More importantly, it controls who can access or modify that data.
Imagine youâre using a vending machine. You donât need to know how it works internallyâyou just press a button. Similarly, in encapsulated code, users interact through defined interfaces (methods), without worrying about the internal logic.
đ§± Benefits of Encapsulation
- â Protects object integrity by preventing outside interference
- â Simplifies code and hides complexity
- â Encourages modular, maintainable design
- â Makes the code easier to debug and test
- â Enables future-proofing: internals can change without breaking user code
đ€« What is Data Hiding?
Data hiding is a part of encapsulation that prevents direct access to class variables from outside the class. This is where _protected
and __private
come into play in Python.
Unlike other languages that use keywords like private
, protected
, or public
, Python uses naming conventions:
Prefix | Access Level | Description |
---|---|---|
None | Public | Accessible from anywhere |
_var | Protected | Should not be accessed outside the class or subclass |
__var | Private | Name mangled to prevent outside access |
đ Public Variables (Default)
Any variable or method that doesnât start with _
or __
is public.
class Person: def __init__(self, name): self.name = name
p = Person("Alice")print(p.name) # Output: Alice
Here, name
is public and can be accessed or modified directly.
đĄïž Protected Variables (_single_underscore
)
A single underscore (_
) before a variable indicates itâs protected, meaning it should not be accessed outside the class or its subclasses.
Itâs a convention, not a rule.
class Person: def __init__(self, name, age): self.name = name self._age = age # Protected
def show_age(self): print(f"{self.name} is {self._age} years old")
p = Person("Bob", 30)print(p._age) # Technically allowed, but discouraged
The _age
attribute can still be accessed, but youâre saying to other developers: âDonât touch this unless you know what youâre doing.â
đ Private Variables (__double_underscore
)
Two leading underscores (__
) trigger name mangling, where Python internally changes the variable name to include the class name. This makes it harder (not impossible) to access from outside.
class BankAccount: def __init__(self, balance): self.__balance = balance # Private
def get_balance(self): return self.__balance
account = BankAccount(1000)print(account.get_balance()) # â
Output: 1000# print(account.__balance) â AttributeError
Trying to access __balance
directly will fail, but you can still do this:
print(account._BankAccount__balance) # đ
Output: 1000 (Not recommended)
Thatâs why itâs called name manglingâPython rewrites __balance
internally as _BankAccount__balance
.
đ§Ș Example: Full Encapsulation with Getters & Setters
You can create fully encapsulated classes by providing controlled access to attributes through getters and setters.
class Employee: def __init__(self, name, salary): self.__name = name self.__salary = salary
def get_salary(self): return self.__salary
def set_salary(self, amount): if amount > 0: self.__salary = amount else: print("Invalid salary!")
emp = Employee("John", 50000)print(emp.get_salary()) # Output: 50000emp.set_salary(60000)print(emp.get_salary()) # Output: 60000emp.set_salary(-1000) # Output: Invalid salary!
Here, direct access to __salary
is blocked. Any changes must go through the set_salary()
method, which adds validation.
đ§ Best Practices
- Use public attributes only when safe to expose.
- Use protected attributes when you want limited access but still allow subclass interaction.
- Use private attributes when you want to hide implementation details completely.
- Encapsulate behavior using getters and setters, especially if logic like validation is required.
- Donât overuse private attributes unless necessaryâPython favors consenting adults over strict access control.
đ Use Case: Banking System with Protected and Private Data
class BankAccount: def __init__(self, name, balance): self.name = name self._account_type = "Savings" # Protected self.__balance = balance # Private
def deposit(self, amount): if amount > 0: self.__balance += amount
def withdraw(self, amount): if 0 < amount <= self.__balance: self.__balance -= amount
def get_balance(self): return self.__balance
account = BankAccount("Alice", 1000)account.deposit(500)print(account.get_balance()) # Output: 1500print(account._account_type) # Output: Savings (not recommended)# print(account.__balance) # AttributeError
This example mimics real-world systems where you donât want users directly modifying the balanceâonly through trusted interfaces.
đ§Ż Encapsulation vs Abstraction
Many beginners confuse these two terms:
Term | Definition |
---|---|
Encapsulation | Bundling data and methods + access control |
Abstraction | Hiding internal logic and showing only relevant features |
They work together to secure and simplify code.
â Summary
- Encapsulation in Python controls access to class data using naming conventions.
- Use:
- Public for open access
_protected
for limited access (by subclass)__private
for full restriction (via name mangling)
- Use getters and setters to access private data safely.
- Python doesnât enforce strict access controlâyou, the developer, are responsible.
đ Final Thoughts
Python may not have rigid access modifiers like other languages, but its clear and developer-friendly approach to encapsulation works incredibly well. By following simple naming conventions and using built-in mechanisms like name mangling and method-based access, you can build robust and secure class designs.
Encapsulation isnât about hiding your codeâitâs about protecting your data.