Hướng dẫn thử thách
1 / 2
What is Object-Oriented Programming, and How Does Encapsulation Work?
Object-oriented programming, also known as OOP, is a programming style in which developers treat everything in their code like a real-world object.
A class is like a blueprint for creating objects. Every single object created from a class has attributes that define data and methods that define the behaviors of the objects.
In a previous lesson, you learned how to create classes. Here's a reminder of the syntax:
```py
class ClassName:
def __init__(self, parameters):
attribute = value
def method_name(self):
# method logic
```
Here's an example of a class that uses the `__init__` special method to initialize the brand and color attributes whenever an object is created using the class:
```py
class Car:
def __init__(self, brand, color):
self.brand = brand
self.color = color
# create two objects from the Car class
car1 = Car('Toyota', 'red')
car2 = Car('Lambo', 'green')
print('Car 1 Brand:', car1.brand) # Car 1 Brand: Toyota
print('Car 1 Color:', car1.color) # Car 1 Color: red
print('Car 2 Brand:', car2.brand) # Car 2 Brand: Lambo
print('Car 2 Color:', car2.color) # Car 2 Color: green
```
Object-oriented programming has four key principles that help you organize and manage code effectively. They are encapsulation, inheritance, polymorphism, and abstraction.
The rest of this lesson will focus on how encapsulation works.
Encapsulation is the bundling of the attributes and methods of an object into a single unit, the class.
With encapsulation, you can hide the internal state of the object behind a simple set of public methods and attributes that act like doors. Behind those doors are private attributes and methods that control how the data changes and who can see it.
Let's say you want to track a wallet balance. You want to allow people to deposit or withdraw money from the wallet, but no one should be able to tamper with the balance directly.
In that case, you can make `deposit()` and `withdraw()` public methods, and you hide the balance under the `_balance` attribute:
```py
class Wallet:
def __init__(self, balance):
self._balance = balance # For internal use by convention
def deposit(self, amount):
if amount > 0:
self._balance += amount # Add to the balance safely
def withdraw(self, amount):
if 0 < amount <= self._balance:
self._balance -= amount # Remove from the balance safely
```
By convention, prefixing attribute and methods with a single underscore means they are meant for internal use. No one should directly access them from outside the class since it defies the principles of encapsulation, which can lead to bugs.
While a single underscore prefix is just a convention, prefixing attributes and methods with a double underscore effectively prevents them to be accessed from the outside of their class, making those attributes and methods private.
```py
class Wallet:
def __init__(self, balance):
self.__balance = balance # Private attribute
def deposit(self, amount):
if amount > 0:
self.__balance += amount # Add to the balance safely
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount # Remove from the balance safely
account = Wallet(500)
print(account.__balance) # AttributeError: 'Wallet' object has no attribute '__balance'
```
To get the current value of `__balance`, you can define a `get_balance` method. For example:
```py
class Wallet:
def __init__(self, balance):
self.__balance = balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
def get_balance(self):
return self.__balance
acct_one = Wallet(100)
acct_one.deposit(50)
print(acct_one.get_balance()) # 150
acct_two = Wallet(450)
acct_two.withdraw(28)
print(acct_two.get_balance()) # 422
acct_two.deposit(150)
print(acct_two.get_balance()) # 572
```
You can also define a private `__validate` method to check if every deposit or withdrawal amount is a positive number:
```py
class Wallet:
def __init__(self):
self.__balance = 0
def __validate(self, amount):
if amount < 0:
raise ValueError('Amount must be positive')
def deposit(self, amount):
self.__validate(amount)
self.__balance += amount
def withdraw(self, amount):
self.__validate(amount)
if amount > self.__balance:
raise ValueError('Insufficient funds')
self.__balance -= amount
def get_balance(self):
return self.__balance
acct_one = Wallet()
acct_one.deposit(3)
print(acct_one.get_balance()) # 3
acct_one.deposit(50)
print(acct_one.get_balance()) # 53
acct_one.deposit(-4) # ValueError: Amount must be positive
acct_one.withdraw(-8) # ValueError: Amount must be positive
acct_one.withdraw(58) # ValueError: Insufficient funds
```
As you can see, the `__validate` method is private, and runs behind the scenes in the `deposit()` and `withdraw()` public methods to make sure the amount is always valid.
In a coming lesson, you will learn more about how attributes prefixed with a double underscore works.
In summary, encapsulation locks down internal data behind clear public methods. That's how you keep your classes safe from tampering and centralize validation in one place. You can update or extend your code freely, knowing that outside code only touches the interfaces you expose.
Vượt qua bài kiểm tra hiện tại để mở khóa bài tiếp theo.
main.py
UTF-8 • Tab Size: 2Kiểm tra bài:⌘↵