# Public, Private And Protected Access Modifiers In Python

Python is an object-oriented programming (OOPs) language in which Classes are integral. Classes are so powerful in object-oriented programming that we can perform high-level tasks like inheritance, abstraction, encapsulation and polymorphism.

In short, Python classes provide a way to organize code, encapsulate data and behaviour, create reusable templates for objects, and implement inheritance. Classes offer a powerful way to organize and manage complex code, promote reusability and make the code easier to read and understand.

We can control the access of the variables and methods inside the Python classes. Access modifiers are used to control access to the variables and methods.

# Access modifiers

Access modifiers play an important role in securing the data from unauthorized access and preventing any data exploitation.

Using the underscore (`_`), we can control access to the data inside the Python classes. Python Class has three types of access modifiers:

* **Public Access Modifier**
    
* **Private Access Modifier**
    
* **Protected Access Modifier**
    

Let's understand those above-mentioned access modifiers one by one.

# Public Access Modifier

The name "**Public**" says all about this access modifier the variables and methods declared inside the specific Python class can be accessed by that class and any Python class outside that specific class.

Public methods are accessible outside the class and with the help of objects the public methods can be invoked inside the class.

All the variables and methods in a Python class are **public** by default and just like mentioned above can be accessed from outside the class environment. Here's an example that will help us understand better.

```python
class Hero:
    def __init__(self, real_name, reel_name, hero_name):
        self.real_name = real_name
        self.reel_name = reel_name
        self.hero_name = hero_name

hero = Hero("RDJ", "Tony Stark", "Iron Man")

print("Real name: ", hero.real_name)
print("Reel name: ", hero.reel_name)
print("Hero name: ", hero.hero_name)
```

In the above code, we defined a Python class named `Hero` in which we created a constructor that accepts three arguments named `real_name`, `reel_name`, and `hero_name`.

Then we created a variable called `hero` outside the class and instantiated the class `Hero` with corresponding arguments and then printed the values.

```python
Real name:  RDJ
Reel name:  Tony Stark
Hero name:  Iron Man
```

Here, `real_name`, `reel_name` and `hero_name` are public data members and can be used anywhere in the program. We can also create a public member function inside the class and access it. The following example will show how to do it.

```python
class Hero:
    def __init__(self, real_name, reel_name, hero_name):
        self.real_name = real_name
        self.reel_name = reel_name
        self.hero_name = hero_name

    def display_name(self):
        print("Real name :", self.real_name)
        print("Reel name :", self.reel_name)

hero = Hero("Chris Evans", "Steve Rogers", "Captain America")
hero.display_name()
print("Hero name: ", hero.hero_name)
```

In the above code, `display_name` is a public member function and we accessed it outside the class. The code will run without any errors.

```python
Real name : Chris Evans
Reel name : Steve Rogers
Hero name:  Captain America
```

We can use these variables in other functions also and the following code shows how to do it.

```python
def access_public_data():
    x = Hero("Andrew Garfield", "Peter Parker", "Spider-man")
    print("Real name: ", x.real_name)
    print("Reel name: ", x.reel_name)
    print("Hero name: ", x.hero_name)

access_public_data()
```

We created a function called `access_public_data` and instantiated the class `Hero` which we made earlier and passed the required arguments and called that function. Since the variables inside the `Hero` class are public, the code will run without any error.

```python
Real name:  Andrew Garfield
Reel name:  Peter Parker
Hero name:  Spider-man
```

# Protected Access Modifier

Protected variables and methods are accessible within the specific class environment and can also be accessed by the sub-classes. We can also say that it allows the resources of the parent class to be inherited by the child class.

Any variables or methods prefixed with a **single underscore** (`_`) in a class are **protected** and can be accessed within the specific class environment. The protected variables/methods can be accessed inside the sub-classes of the parent class.

Here is a code to make protected variables/methods inside the Python class.

```python
class Anime:
    _rating = "Best"
    def __init__(self, anime, release_year):
        self._anime = anime
        self._release_year = release_year

    def _show(self):
        print("Release:", self._release_year)

obj = Anime("Naruto", 2002)
print("Anime:", obj._anime)
obj._show()
```

In the above code, `_anime` and `_release_year` which are protected instance variables inside the class `Anime` as well as it has a protected function called `_show`.

In the next block of code, we instantiated the class `Anime` and passed the required arguments and stored them inside the object named `obj` then displayed the result by calling the **protected** function and variable.

```python
Anime: Naruto
Release: 2002
```

We can also access these protected instance variables and protected functions inside the derived class.

```python
# Derived class
class Other_Anime(Anime):
    def __init__(self, anime, year):
        Anime.__init__(self, anime, year)

    def show_anime(self):
        print("Anime:", self._anime)
        self._show()

x = Other_Anime("Demon Slayer", 2019)
x.show_anime()
```

In the above code, the class `Other_Anime` is created which inherits the class `Anime` and we defined the public function named `show_anime` that accesses the **protected** variables of the class `Anime`.

We called the **public** function to display the result from the protected variables.

```python
Anime: Demon Slayer
Release: 2019
```

You might be thinking that **protected variables** of the class `Anime` were also accessible outside the class environment. The protected variables and functions can be accessed by the derived classes and any other classes but it is the sole responsibility of the good programmer not to use the **protected data members** outside the specific class environment.

# Private Access Modifier

As we can tell by seeing its name the "**Private**" access modifier restricts the variables and methods declared inside the specific class to that class environment.

Simply put, the variables and methods declared inside a class can be accessed inside that class environment and not outside that class. Python doesn't have any mechanism restricting access to the variables or methods.

But there is a way by which we can impose restrictions to access the variables and methods in Python. Python suggests using a **double underscore** to imitate the behaviour of the private access modifier.

Variables and methods prefixed with a **double underscore** (`__`) make them private and cannot be accessed outside the specific class. Let's understand it with an example.

```python
class Superhero:
    __hero = "Iron Man"

    def __init__(self, name):
        self.__name = name
        
obj = Superhero("Shaktiman")
print(obj.__name)
```

In the above code, the class `Superhero` is created and we created the private variable named `__hero` and a private instance variable named `__name`. Then we instantiated the class and passed the required arguments and tried to access the **private data**.

```python
Traceback (most recent call last):
  ...
    print(obj.__name)
AttributeError: 'Superhero' object has no attribute '__name'
```

We got the **AttributeError** saying that the class `Superhero` has no attribute called `__name` and it happened because the private data in a class cannot be accessed outside the class. But we can access the private variables and methods inside the class.

```python
class Superhero:
    def __init__(self, name):
        self.__name = name

    def displayname(self):
        print("Hero:", self.__name)

obj = Superhero("Shaktiman")
obj.displayname()
```

In the above code, we created a public function called `displayname` that accesses the private variable `__name` inside the class and we tried to print the output.

```python
Hero: Shaktiman
```

The code ran without any error and we got the output that we expected.

Python prevents private data from accessing outside the class so it does **name mangling** which means that it changes the process of accessing private data.

We can **access the private data** from the class and the following example will show you how to do it.

```python
class Superhero:
    __hero = "Iron Man"

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

obj = Superhero("Shaktiman")
print(obj._Superhero__name)
print(obj._Superhero__hero)
```

We tried the **name-mangling** process that helps us access the variables outside the class. We added the `_Superhero` which is the name of our base class and then added the private variable to the class object `obj`.

```python
Shaktiman
Iron Man
```

We successfully accessed the `__name` and `__hero` variables outside the class.

# Conclusion

Python uses a specific naming convention to make any variables/methods protected and private inside the class and all the variables and methods defined inside the Python class are public by default.

Public data attributes are accessible by any class and function, protected data attributes should only be accessed inside the class environment and can also be accessed inside the sub-classes and private data attributes are only accessible inside the class.

We have learnt about the public, protected and private access modifiers which are used to impose restrictions on accessing the variables and methods of the Python class.

---

🏆**Other articles you might like if you liked this article**

✅[A modern way to perform string interpolation using f-string in Python](https://geekpython.in/f-string-in-python).

✅[Integrate the PostgreSQL database with Python](https://geekpython.in/integrate-postgresql-database-in-python).

✅[Build a custom deep-learning model using the transfer learning technique](https://geekpython.in/using-transfer-learning-for-deep-learning-model).

✅[8 different ways by which you can reverse a Python list](https://geekpython.in/different-ways-to-reverse-a-python-list).

✅[Powerful one-liners in Python to enhance your code](https://geekpython.in/one-liners-in-python).

✅[Take multiple inputs from the user in a single line in Python](https://geekpython.in/multiple-inputs-in-python).

---

**That's all for now**

**Keep Coding✌✌**
