In Python, access modifiers are used to define the visibility or scope of variables, methods, and classes.
Unlike languages such as Java or C++, Python does not have explicit keywords like public, private, or protected.
Instead, Python follows a convention-based approach using underscores (_) to indicate the access level of class members (variables and methods).
In this tutorial, we will cover:
- What are Access Modifiers?
- Public Members
- Protected Members
- Private Members
- Name Mangling in Python
- Examples and Use Cases
Let’s dive into each type of access modifier with examples!
1. What are Access Modifiers?
Access modifiers in Python control the visibility of class attributes (variables) and methods.
Even though Python does not enforce strict access control like other languages, it uses naming conventions to communicate the intended scope of class members.
Python Access Levels:
- Public: Accessible from anywhere.
- Protected: Accessible within the class and subclasses (intended for internal use but can still be accessed outside).
- Private: Accessible only within the class (using name mangling to discourage direct access).
2. Public Members
In Python, any member (variable or method) that is not prefixed with an underscore (_) is considered public. Public members are accessible from anywhere, including outside the class.
Example 1: Public Members
class Car: # Public variable brand = "Toyota" # Public method def start_engine(self): print(f"The {self.brand} engine has started.") # Create an object of the class my_car = Car() # Accessing public variable print(my_car.brand) # Output: Toyota # Calling public method my_car.start_engine() # Output: The Toyota engine has started.
Explanation:
- The brand variable and the start_engine() method are public members, meaning they can be accessed both inside and outside the class without any restrictions.
3. Protected Members
A protected member is indicated by a single underscore (_). By convention, protected members should not be accessed outside of the class or its subclasses. However, Python does not strictly enforce this rule, so protected members can still be accessed directly outside the class.
Example 2: Protected Members
class Vehicle: def __init__(self, name): # Protected variable self._name = name # Protected method def _show_name(self): print(f"Vehicle name: {self._name}") class Car(Vehicle): def display(self): # Accessing protected member in subclass print(f"Car name: {self._name}") # Create an object of the Car class my_car = Car("Honda") # Accessing protected variable and method from within the subclass my_car.display() # Output: Car name: Honda # Accessing protected variable outside the class (not recommended but possible) print(my_car._name) # Output: Honda # Accessing protected method outside the class (not recommended but possible) my_car._show_name() # Output: Vehicle name: Honda
Explanation:
- The variable _name and the method _show_name() are protected members. They can be accessed in the subclass Car, but Python also allows access to these members from outside the class, though it’s considered bad practice.
4. Private Members
Private members are prefixed with a double underscore (__). They are not accessible directly outside the class. Python achieves this by performing name mangling, which internally renames the private member, making it difficult (though still possible) to access from outside the class.
Example 3: Private Members
class BankAccount: def __init__(self, account_number, balance): self.__account_number = account_number # Private variable self.__balance = balance # Private variable # Private method def __show_account_info(self): print(f"Account Number: {self.__account_number}, Balance: {self.__balance}") # Public method to access private members def display_balance(self): print(f"Balance: {self.__balance}") self.__show_account_info() # Accessing private method inside the class # Create an object of the BankAccount class account = BankAccount("123456789", 1000) # Accessing private variable outside the class (will raise an AttributeError) # print(account.__balance) # Error: AttributeError: 'BankAccount' object has no attribute '__balance' # Accessing private method outside the class (will raise an AttributeError) # account.__show_account_info() # Error: AttributeError # Accessing private members via public method account.display_balance() # Output: # Balance: 1000 # Account Number: 123456789, Balance: 1000
Explanation:
- The __account_number and __balance variables, as well as the __show_account_info() method, are private members and cannot be accessed directly outside the class.
- However, the display_balance() method provides indirect access to private members from outside the class.
5. Name Mangling in Python
Although private members cannot be accessed directly, Python performs name mangling to prevent accidental access. Name mangling changes the name of the private member to _ClassName__memberName. This makes it harder (but not impossible) to access private members from outside the class.
Example 4: Accessing Private Members with Name Mangling
class Person: def __init__(self, name, age): self.__name = name # Private variable self.__age = age # Private variable def show_info(self): print(f"Name: {self.__name}, Age: {self.__age}") # Create an object of the Person class person = Person("John", 30) # Accessing private members using name mangling (not recommended) print(person._Person__name) # Output: John print(person._Person__age) # Output: 30 # Accessing private method using name mangling (if any) # person._Person__private_method()
Explanation:
- By using name mangling, the private variable __name can be accessed outside the class as _Person__name. This is not recommended, but it shows that private members are not completely hidden in Python.
6. Examples and Use Cases
Example 5: Combining Access Modifiers
class Employee: # Public members employee_count = 0 def __init__(self, name, salary): self.name = name # Public variable self._salary = salary # Protected variable Employee.employee_count += 1 # Public class variable # Public method def show_info(self): print(f"Employee Name: {self.name}") print(f"Salary: {self._salary}") # Protected method def _calculate_bonus(self): return self._salary * 0.1 # Private method def __raise_salary(self): self._salary += 5000 print(f"Salary increased to {self._salary}") # Public method to modify private member def raise_employee_salary(self): self.__raise_salary() # Create an Employee object employee1 = Employee("Alice", 60000) # Access public members print(f"Employee Name: {employee1.name}") # Output: Employee Name: Alice employee1.show_info() # Output: # Employee Name: Alice # Salary: 60000 # Access protected member (not recommended but possible) print(f"Protected Salary: {employee1._salary}") # Output: Protected Salary: 60000 # Access private member via public method employee1.raise_employee_salary() # Output: Salary increased to 65000 # Access private member via name mangling (not recommended) # print(employee1._Employee__raise_salary()) # Raises an error if accessed directly
Explanation:
- The class Employee has public, protected, and private members. The private method __raise_salary() is accessed via the public method raise_employee_salary(), while protected members can be accessed directly (though not recommended).
Summary of Python Access Modifiers
Modifier | Syntax | Access |
---|---|---|
Public | variable, method() | Accessible from anywhere (inside and outside the class). |
Protected | _variable, _method() | Accessible within the class, subclasses, and (not recommended) outside the class. |
Private | __variable, __method() | Accessible only within the class (can be accessed outside via name mangling). |
Conclusion
In Python, access modifiers are handled through naming conventions, rather than strict keywords.
This gives you the flexibility to determine the visibility of class members, but it also places responsibility on the developer to follow best practices and avoid accessing protected or private members directly.
In this tutorial, we covered:
- Public members that can be accessed from anywhere.
- Protected members, which can be accessed within the class and its subclasses (but should not be accessed directly from outside).
- Private members, which use name mangling to restrict access to within the class, but can still be accessed with workarounds (though not recommended).