Python OOP Access Modifiers: Public, Protected, and Private

Learn about Python's access modifiers used in object-oriented programming to control access to class members. Understand the distinctions between public, protected, and private members, and how they affect access within and outside the class.



Python - Access Modifiers

The Python access modifiers are used to restrict access to class members (i.e., variables and methods) from outside the class. There are three types of access modifiers: public, protected, and private.

  • Public members − A class member is said to be public if it can be accessed from anywhere in the program.
  • Protected members − They are accessible from within the class as well as by classes derived from that class.
  • Private members − They can be accessed from within the class only.

Usually, methods are defined as public and instance variables are private. This arrangement ensures the principle of encapsulation.

Access Modifiers in Python

Unlike C++ and Java, Python does not use the Public, Protected, and Private keywords to specify the type of access modifiers. By default, all the variables and methods in a Python class are public.

Example

class Employee:
    'Common base class for all employees'
    def __init__(self, name="Bhavana", age=24):
        self.name = name
        self.age = age

e1 = Employee()
e2 = Employee("Bharat", 25)

print("Name: {}".format(e1.name))
print("Age: {}".format(e1.age))
print("Name: {}".format(e2.name))
print("Age: {}".format(e2.age))
        
Output

Name: Bhavana
Age: 24
Name: Bharat
Age: 25
        

Python doesn't enforce restrictions on accessing any instance variable or method. However, Python prescribes a convention of prefixing the name of a variable/method with a single or double underscore to emulate the behavior of protected and private access modifiers.

  • To indicate that an instance variable is private, prefix it with a double underscore (e.g., __age).
  • To imply that a certain instance variable is protected, prefix it with a single underscore (e.g., _salary).
Another Example

class Employee:
    def __init__(self, name, age, salary):
        self.name = name # public variable
        self.__age = age # private variable
        self._salary = salary # protected variable

    def displayEmployee(self):
        print("Name : ", self.name, ", age: ", self.__age, ", salary: ", self._salary)

e1 = Employee("Bhavana", 24, 10000)

print(e1.name)
print(e1._salary)
print(e1.__age)
        
Output

Bhavana
10000
Traceback (most recent call last):
    File "example.py", line 14, in 
        print(e1.__age)
               ^^^^^^^^
AttributeError: 'Employee' object has no attribute '__age'
        

Python displays an AttributeError because __age is private and not available for use outside the class.

Name Mangling

Python doesn't block access to private data; it just leaves it up to the programmer's wisdom not to write any code that accesses it from outside the class. You can still access the private members by Python's name mangling technique.

Name mangling is the process of changing the name of a member with a double underscore to the form object._class__variable. If required, it can still be accessed from outside the class, but this practice should be refrained from.

In our example, the private instance variable __age can be accessed as e1._Employee__age.

Modified Print Statement

print(e1._Employee__age)
        
Output

24
        

Python Property Object

Python's standard library has a built-in property() function. It returns a property object and acts as an interface to the instance variables of a Python class.

Syntax

property(fget=None, fset=None, fdel=None, doc=None)
        

The property() function uses getter, setter, and delete methods defined in a class to define a property object for the class.

Getters and Setter Methods

A getter method retrieves the value of an instance variable, usually named as get_varname, whereas the setter method assigns value to an instance variable, named as set_varname.

Example

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

    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age

    def set_name(self, name):
        self.__name = name

    def set_age(self, age):
        self.__age = age

e1 = Employee("Bhavana", 24)
print("Name:", e1.get_name(), "age:", e1.get_age())
e1.set_name("Archana")
e1.set_age(21)
print("Name:", e1.get_name(), "age:", e1.get_age())
        
Output

Name: Bhavana age: 24
Name: Archana age: 21
        

The getter and setter methods can retrieve or assign values to instance variables. The property() function uses them to add property objects as class attributes.

Defining Property

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

    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age

    def set_name(self, name):
        self.__name = name

    def set_age(self, age):
        self.__age = age

    name = property(get_name, set_name, "name")
    age = property(get_age, set_age, "age")

e1 = Employee("Bhavana", 24)
print("Name:", e1.name, "age:", e1.age)

e1.name = "Archana"
e1.age = 23
print("Name:", e1.name, "age:", e1.age)
        
Output

Name: Bhavana age: 24
Name: Archana age: 23