Encapsulation
Encapsulation
Bundling of data. In this you will take care of attributes availability to outer world for modification by using access modifiers. As python has three types of access modifiers.
- public - no underscore before any variable/method
- protected - _ single underscore before any variable/method
- private - __ double underscore before any variable/method
Why is it needed?
- Helps keep related fields and methods together
- Makes are code cleaner and easier to read
- Provides more flexibility to our code
- Provides more reusability with our code
- Hide values which a coder must not change or not need to see
Example: When no access modifier is provided in Enemy.py class file then main.py implementation can cause issues by modifying values of attribute.
main.py
example:
from Enemy import *
zombie = Enemy('Zombie')
zombie.typeOfEnemy = 'Orc' # As you can see initialized value got modified by external user.
zombie.talk()
zombie.walk_forward()
zombie.attack()
To safeguard from this security breach or mis-use of code we need to use encapsulation and it's working.
In short by using encapsulation we can put guardrail on code which will provide users on restriction basis to use resources or to modify them.
So to make is possible we need to make attributes private in place of public.
You can make it by using __ (double underscore at the start of any attribute name to make it private)
Example:
Emcapsulaton.py
# Implementing encapsulation in Python for enemy class
class Enemy:
# Defining priovate attributes by using double underscore
def __init__(self, typeOfEnemy: str, healthPoints: int = 10,
attack_damage: int = 1):
self.__typeOfEnemy = typeOfEnemy
self.__healthPoints = healthPoints
self.__attack_damage = attack_damage
print(f'New enemy created! Type: {self.__typeOfEnemy}, Health:
{self.__healthPoints}, Attack Damage: {self.__attack_damage}')
# Getter method for typeOfEnemy
def get_typeOfEnemy(self):
return self.__typeOfEnemy
# If we want to not allow anyone to change initialized attribute values
# then we need to remove setter from class.
# Setter method for typeOfEnemy
def set_typeOfEnemy(self, typeOfEnemy: str):
self.__typeOfEnemy = typeOfEnemy
def talk(self):
print(f"I am a {self.__typeOfEnemy}. Be prepared to fight!")
main.py
# file to use enemy class file
#from Enemy import Enemy
from Encapsulation import Enemy
"""
enemy = Enemy() # calling a constructor of the class Enemy() -> This keyword.
# print(enemy.typeOfEnemy) this part of code will fail
# as no value is assigned in class for this attribute.
enemy.typeOfEnemy = "Goblin" # Assigning a value to the typeOfEnemy attribute
enemy.talk() # This will call the talk method from the Enemy class
enemy.walk_forward() # This will call the walk_forward method from the Enemy class
enemy.attack() # This will call the attack method from the Enemy class
print(enemy.typeOfEnemy) # now it will work.
print(enemy.healthPoints)
print(enemy.attack_damage)
"""
enemy2 = Enemy(typeOfEnemy="Orc", healthPoints=20, attack_damage=5)
# Creating another instance of the Enemy class with parameters
enemy3 = Enemy(typeOfEnemy="Dragon")
# Creating another instance of the Enemy class with parameters
print(f"Enemy type = {enemy3.get_typeOfEnemy()}")
# This will call the getter method for typeOfEnemy
Enemy.py file content:
# Defining class with access modifiers to implement encapsulation.
class Enemy:
typeOfEnemy: str
healthPoints: int = 10
attack_damage: int = 1
# Defining public attributes
"""
def __init__(self, typeOfEnemy: str, healthPoints: int = 10, attack_damage: int = 1):
self.typeOfEnemy = typeOfEnemy
self.healthPoints = healthPoints
self.attack_damage = attack_damage
print(f'New enemy created! Type: {self.typeOfEnemy}, Health: {self.healthPoints}, Attack Damage: {self.attack_damage}')
"""
# Defining private attributes by using double underscore
def __init__(self, typeOfEnemy: str, healthPoints: int = 10, attack_damage: int = 1):
self.__typeOfEnemy = typeOfEnemy
self.__healthPoints = healthPoints
self.__attack_damage = attack_damage
print(f'New enemy created! Type: {self.__typeOfEnemy}, Health: {self.__healthPoints}, Attack Damage: {self.__attack_damage}')
def talk(self):
print(f"I am a {self.__typeOfEnemy}. Be prepared to fight!")
def walk_forward(self):
print(f"{self.__typeOfEnemy} moves closer to you!")
def attack(self):
print(f"{self.__typeOfEnemy} attacks you for {self.__attack_damage} damage!")
# Getter method for typeOfEnemy
def get_typeOfEnemy(self):
return self.__typeOfEnemy
main.py file content:
# file to use encapsulation class file
from Enemy import Enemy
# Creating an instance of the Enemy class with parameters
zombie = Enemy(typeOfEnemy="Zombie", healthPoints=15, attack_damage=3)
#Overriding already initailized attribute value
# This will not change the private attribute __typeOfEnemy
# In this case you have created a local variable with instance reference and you are trying to print is so it will show you the result.
# But if you want to change the value of private attribute then you need to use setter method.
zombie.typeofEnemy = "Orge"
print(f"Enemy type = {zombie.typeofEnemy}") # This will call the getter method for typeOfEnemy
print(f"Enemy type from instance = {zombie.get_typeOfEnemy()}") # This will call the getter method for typeOfEnemy
#Analysis:
"""
PS C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation> python .\main.py
Traceback (most recent call last):
File "C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation\main.py", line 2, in <module>
from encapsulation.Encapsulation import Enemy
ModuleNotFoundError: No module named 'encapsulation'
PS C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation> python .\main.py
Traceback (most recent call last):
File "C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation\main.py", line 2, in <module>
from encapsulation.Enemy import Enemy
ModuleNotFoundError: No module named 'encapsulation'
PS C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation> python .\main.py
Traceback (most recent call last):
File "C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation\main.py", line 5, in <module>
zombie = Enemy(typeOfEnemy="Zombie", healthPoints=15, attack_damage=3)
File "C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation\Enemy.py", line 13, in __init__
print(f'New enemy created! Type: {self.__typeOfEnemy}, Health: {self.__healthPoints}, Attack Damage: {self.__attack_damage}')
^^^^^^^^^^^^^^^^^^
AttributeError: 'Enemy' object has no attribute '_Enemy__typeOfEnemy'. Did you mean: 'get_typeOfEnemy'?
PS C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation> python .\main.py
New enemy created! Type: Zombie, Health: 15, Attack Damage: 3
Enemy type = Orge
PS C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation> python .\main.py
New enemy created! Type: Zombie, Health: 15, Attack Damage: 3
Enemy type = Orge
PS C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation> python .\main.py
New enemy created! Type: Zombie, Health: 15, Attack Damage: 3
Enemy type = Orge
Traceback (most recent call last):
File "C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation\main.py", line 14, in <module>
print(f"Enemy type from instance = {zombie.get_typeOfEnemy()}") # This will call the getter method for typeOfEnemy
~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation\Enemy.py", line 34, in get_typeOfEnemy
return self.typeOfEnemy
^^^^^^^^^^^^^^^^
AttributeError: 'Enemy' object has no attribute 'typeOfEnemy'. Did you mean: 'typeofEnemy'?
PS C:\Users\punee\OneDrive\Desktop\FastAPILearning\encapsulation> python .\main.py
New enemy created! Type: Zombie, Health: 15, Attack Damage: 3
Enemy type = Orge
Enemy type from instance = Zombie
"""
Comments
Post a Comment