In Python, encapsulation represents a core principle of object-oriented programming (OOP). This concept pertains to a class as a grouping of data (variables) and the associated methods that manipulate that data.
Encapsulation limits direct access to certain elements of an object, thereby helping to prevent unintended interference and potential data corruption.
How does Encapsulation Work in Python?
In Python, encapsulation is achieved by preventing users from directly interacting with specific components of an object, while still providing access to those components through alternative methods.
Access can be controlled using different access modifiers :
- Public Attribute: Accessible from anywhere.
- Protected Attributes (_singleUnderscore ) : Not intended for public use, but still accessible.
- Private Attributes (__doubleUnderscore): Not directly accessible from outside the class.
| Member Type | Syntax | Accessible Inside Class | Accessible in Subclasses | Accessible Outside Class |
|---|---|---|---|---|
| Public | self.var | Yes | Yes | Yes |
| Protected | self._var | Yes | Yes (Recommended inside subclasses only) | Yes (Not recommended) |
| Private | self.__var | Yes | No (Unless using name mangling) | No (Direct access restricted) |
Implementation of Encapsulation in Python
Python uses three levels of access control for class members:
- public,
- protected, and
- private.
Let's explore each with examples.
Public Members
Public members are accessible from any location, including within the class itself, from outside the class, and within any derived (child) classes.
- Usage: There should be no underscore preceding the variable name.
Python Public Members Example
Let us consider an example to illustrate the concept of public members in Python.
Example
class Car:
def __init__(self, brand, model):
self.brand = brand # Public attribute
self.model = model # Public attribute
def display(self):
print(f"Car: {self.brand} {self.model}")
# Creating an object
car = Car("Toyota", "Corolla")
# Accessing public members
print(car.brand)
print(car.model)
# Calling public method
car.display()
Output:
Toyota
Corolla
Car: Toyota Corolla
Explanation:
The public attributes (brand, model) will be available for access from outside the class. Additionally, the display method, which is also designated as public, can be invoked from other classes.
Protected Members
Protected attributes are denoted by a single underscore (_variable).
- Usage: These can be accessed from outside the class, yet they are intended to be used only within the class itself and its subclasses (this is a convention rather than a strict rule).
Python Protected Members Example
Let us consider an example to illustrate the concept of protected members in Python.
Example
class Car:
def __init__(self, brand, model, engine):
self.brand = brand # Public attribute
self._model = model # Protected attribute
self._engine = engine # Protected attribute
def _show_details(self): # Protected method
print(f"Brand: {self.brand}, Model: {self._model}, Engine: {self._engine}")
class ElectricCar(Car):
def __init__(self, brand, model, battery_capacity):
super().__init__(brand, model, "Electric")
self.battery_capacity = battery_capacity
def show_info(self):
self._show_details() # Accessing protected method from subclass
print(f"Battery: {self.battery_capacity} kWh")
# Creating an object of ElectricCar
tesla = ElectricCar("Tesla", "Model S", 100)
# Accessing protected members from subclass
tesla.show_info()
# Accessing protected members outside the class (not recommended)
print(tesla._model) # Works, but not recommended
Output:
Brand: Tesla, Model: Model S, Engine: Electric
Battery: 100 kWh
Model S
Explanation:
The attributes model and engine are designated as protected, while the method showdetails is also classified as protected. These elements can be accessed within subclasses; however, it is generally advised against directly utilizing them outside of their defining class.
Private Members
Private attributes are denoted by double underscores (__variable).
- Usage: Such members cannot be accessed directly from outside the class.
Python Private Members Example
Let's consider an illustration to showcase the concept of private members in Python.
Example
class BankAccount:
def __init__(self, account_number, balance):
self.account_number = account_number # Public attribute
self.__balance = balance # Private attribute
def get_balance(self): # Getter method
return self.__balance
def set_balance(self, amount): # Setter method
if amount >= 0:
self.__balance = amount
else:
print("Invalid amount! Balance cannot be negative.")
# Creating an account object
account = BankAccount("123456789", 1000)
# Accessing public member
print(account.account_number) # Works fine
# Trying to access private member directly (will raise AttributeError)
# print(account.__balance) # Uncommenting this will cause an error
# Using getter method to access private attribute
print(account.get_balance()) # Works fine
# Using setter method to update private attribute
account.set_balance(2000)
print(account.get_balance()) # Updated balance
# Accessing private attribute using name mangling (Not recommended)
print(account._BankAccount__balance) # Works, but should be avoided
Output:
123456789
1000
2000
2000
Explanation:
The attribute _balance is designated as private, which means it cannot be accessed directly. To manage access to this attribute, we employ getter (getbalance) and setter (setbalance) methods. Internally, Python alters the name of balance to BankAccount__balance, enabling access through name mangling. However, this practice is generally discouraged.
Conclusion
Encapsulation conceals the internal workings and the implementation specifics of an object's properties by restricting direct access. In Python, encapsulation is achieved using public, protected, and private members for class attributes, along with managing access through getters and setters. This practice enhances the security, maintainability, and organization of the code due to the convention-driven methodology utilized in Python.
Encapsulation in Python FAQs
1. What is Encapsulation in Python?
Encapsulation is a fundamental concept in object-oriented programming that restricts direct access to an object's data and its associated methods. Instead, access is facilitated through regulated interfaces known as public methods, which guarantees that the data remains secure and safeguarded.
2. How is Encapsulation Implemented in Python?
Encapsulation is achieved through the use of access specifiers:
- Self Variable (self.var): Public Members are accessible from any location. Protected Members, indicated by a single underscore (_var), signify that they are intended for internal use only.
- Double underscore(__var): This refers to Private Members, which implies that direct access to them is restricted.
3. Why is Encapsulation Important?
Encapsulation Provides:
- Intended modification is prevented so data is secured.
- Defined methods are the only way data can be accessed meaning method controlled access is provided.
- Structure and Modularity improves so the code becomes maintainable.
4. How Do Getters and Setters Work in Encapsulation?
Private variables can be accessed through the use of getter and setter methods, which serve distinct purposes.
Example
class BankAccount:
def __init__(self, balance):
self.__balance = balance
def get_balance(self): # Getter
return self.__balance
def set_balance(self, amount): # Setter
if amount >= 0:
self.__balance = amount
else:
print("Invalid amount!")
account = BankAccount(1000)
print(account.get_balance())
account.set_balance(2000)
print(account.get_balance())
Output:
1000
2000
5. Can Private Members Be Accessed Outside the Class in Python?
Direct access to the class attribute is prohibited, which prevents us from accessing it directly. Nevertheless, we can retrieve the private variable by utilizing name mangling. This is done by using the syntax (ClassName_privateVar).