What Are Access Modifiers – Complete Guide

Welcome to our exploration of access modifiers, a concept in programming that unlocks better control and protection for the data and functions within our code. If you’re crafting digital worlds or building applications, understanding how to properly implement access modifiers is a vital skill that helps in managing the complexity of your projects. These gatekeepers play an essential role in solidifying your architecture, making it both robust and secure.

What Are Access Modifiers?

Access modifiers, sometimes known as access specifiers, are keywords in various programming languages that set the accessibility of classes, methods, and other members. Think of them as the guardians of your code’s castle, determining which parts are open to the public and which ones are restricted to specific areas. Although we’re taking a language-agnostic perspective, we’ll use Python to illustrate our points, simplifying complex ideas into bitesize examples even beginners can digest.

What Are They For?

The primary function of access modifiers is to encapsulate the internal workings of code entities. Encapsulation is one of the four fundamental concepts of object-oriented programming, allowing the bundling of data with the methods that operate on that data. By controlling how classes interact with one another, access modifiers prevent unintended interference and use, ensuring a cleaner and more predictable codebase.

Why Should I Learn About Access Modifiers?

Understanding access modifiers and the principle of encapsulation they support, equips you with the ability to:

– Protect data from unintended manipulation.
– Create a clear structure within your code.
– Support easier maintenance and scalability.

Moreover, as you become part of larger teams or work on more complex projects, using these concepts will be vital for seamless collaboration and integration. Whether you are just starting out or an experienced coder brushing up on best practices, realizing the power of access modifiers is sure to make a significant impact on your programming prowess.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Python Access Modifier Basics

In Python, access modifiers are not as explicit as in some other languages, such as Java or C++. Instead, Python relies on a naming convention to signal the intended level of access for class members (functions and variables):

– **Public Access**: By default, all class members in Python are public. This means they can be freely accessed from inside or outside of the class.
– **Protected Access**: Members are indicated by a single underscore prefix (_). They should not be accessed outside the class, except in a subclass.
– **Private Access**: Denoted by a double underscore prefix (__), these members can only be accessed within the class itself.

Let’s see how these access levels are implemented through examples.

Public Members

Public members are accessible from anywhere. Here’s how to declare and access a public member in Python.

class PublicExample:
    def __init__(self):
        self.public_variable = "I am public"

pe = PublicExample()
print(pe.public_variable)

This will output: I am public. Since the variable is public, it is accessible from outside the class.

Protected Members

Protected members are intended for use within the class and its subclasses. Here’s an example demonstrating this concept:

class ProtectedExample:
    def __init__(self):
        self._protected_variable = "I am protected"
    
    def _protected_method(self):
        return "Protected method"

class SubclassExample(ProtectedExample):
    def access_protected_member(self):
        return self._protected_variable

pe = ProtectedExample()
se = SubclassExample()

# Trying to access the protected variable from subclass
print(se.access_protected_member())

# This is allowed, but not recommended
print(pe._protected_variable)

The output will be:
I am protected
I am protected

Private Members

Private members are more strictly controlled. They can only be accessed from within their own class. Here’s how you declare a private variable and method and try to access them:

class PrivateExample:
    def __init__(self):
        self.__private_variable = "I am private"
    
    def __private_method(self):
        return "Private method"
    
    def access_private_member(self):
        return self.__private_method()

pe = PrivateExample()

# Accessing private method through a public one
print(pe.access_private_member())

# The following will raise an AttributeError
# print(pe.__private_variable)

The code will output: Private method. Attempting to access the private variable or method directly will result in an error.

Understand Name Mangling for Private Variables

In Python, private variables are name mangled. This means Python changes the name of the variable in a way that makes it harder to create subclasses that accidentally override the private fields and methods. Here’s the name mangling in action:

class NameManglingExample:
    def __init__(self):
        self.__mangled = 'I get mangled'

    def access_mangled(self):
        return self.__mangled

nme = NameManglingExample()

# Direct access will fail
# print(nme.__mangled)

# Access through a method
print(nme.access_mangled())

# Name mangling syntax
print(nme._NameManglingExample__mangled)

The output will be:
I get mangled
I get mangled

Although you can access the mangled name as shown, it’s typically discouraged because it breaks the encapsulation concept, and it’s contrary to the intent of the private access level. These examples cover the core basics of how access modifiers work in Python. Remember, while Python does not enforce strict access control, using the conventions gives you and your team a guideline for how the members of a class are intended to be accessed and used.Continuing with our exploration of access modifiers in Python, let’s delve into more practical examples. We’ll look into different scenarios where access levels control the behavior and interaction of your program’s components.

Using Access Modifiers in a Real-world Context

When working with classes that represent entities in your application, using proper access specification can ensure data integrity. Let’s create a `BankAccount` class to illustrate how access modifiers can be applied.

class BankAccount:
    def __init__(self, initial_balance):
        self._balance = initial_balance  # Protected variable

    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
            return True
        else:
            return False

    def withdraw(self, amount):
        if 0 < amount <= self._balance:
            self._balance -= amount
            return True
        else:
            return False

    def _calculate_interest(self):  # Protected method
        # Dummy interest calculation
        return self._balance * 0.05

    def update_balance_with_interest(self):
        interest = self._calculate_interest()
        self.deposit(interest)

# Usage
account = BankAccount(1000)
account.deposit(500)
account.withdraw(200)
print(account._balance)  # Not recommended
account.update_balance_with_interest()
print(account._balance)

Here’s how the `BankAccount` class functions:
– The balance is a protected variable since it should not be directly accessed but can be modified by subclass if created (like a SavingsAccount class).
– The `deposit` and `withdraw` methods are public so the account holder can perform transactions.
– The `_calculate_interest` method is protected as it should not be accessed by the user directly.
– Interest is added to the account through the public method `update_balance_with_interest` which internally utilizes the protected method.

Enforcing Private Access

Sometimes you want to enforce stricter access to ensure internal mechanisms are not altered. Here’s how we can use private access to protect core functionality.

class SecureSystem:
    def __init__(self):
        self.__security_code = "1234"  # Private variable

    def __verify_security_code(self, input_code):  # Private method
        return input_code == self.__security_code

    def enter_system(self, input_code):
        if self.__verify_security_code(input_code):
            print("Access granted")
        else:
            print("Access denied")

# Usage
secure_system = SecureSystem()
secure_system.enter_system("1111")  # Access denied
secure_system.enter_system("1234")  # Access granted

# Direct access to private members will fail
# print(secure_system.__security_code)  # AttributeError will be raised

The `SecureSystem` class has a private `__security_code` variable and private method `__verify_security_code` to prevent external modification and access. The public method `enter_system` provides a controlled way to interact with these private mechanisms.

Combining Access Levels

A well-designed class often combines different access levels to provide both functionality and safety.

class Car:
    def __init__(self, make, model):
        self.make = make  # Public variable
        self.model = model  # Public variable
        self.__speed = 0  # Private variable

    def accelerate(self):
        self.__change_speed(5)

    def brake(self):
        self.__change_speed(-5)

    def __change_speed(self, amount):  # Private method
        self.__speed = max(0, self.__speed + amount) 
        print(f"Current speed: {self.__speed} km/h")

# Usage
car = Car("Toyota", "Corolla")
car.accelerate()  # Current speed: 5 km/h
car.accelerate()  # Current speed: 10 km/h
car.brake()       # Current speed: 5 km/h

# The following will raise an AttributeError
# car.__change_speed(10)

In this `Car` class example, `make` and `model` are public variables, whereas `__speed` is kept private to prevent changes that do not adhere to the `accelerate` and `brake` methods’ requirements. The private method `__change_speed` centralizes speed alterations.

In conclusion, Python may not enforce access control as strictly as other languages, but adhering to the conventions of access modifiers encourages clean coding practices, enhances security, and facilitates maintenance. Through these examples, we’ve seen how to apply public, protected, and private access levels to safeguard the behavior of our classes and their instances.

Through consistent application and practice, using access modifiers will become second nature, enabling you to build more resilient and reliable applications. Whether you’re working on game development, web applications, or any other software project, mastering these concepts is crucial for effective coding, which is why we at Zenva highly encourage learners to embrace these best practices in their programming journey.Access modifiers are a fundamental part of programming languages that support principles of object-oriented design. Through proper use of access modifiers, you can ensure that your objects’ data integrity is maintained and that coupling between different parts of your application is minimized. Let’s dive deeper with more examples illustrating best practices and common uses of access modifiers.

Advanced Use of Protected Members

Expanding upon the concept of protected members, these are typically used when we anticipate inheritance and want to ensure that the derived classes have the ability to make use of the base class’s properties or methods.

Let’s look at how we might design a base class `Shape` with a protected member that should be accessible by a subclass `Circle`.

class Shape:
    def __init__(self, color):
        self._color = color  # Protected variable

class Circle(Shape):
    def __init__(self, color, radius):
        super().__init__(color)
        self.radius = radius

    def display_color(self):
        return f"Circle color is {self._color}"

circle = Circle("Blue", 5)
print(circle.display_color())  # Circle color is Blue

The protected member `_color` from the `Shape` class is safely accessible in the subclass `Circle`, and is used within methods that augment `Circle`’s functionality.

Immutable Properties with Private Access

Sometimes you’ll want to create read-only properties in your classes. This can be achieved in Python using private variables and property decorators.

class Product:
    def __init__(self, name, price):
        self.__name = name  # Private variable
        self.__price = price  # Private variable

    @property
    def price(self):
        return self.__price
    
    @property
    def name(self):
        return self.__name

# Usage
prod = Product("Chocolate", 2)
print(prod.name)  # Chocolate
print(prod.price)  # 2

# Attempting to modify will raise an AttributeError
# prod.price = 3

By using private variables and exposing them through properties, `Product` maintains control over how `name` and `price` are accessed but does not allow them to be modified.

Dynamic Access Control

We can design our classes to provide different levels of access to properties based on certain conditions or states.

class Account:
    def __init__(self, username, password, is_admin=False):
        self.username = username
        self.__password = password  # Private variable to store password
        self.__is_admin = is_admin  # Private variable to check admin status

    def change_password(self, old_password, new_password):
        if old_password == self.__password:
            self.__password = new_password
            print("Password updated successfully.")
        else:
            print("Old password is incorrect.")

    def get_admin_status(self):
        return "Admin access granted." if self.__is_admin else "Not an admin."

# Usage
account = Account("user1", "pass123")
account.change_password("pass123", "newpass456")  # Password updated successfully.
print(account.get_admin_status())  # Not an admin.

# Password property has been designed such that it is always kept private and only manipulated through methods that provide necessary checks.

Here, password changes are guarded by an existing password check, and administrative status can only be determined but not directly set from outside the `Account` class.

Enforcing Class-Specific Private Members

When dealing with multiple classes that might have methods or properties with the same name, private variables can prevent variable name collisions due to name mangling.

class ClassA:
    def __init__(self):
        self.__shared_name = "A"

    def reveal_identity(self):
        print(f"My identity is {self.__shared_name}")

class ClassB:
    def __init__(self):
        self.__shared_name = "B"

    def reveal_identity(self):
        print(f"My identity is {self.__shared_name}")

a = ClassA()
b = ClassB()

a.reveal_identity()  # My identity is A
b.reveal_identity()  # My identity is B

In the above classes, `__shared_name` does not clash between instances of `ClassA` and `ClassB` due to each having their respective private variables after name mangling.

In summary, access modifiers play a crucial role in fostering a disciplined and secure approach to coding. As we’ve demonstrated through our examples, they afford a powerful way to define how parts of your program should interact with each other. By using public, protected, and private members wisely, you encapsulate logic, manage dependencies, and protect sensitive data from unintended access—an excellent practice we at Zenva uphold in our courses and encourage students to master for robust software development.

Continue Your Learning Journey With Zenva

You’ve dipped your toes into the world of access modifiers in Python, and perhaps have even started reaping the benefits in your own projects. But, the world of Python—and programming in general—is vast and full of wonders to explore. If you’re excited about expanding your skills and building a robust portfolio of projects, Zenva has the perfect pathway for you: our Python Mini-Degree.

This comprehensive course collection is designed to escalate your proficiency in Python, covering a wide range of topics beyond the basics, from algorithms and object-oriented programming, to creating your own games, bots, and applications. With the flexibility to learn at your own pace and a community of over 1 million learners, Zenva empowers you to gain practical, hands-on experience to propel your career forward.

And if you’re looking to broaden your coding horizons even further, check out our full selection of Programming Courses. Whether you’re a beginner or looking to sharpen your professional skills, Zenva is your partner on this compelling journey of learning and mastery. Start crafting your future in tech today!

Conclusion

As we close the chapter on access modifiers, remember that these guardians of your code’s integrity are but a small part of the vast programming landscape. We at Zenva hope that you feel empowered to apply these principles in your next project, ensuring safety, structure, and clarity within your codebase. But don’t let your journey end here! Development and learning are ongoing adventures, and we’re excited to challenge and support you through every step.

Whether you’re looking to consolidate your Python mastery or branch out into new programming territories, Zenva’s courses are tailored to help you stay ahead. Join us in our Python Mini-Degree to transform your curiosity into skill and your ambition into achievement. Let’s code the future together!

Did you come across any errors in this tutorial? Please let us know by completing this form and we’ll look into it!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.