2024-11-08 19:30:32 +00:00
|
|
|
"""
|
|
|
|
Now that we know the basics of classes, variables, and functions, we will move on to more
|
|
|
|
abstract ideas.
|
|
|
|
|
|
|
|
I'm also going to introduce type hinting; this reduces ambiguity and improves readability.
|
|
|
|
|
|
|
|
Key Concepts:
|
|
|
|
**Encapsulation** is the concept of grouping related data and methods within a
|
|
|
|
class and restricting access to them to control how they are used.
|
|
|
|
|
|
|
|
**Access Modifiers** are used to determine who/what can access a certain attribute or method.
|
|
|
|
|
|
|
|
- **Public**: Accessible from any part of the code. Used for attributes and methods intended to be part
|
|
|
|
of the class's interface for external use.
|
|
|
|
|
|
|
|
- **Protected**: Intended for internal use within the class and its subclasses. "_value" represents it.
|
|
|
|
Useful for attributes/methods that should be accessible in subclasses but not publicly.
|
|
|
|
|
|
|
|
- **Private**: Only accessible within the class, represented by "__value". Useful for securing sensitive
|
|
|
|
data or internal methods that should not be altered externally.
|
|
|
|
|
|
|
|
IMPORTANT: Python does not strictly enforce access control, so these conventions mainly serve as guidelines.
|
|
|
|
"""
|
|
|
|
|
2024-11-08 20:47:03 +00:00
|
|
|
# This is the abstraction library in Python
|
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
# Type hinting, not needed but reduces ambiguity. Note: not enforced at runtime.
|
|
|
|
from typing import Optional
|
2024-11-08 19:30:32 +00:00
|
|
|
|
2024-11-08 20:47:03 +00:00
|
|
|
# An abstract class, provides a blueprint for other classes to inherit.
|
|
|
|
class Shape(ABC):
|
2024-11-08 19:30:32 +00:00
|
|
|
|
2024-11-08 20:47:03 +00:00
|
|
|
# This method is required in all subclasses, ensuring they provide their own area calculation.
|
2024-11-08 19:30:32 +00:00
|
|
|
@abstractmethod
|
|
|
|
def area(self) -> float:
|
|
|
|
"""Implemented to ensure each subclass contains this method."""
|
2024-11-08 20:47:03 +00:00
|
|
|
|
2024-11-08 19:30:32 +00:00
|
|
|
|
|
|
|
class Rectangle(Shape):
|
|
|
|
def __init__(self, width: float, height: float):
|
2024-11-08 20:47:03 +00:00
|
|
|
# A private attribute to store width.
|
|
|
|
self.__width = width
|
|
|
|
# A private attribute to store height.
|
|
|
|
self.__height = height
|
2024-11-08 19:30:32 +00:00
|
|
|
|
2024-11-08 20:47:03 +00:00
|
|
|
# This allows access to the private 'width' attribute in a controlled way.
|
|
|
|
@property
|
2024-11-08 19:30:32 +00:00
|
|
|
def width(self) -> float:
|
|
|
|
return self.__width
|
|
|
|
|
2024-11-08 20:47:03 +00:00
|
|
|
# This allows you to set the value of 'width' after initialization.
|
|
|
|
@width.setter
|
2024-11-08 19:30:32 +00:00
|
|
|
def width(self, value: float):
|
|
|
|
if value <= 0:
|
|
|
|
raise ValueError("Width must be positive.")
|
|
|
|
self.__width = value
|
|
|
|
|
2024-11-08 20:47:03 +00:00
|
|
|
# This allows access to the private 'height' attribute in a controlled way.
|
|
|
|
@property
|
2024-11-08 19:30:32 +00:00
|
|
|
def height(self) -> float:
|
|
|
|
return self.__height
|
|
|
|
|
2024-11-08 20:47:03 +00:00
|
|
|
# This allows you to set the value of 'height' after initialization.
|
|
|
|
@height.setter
|
2024-11-08 19:30:32 +00:00
|
|
|
def height(self, value: float):
|
|
|
|
if value <= 0:
|
|
|
|
raise ValueError("Height must be positive.")
|
|
|
|
self.__height = value
|
|
|
|
|
|
|
|
def area(self) -> float:
|
2024-11-08 20:47:03 +00:00
|
|
|
# Calculates the area of the rectangle.
|
|
|
|
return self.__width * self.__height
|
2024-11-08 19:30:32 +00:00
|
|
|
|
|
|
|
def set_dimensions(self, width: Optional[float] = None, height: Optional[float] = None):
|
|
|
|
if width is not None:
|
2024-11-08 20:47:03 +00:00
|
|
|
# Sets 'width' using the setter.
|
|
|
|
self.width = width
|
2024-11-08 19:30:32 +00:00
|
|
|
if height is not None:
|
2024-11-08 20:47:03 +00:00
|
|
|
# Sets 'height' using the setter.
|
|
|
|
self.height = height
|
2024-11-08 19:30:32 +00:00
|
|
|
|
|
|
|
rect = Rectangle(5, 10)
|
2024-11-08 20:47:03 +00:00
|
|
|
|
|
|
|
# Prints the area of the rectangle (5 * 10 = 50).
|
|
|
|
print(rect.area())
|
|
|
|
|
|
|
|
# Updates 'width' using the setter, height remains the same.
|
|
|
|
rect.set_dimensions(width=8)
|
|
|
|
|
|
|
|
# Prints the new area of the rectangle (8 * 10 = 80).
|
|
|
|
print(rect.area())
|