Python - Access Modifiers
Hello there, aspiring Python programmers! Today, we're going to embark on an exciting journey into the world of Access Modifiers in Python. Don't worry if you're new to programming; I'll guide you through this concept step by step, with plenty of examples and explanations along the way. So, let's dive in!
Access Modifiers in Python
In object-oriented programming, access modifiers are used to control the visibility and accessibility of class members (attributes and methods). While many programming languages have strict access modifiers like public, private, and protected, Python takes a more relaxed approach. It follows a philosophy often referred to as "We're all consenting adults here."
In Python, we have three types of access modifiers:
- Public
- Protected
- Private
Let's explore each of these with examples.
Public Members
In Python, all members are public by default. This means they can be accessed from outside the class. Here's an example:
class Student:
def __init__(self, name, age):
self.name = name # Public attribute
self.age = age # Public attribute
def display_info(self): # Public method
print(f"Name: {self.name}, Age: {self.age}")
# Creating an instance of Student
student1 = Student("Alice", 20)
# Accessing public members
print(student1.name) # Output: Alice
student1.display_info() # Output: Name: Alice, Age: 20
In this example, name
, age
, and display_info()
are all public members. We can access them directly from outside the class.
Protected Members
Protected members are denoted by prefixing the member name with a single underscore (_). They are not truly private and can still be accessed from outside the class, but it's a convention to treat them as internal use only.
class Employee:
def __init__(self, name, salary):
self._name = name # Protected attribute
self._salary = salary # Protected attribute
def _display_salary(self): # Protected method
print(f"{self._name}'s salary is ${self._salary}")
# Creating an instance of Employee
emp1 = Employee("Bob", 50000)
# Accessing protected members (Note: This is possible but not recommended)
print(emp1._name) # Output: Bob
emp1._display_salary() # Output: Bob's salary is $50000
While we can access _name
, _salary
, and _display_salary()
, it's generally not recommended to do so outside the class or its subclasses.
Private Members
Private members are denoted by prefixing the name with double underscores (__). Python performs name mangling for these members, making them harder (but not impossible) to access from outside the class.
class BankAccount:
def __init__(self, account_number, balance):
self.__account_number = account_number # Private attribute
self.__balance = balance # Private attribute
def __display_balance(self): # Private method
print(f"Balance: ${self.__balance}")
def public_display(self):
self.__display_balance()
# Creating an instance of BankAccount
account1 = BankAccount("123456", 1000)
# Trying to access private members
# print(account1.__account_number) # This will raise an AttributeError
# account1.__display_balance() # This will also raise an AttributeError
# Accessing private method through a public method
account1.public_display() # Output: Balance: $1000
In this example, __account_number
, __balance
, and __display_balance()
are private members. Attempting to access them directly from outside the class will raise an AttributeError.
Name Mangling
Remember when I mentioned that private members in Python are not truly private? This is because of a mechanism called name mangling. When you create a private member using double underscores, Python changes its name internally to make it harder to access accidentally.
Here's how it works:
class NameManglingDemo:
def __init__(self):
self.__private_var = "I'm private!"
demo = NameManglingDemo()
print(dir(demo))
# Output: [..., '_NameManglingDemo__private_var', ...]
# Accessing the private variable using the mangled name
print(demo._NameManglingDemo__private_var) # Output: I'm private!
As you can see, Python renames __private_var
to _NameManglingDemo__private_var
. This is name mangling in action!
Python Property Object
The property()
function in Python is a built-in function that creates and returns a property object. It's a way to add getter, setter, and deleter methods to class attributes.
Here's an example:
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
def get_fahrenheit(self):
return (self._celsius * 9/5) + 32
def set_fahrenheit(self, fahrenheit):
self._celsius = (fahrenheit - 32) * 5/9
fahrenheit = property(get_fahrenheit, set_fahrenheit)
# Using the property
temp = Temperature(25)
print(temp.fahrenheit) # Output: 77.0
temp.fahrenheit = 86
print(temp._celsius) # Output: 30.0
In this example, fahrenheit
is a property that allows us to get and set the temperature in Fahrenheit while internally storing it in Celsius.
Getters and Setter Methods
Getters and setters are methods used to get and set the values of class attributes. They provide a way to access and modify private attributes while maintaining encapsulation.
Here's an example using the @property
decorator, which is a more Pythonic way to implement getters and setters:
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
raise ValueError("Name must be a string")
self._name = value
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if not isinstance(value, int) or value < 0:
raise ValueError("Age must be a positive integer")
self._age = value
# Using getters and setters
person = Person("Charlie", 30)
print(person.name) # Output: Charlie
person.name = "David"
print(person.name) # Output: David
try:
person.age = -5
except ValueError as e:
print(e) # Output: Age must be a positive integer
In this example, we've created getter and setter methods for name
and age
. The setter methods include validation to ensure that the values being set meet certain criteria.
To summarize the methods we've discussed, here's a table in Markdown format:
Method | Description | Example |
---|---|---|
Public | Accessible from anywhere | self.name |
Protected | Accessible within class and subclasses (by convention) | self._name |
Private | Name mangled to restrict access | self.__name |
Property | Creates a property object | property(get_method, set_method) |
Getter | Method to get the value of an attribute | @property |
Setter | Method to set the value of an attribute | @attribute.setter |
And there you have it! We've covered access modifiers in Python, name mangling, property objects, and getter and setter methods. Remember, Python's approach to access control is more about convention and trust than strict rules. As you continue your Python journey, you'll find that this flexibility allows for clean and readable code while still providing ways to implement encapsulation when needed.
Keep practicing, stay curious, and happy coding!
Credits: Image by storyset