Examples

Example 1: Data Analysis Example — Movie Rating Analysis

Suppose you have a dataset containing movie ratings, and you want to perform some data analysis on it. You can create a MovieRatings class with a ratings attribute representing the list of movie ratings. We'll use a getter to calculate statistics like average rating and a setter to validate and filter out invalid ratings.

class MovieRatings:
    def __init__(self, ratings):
        self._ratings = ratings

    @property
    def ratings(self):
        return self._ratings

    @ratings.setter
    def ratings(self, new_ratings):
        valid_ratings = [rating for rating in new_ratings if 0 <= rating <= 10]
        self._ratings = valid_ratings

    @property
    def average_rating(self):
        return sum(self._ratings) / len(self._ratings)

# Create an instance of the MovieRatings class
movie_ratings = MovieRatings([7, 8, 5, 9, 11, 6, 10])

# Set new ratings with the setter (invalid ratings will be filtered out)
movie_ratings.ratings = [7, 8, 5, 9, 11, -2, 6, 10]

# Access valid ratings and average rating using the getter
print(f"Valid Ratings: {movie_ratings.ratings}")           # Output: Valid Ratings: [7, 8, 5, 9, 6, 10]
print(f"Average Rating: {movie_ratings.average_rating}")   # Output: Average Rating: 7.5

In this example, the ratings setter filters out any invalid ratings (less than 0 or greater than 10), ensuring that only valid ratings are stored. The average_rating getter calculates the average rating based on the filtered ratings. This data analysis example shows how getters and setters can be used for data validation and processing in real-world applications.

Example 2: Data Pipeline Example — Image Processing

Let's consider a data pipeline for image processing. You want to create a ImagePipeline class that takes a list of images, resizes them, converts them to grayscale, and stores the processed images. We'll use setters to trigger the image processing and getters to access the processed images.

from PIL import Image

class ImagePipeline:
    def __init__(self, images):
        self._original_images = images
        self._processed_images = []

    @property
    def original_images(self):
        return self._original_images

    @original_images.setter
    def original_images(self, images):
        self._original_images = images
        self._processed_images = []  # Reset processed images when new images are set

    @property
    def processed_images(self):
        if not self._processed_images:
            self._process_images()
        return self._processed_images

    def _process_images(self):
        for image in self._original_images:
            resized_image = image.resize((100, 100))
            grayscale_image = resized_image.convert("L")
            self._processed_images.append(grayscale_image)

# Create an instance of the ImagePipeline class
image1 = Image.open("image1.jpg")
image2 = Image.open("image2.jpg")
image_pipeline = ImagePipeline([image1, image2])

# Set new images with the setter
image3 = Image.open("image3.jpg")
image_pipeline.original_images = [image2, image3]

# Access processed images with the getter (will trigger processing if not already done)
processed_images = image_pipeline.processed_images

In this example, the original_images setter allows you to set a new list of images for processing. Whenever you set new images, it resets the list of processed images to ensure accurate processing. The processed_images getter triggers the image processing if the processed images haven't been generated yet. It then returns the list of processed grayscale images.

This data pipeline example demonstrates how getters and setters can be used to manage and automate data processing steps, making the code more modular and organized. It's particularly useful when you need to handle complex data transformations and want to control the data flow through the pipeline.

Example 3: Data Analyzer

Let's consider an advanced example of a DataAnalyzer class that performs statistical analysis on a dataset. The dataset contains student exam scores, and we want to calculate various statistics such as mean, median, and standard deviation. We'll use getters to calculate these statistics on-demand, and setters to update the dataset.

import statistics

class DataAnalyzer:
    def __init__(self, data):
        self._data = data

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, new_data):
        if not all(isinstance(score, (int, float)) for score in new_data):
            raise ValueError("Data must contain numerical values.")
        self._data = new_data

    @property
    def mean(self):
        return statistics.mean(self._data)

    @property
    def median(self):
        return statistics.median(self._data)

    @property
    def standard_deviation(self):
        return statistics.stdev(self._data)

# Create an instance of the DataAnalyzer class
scores = [85, 78, 92, 64, 90]
analyzer = DataAnalyzer(scores)

# Get statistics using the getters
print(f"Original Data: {analyzer.data}")                     # Output: Original Data: [85, 78, 92, 64, 90]
print(f"Mean Score: {analyzer.mean:.2f}")                   # Output: Mean Score: 81.80
print(f"Median Score: {analyzer.median}")                   # Output: Median Score: 85
print(f"Standard Deviation: {analyzer.standard_deviation:.2f}")  # Output: Standard Deviation: 10.27

# Update the dataset using the setter
new_scores = [77, 88, 95, 71, 83, 90]
analyzer.data = new_scores

# Get statistics for the updated dataset
print(f"Updated Data: {analyzer.data}")                     # Output: Updated Data: [77, 88, 95, 71, 83, 90]
print(f"Mean Score: {analyzer.mean:.2f}")                   # Output: Mean Score: 84.00
print(f"Median Score: {analyzer.median}")                   # Output: Median Score: 85.5
print(f"Standard Deviation: {analyzer.standard_deviation:.2f}")  # Output: Standard Deviation: 7.61

In this example, the data setter ensures that only numerical values are allowed in the dataset. If you attempt to set non-numerical data, it raises a ValueError.

The mean, median, and standard_deviation getters calculate the corresponding statistics on-demand when accessed. This approach allows you to perform data analysis only when needed, avoiding unnecessary calculations and improving performance.

Using getters and setters in this data analysis example enables you to manage and analyze datasets with ease, ensuring data integrity and providing quick access to various statistical metrics.