Explore programming tutorials, exercises, quizzes, and solutions!
Python Encapsulation Exercises
1/20
In Python’s object-oriented programming, encapsulation is a principle that involves hiding internal object details and only exposing what is necessary through a public interface. It helps protect data from unintended modifications and enforces controlled access using getters and setters.
Although Python does not enforce access restrictions strictly like some other languages, it supports encapsulation through naming conventions:
Attributes prefixed with a single underscore (_var) are considered "protected" by convention.
Attributes prefixed with double underscores (__var) become "private" through name mangling and are harder to access directly.
What does this code demonstrate about encapsulation in Python?
In this example, the attribute __balance is marked as private using double underscores. This triggers name mangling, meaning Python internally renames it to _BankAccount__balance to prevent direct external access.
Encapsulation is achieved by:
Hiding __balance from external modification.
Allowing safe access and updates only through methods like get_balance() and deposit().
This ensures that sensitive data (like a bank balance) isn't tampered with directly and can only be modified under controlled conditions, helping maintain data integrity and security.
Encapsulation helps you design clean, modular code where each class is responsible for managing its own data responsibly.
Using a private variable and providing a public method to access it.
Encapsulation is implemented by using private variables and providing public methods to access and modify them, ensuring controlled access.
What is the purpose of the @property decorator in Python?
The @property decorator in Python is used to define a getter method for a property, allowing it to be accessed like an attribute while still being controlled by a method.
Which of the following is an appropriate way to define a private variable in Python?
While self.__variable indicates a private variable, self.variable is just a regular variable. It is not technically private, but it can still be used within the class.
How can you access a private variable from outside a class in Python?
While Python allows indirect access to private variables using tricks like object._variable, it is not recommended. The proper way to access private variables is through public methods that provide controlled access to those variables.
Which of the following concepts is a benefit of encapsulation in Python?
Encapsulation allows you to hide the internal state of an object and only expose necessary information. This is achieved by using private variables and controlled access through getter and setter methods.
How can a class restrict access to its internal attributes in Python?
In Python, double underscores (__) before a variable name make the attribute private. This name mangling prevents direct access to the variable from outside the class.
Which of the following is an advantage of using encapsulation?
Encapsulation ensures that the internal state of an object is protected, and any modification or access to it is controlled through well-defined methods, increasing security and maintaining integrity.
Which of the following is true about the __init__() method in Python?
The __init__() method in Python is not only used to initialize an object but also to initialize inherited attributes when working with inheritance. This makes it essential for setting up new instances of a class.
What will happen if you try to access a private variable outside the class in Python?
If you try to access a private variable outside the class in Python, an AttributeError will be raised. Private variables are meant to be accessed only within the class itself.
What will the following code print?
class Employee:
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
e = Employee("John")
print(e.get_name())
In this example, __name is a private attribute due to the double underscore. It is accessed using the public method get_name(), which is part of the class’s interface. Since the access is performed inside the class via a method, Python resolves the name correctly and returns "John". This demonstrates proper encapsulation—restricting direct access and exposing data through controlled interfaces.
Which technique breaks encapsulation even if a variable is private?
class Secret:
def __init__(self):
self.__key = 9876
s = Secret()
Even though __key is marked private using double underscores, Python internally applies name mangling. This means it renames the attribute to _Secret__key. If someone accesses this attribute using the mangled name (s._Secret__key), they can bypass the encapsulation layer. This technique, while possible, violates the intent of encapsulation and exposes internal state that should remain hidden from external users.
Here, the attribute __hidden is private and would normally be inaccessible outside the class. However, due to name mangling, Python internally renames it to _Demo__hidden. By using this mangled name, the value "secret" is accessed and printed. This is a workaround to reach private variables, which again defeats the encapsulation purpose, but technically works if the class name is known.
The line acc.__balance = 0 doesn’t modify the internal private attribute. Instead, it creates a new attribute __balance on the instance itself. The original attribute (renamed as _Account__balance by Python due to name mangling) remains unchanged. Therefore, when get_balance() is called, it still accesses the original encapsulated value 1000. This shows how Python protects private attributes from accidental overwrites.
Which approach preserves encapsulation while exposing a computed value?
class Car:
def __init__(self, fuel):
self.__fuel = fuel
The best way to expose a private value like __fuel without breaking encapsulation is through a controlled interface, such as a getter method. This ensures that the internal state of the object remains hidden and can only be accessed in the way the class intends. Option 1 removes encapsulation, Option 3 bypasses it using name mangling, and Option 4 breaks modular design. Only Option 2 respects encapsulation principles.
What will be the final output of the following code?
class Vault:
def __init__(self):
self.__code = "ABC123"
def update_code(self, new_code):
if isinstance(new_code, str) and new_code.isalnum():
self.__code = new_code
def get_code(self):
return self.__code
v = Vault()
v.update_code("!!@@##")
v.__code = "HACKED"
print(v.get_code())
The update_code method only accepts alphanumeric strings. Since "!!@@##" is not alphanumeric, the update is rejected. Also, the line v.__code = "HACKED" does not modify the actual private attribute — it creates a new attribute named __code in the instance namespace. The original self.__code remains untouched. Hence, get_code() still returns "ABC123".
What will be printed by this code?
class Settings:
def __init__(self):
self.__theme = "dark"
def set_theme(self, value):
if value in ["dark", "light"]:
self.__theme = value
def get_theme(self):
return self.__theme
s = Settings()
s.set_theme("light")
s.set_theme("contrast")
s.__theme = "no-theme"
print(s.get_theme())
The first call set_theme("light") updates the private attribute successfully. The second call set_theme("contrast") is ignored as it doesn't meet the condition. Then s.__theme = "no-theme" creates a new attribute, not affecting the private one. Hence, the encapsulated value remains "light" and is returned by get_theme().
What will the code below output?
class Bank:
def __init__(self):
self.__balance = 1000
def withdraw(self, amount):
if amount > 0 and amount <= self.__balance:
self.__balance -= amount
def get_balance(self):
return self.__balance
b = Bank()
b.withdraw(300)
b.withdraw(800)
b.__balance -= 100
print(b.get_balance())
b.withdraw(300) reduces balance to 700. b.withdraw(800) fails since 800 > 700. Then b.__balance -= 100 creates a new attribute __balance, unrelated to the private one. It doesn't affect the internal _Bank__balance. Hence, get_balance() shows the last valid value: 700.
Consider the following class. What will be printed?
Even though l.__log = ["Fake log"] appears to overwrite the private attribute, it doesn’t. It creates a new attribute in the instance dictionary. The add_log() method and show_logs() still refer to the original private __log, which contains "Init done." and "Process started.". Therefore, the internal state remains correct.
What happens in the following scenario?
class Student:
def __init__(self, name):
self.__name = name
def change_name(self, name):
if len(name) >= 3:
self.__name = name
def show(self):
print(self.__name)
s = Student("Ally")
setattr(s, "_Student__name", "Bob")
s.change_name("Ed")
s.show()
Using setattr, we update the mangled name _Student__name to "Bob". Then, change_name("Ed") is called. Since "Ed" is 2 characters long, the method rejects it. Therefore, the name remains "Bob". However, this seems contradictory unless we're careful — oh! Here's the key mistake: "Ed"doesn't satisfy the condition (it's only 2 characters), so the update is blocked. Thus, show() prints "Bob". Correct answer is Option 3, not 1.
Practicing Python Encapsulation? Don’t forget to test yourself later in
our
Python Quiz.
About This Exercise: Python – Encapsulation
Welcome to the Python Encapsulation exercises — a well-crafted set of challenges designed to help you understand and apply one of the fundamental principles of object-oriented programming. Encapsulation is the concept of restricting direct access to an object’s internal data and methods, promoting modularity, security, and maintainability in your Python code. Whether you’re new to OOP or aiming to deepen your programming skills, this section will guide you step-by-step through the concept and its practical uses.
Encapsulation helps protect data by controlling how it is accessed and modified. In Python, this is typically done using access modifiers like public, protected (conventionally using a single underscore), and private (double underscore). These conventions help indicate the intended level of access, though Python does not enforce strict access control like some other languages. These exercises will help you practice how to use these conventions properly to safeguard your data and define clear interfaces for your classes.
Through these challenges, you will learn to create getter and setter methods using Python’s property decorators, enabling controlled access to private attributes. This practice improves data integrity by allowing validation or transformation when attributes are accessed or modified. You’ll also explore how encapsulation supports hiding implementation details, making your classes easier to maintain and evolve without affecting external code.
Mastering encapsulation is crucial for building robust, modular Python applications where components interact through well-defined interfaces. It prevents accidental misuse of internal data and reduces bugs caused by unintended side effects. These exercises simulate real-world scenarios such as managing user data, controlling access to sensitive information, and designing reusable libraries.
Alongside coding practice, this section highlights best practices for encapsulation, such as balancing data hiding with usability, writing clear and concise class interfaces, and documenting intended access levels for class members. Understanding these concepts is essential for professional Python development and prepares you for technical interviews focusing on OOP principles.
To enhance your learning, consider exploring related topics such as classes and objects, inheritance, and polymorphism. You can also test your knowledge with quizzes and multiple-choice questions available on our platform to reinforce your understanding of encapsulation.
Start practicing the Python Encapsulation exercises today to build secure, maintainable, and well-organized code. With consistent practice, you’ll become confident in protecting your data and designing clean, efficient Python programs.