Encapsulation Hands-On: Basics

kameshcodes

This is a two-part blog series on Encapsulation in Python:

  1. Encapsulation Hands-on: Basics
  2. Encapsulation Hands-on: Advanced


Encapsulation in simplest terms is bundling the data and protecting it.

Precisely, with encapsulation

  • You store data inside a class.
  • You restrict direct access to that data from outside the class.
  • You give controlled access using methods.
class Agent:
  def __init__(self, name, age):
    self.name = name
    self.age = age
agent1 = Agent("Kamesh", 25)
agent1
<__main__.Agent at 0x7e652d090a10>
agent1.age
25
agent1.age = -5
agent1.age
-5

This is a problem


  1. Age shouldn't be negative!
  2. Anyone can change agent1.age to something invalid. There's no protection.

Although in Python, we can't make truly private variables, but we can discourage access using naming conventions.


  • _var = protected (internal use; not enforced)

  • __var = private (name mangling adds safety)

Protected class var using\textbf{Protected class var using} _

class Agent:
  def __init__(self, name, age):
    self.name = name
    self._age = age
agent2 = Agent("Priya", 23)
agent2._age
23
agent2._age = -5
agent2._age
-5
  • _var is a convention, not a rule.
  • It signals: "This is for internal use only — treat it as 'protected'."

Private class var using\textbf{Private class var using} __

class Agent:
  def __init__(self, name, age):
    self.name = name
    self.__age = age
agent3 = Agent("Kritik", 22)
agent3.__age
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/tmp/ipython-input-14-1681600426.py in <cell line: 0>()
----> 1 agent3.__age

AttributeError: 'Agent' object has no attribute '__age'

You can't access the class variable directly because it's private.


However, you can still access it using name mangling by prefixing it with _ClassName.


agent3._Agent__age
22

You see.. This is name mangling.

Name mangling is a process used by Python to internally change the name of a variable to avoid accidental access or override.



agent3.__age           # AttributeError

agent3._Agent__age     # Works due to name mangling;
                       # Syntax: `_ClassName__varName`

and and and, You can still access and manipulate mangled variables.

agent3._Agent__age = -5
agent3._Agent__age
-5

The Right Way


class Agent:
  def __init__(self, name, age):
    self.name = name
    self.__age = age

  def get_age(self): # This get method gives you access to variable from outside the class.
    return self.__age

  def set_age(self, age):
    if age >= 0:
      self.__age = age
    else:
      raise ValueError("Invalid age!")
agent4 = Agent("Kritik", 22)
agent4.__age
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/tmp/ipython-input-20-638608875.py in <cell line: 0>()
----> 1 agent4.__age

AttributeError: 'Agent' object has no attribute '__age'

You can't access the variables directly, but you can access them using method defined in class.

agent4.get_age()
22
agent4.set_age(-5) # since -5 is not valid age value in our class raises error
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipython-input-22-3620207664.py in <cell line: 0>()
----> 1 agent4.set_age(-5) # since -5 is not valid age value in our class raises error

/tmp/ipython-input-18-2719234968.py in set_age(self, age)
     11       self.__age = age
     12     else:
---> 13       raise ValueError("Invalid age!")

ValueError: Invalid age!

But, If you set valid age:

agent4.set_age(5)
agent4.get_age()
5

It works.

Hope by Now:

  1. You understand that encapsulation protects data.
  2. You can write a class with private attributes using __var.
  3. You understand that Python uses name mangling, not strict privacy.
  4. You see why unrestricted access to internal data is dangerous.
  5. These attributes can be accessed using get_ and set_ methods.
  • Note that this get_ and set_ naming is a convention among python community, not a rule. You're free to use other method names.


Note:

Happy Learning ☺️


Made with REPL Notes Build your own website in minutes with Jupyter notebooks.