curriculum/challenges/english/blocks/review-object-oriented-programming/67f39dac6c3fac29c3d54918.md
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'
@property decorator. Here's a getter that gets the radius of a circle:class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self): # A getter to get the radius
return self._radius
@property
def area(self): # A getter to calculate area
return 3.14 * (self._radius ** 2)
my_circle = Circle(3)
print(my_circle.radius) # 3
print(my_circle.area) # 28.26
@<property_name>.setter above it:class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self): # A getter to get the radius
return self._radius
@radius.setter
def radius(self, value): # A setter to set the radius
if value <= 0:
raise ValueError('Radius must be positive')
self._radius = value
my_circle = Circle(3)
print('Initial radius:', my_circle.radius) # Initial radius: 3
my_circle.radius = 8
print('After modifying the radius:', my_circle.radius) # After modifying the radius: 8
my_circle.radius # This will call the getter
my_circle.radius = 4 # This will call the setter
When setting a value, you should not assign to the property name itself because that will cause a RecursionError. Use a separate internal name, often with an underscore, to store the value.
deleter. A deleter runs custom logic when you use the del statement on a property. To create a deleter, you use the @<property_name>.deleter decorator. # Deleter
@radius.deleter
def radius(self):
print("Deleting radius...")
del self._radius
class Parent:
# Parent attributes and methods
class Child(Parent):
# Child inherits, extends, and/or overrides where necessary
class Parent:
# Attributes and methods for Parent
class Child:
# Attributes and methods for Child
class GrandChild(Parent, Child):
# GrandChild inherits from both Parent and Child
# GrandChild can combine or override behavior from each
super() Function: A function that lets you call a method from a parent class, when a class has a different implementation of that method, or it extends the method, without duplicating code.class A:
def action(self): ...
class B:
def action(self): ...
class C:
def action(self): ...
Class().method() # Works for A, B, or C
__attribute into _ClassName__attribute.class Parent:
def __init__(self):
self.__data = 'Parent data'
class Child(Parent):
def __init__(self):
super().__init__()
self.__data = 'Child data'
c = Child()
print(c.__dict__) # {'_Parent__data': 'Parent data', '_Child__data': 'Child data'}
abc module. The module provides the ABC class (abstract base class) and the @abstractmethod decorator. An abstract base class (ABC) defines the common methods and properties subclasses must implement. It can't be instantiated.@abstractmethod and must be overridden in subclasses, even if it has a default implementation. The basic syntax of abstraction looks like this:from abc import ABC, abstractmethod
# Define an abstract base class
class AbstractClass(ABC):
@abstractmethod
def abstract_method(self):
pass
# Concrete subclass that implements the abstract method
class ConcreteClassOne(AbstractClass):
def abstract_method(self):
print('Implementation in ConcreteClassOne')
# Another concrete subclass
class ConcreteClassTwo(AbstractClass):
def abstract_method(self):
print('Implementation in ConcreteClassTwo')
Review the Object Oriented Programming topics and concepts.