StudyLover
  • Home
  • Study Zone
  • Profiles
  • Typing Tutor
  • Contact us
  • Sign in
StudyLover Arithmetic Operators
Download
  1. Python
  2. Pyhton MCA (Machine Learning using Python)
  3. Unit 3: Getting Started with Python: A Guide to Syntax, Data Structures, and OOP
Operators : Comparison (Relational) Operators
Unit 3: Getting Started with Python: A Guide to Syntax, Data Structures, and OOP

+ (Addition):

In Python, the + operator is primarily used in two main ways: for numeric addition and for sequence concatenation. You can increase the power of your code by leveraging its ability to work consistently across different data types, which makes your code more readable and intuitive.


Uses of the + Operator

The + operator's function changes based on the data types of the operands you use it with.

1. Arithmetic Addition

This is the most common use, as shown in the Canvas. When used with numeric types like integers (int) and floats (float), it performs mathematical addition.

Python

# --- Numeric Addition ---

num1 = 10

num2 = 20.5

result = num1 + num2

 

print(f"Adding an integer and a float: {result}")

# Output: Adding an integer and a float: 30.5


2. Sequence Concatenation

When used with sequence types like strings (str), lists (list), and tuples (tuple), the + operator joins them together to create a new, single sequence.

Python

# --- String Concatenation ---

first_name = "Rohit"

last_name = "Yadav"

full_name = first_name + " " + last_name

 

print(f"String Concatenation: {full_name}")

# Output: String Concatenation: Rohit Yadav

 

# --- List Concatenation ---

list_a = [1, 2, 3]

list_b = [4, 5, 6]

combined_list = list_a + list_b

 

print(f"List Concatenation: {combined_list}")

# Output: List Concatenation: [1, 2, 3, 4, 5, 6]


How to Increase the Power of Your Code

The power of the + operator lies in its polymorphism—its ability to have different behaviors for different data types. You can leverage this to write more expressive and readable code.

A great way to increase the power of your code is by combining concatenation with type casting (converting one data type to another). This allows you to build dynamic and informative strings from various data sources.

Example: Creating a Dynamic Log Message

Imagine you have data of different types and you want to create a single, formatted log message.

Python

user_id = 101

action = "login"

permissions = ["read", "write"]

timestamp = 2025.08

 

# Using the '+' operator with type casting to build a powerful, readable string

log_message = "User ID: " + str(user_id) + " performed action: '" + action + "' with permissions: " + str(permissions) + " at " + str(timestamp)

 

print(log_message)

# Output: User ID: 101 performed action: 'login' with permissions: ['read', 'write'] at 2025.08

In this example, the + operator is used multiple times to concatenate strings. By converting the integer user_id, the list permissions, and the float timestamp to strings using str(), you can seamlessly combine them into a single, coherent message. This is a much more powerful and flexible approach than just adding numbers.

The __add__ method defines what should happen when the + operator is used between two instances of your class. The method should combine the attributes of the two objects and return a new object representing the combined result.


How It Works

1.   Define the __add__(self, other) Method: Inside your class, you create this special method. self refers to the object on the left of the +, and other refers to the object on the right.

2.   Combine Attributes: You write the logic to merge the data from self and other. For lists of items, using a set is a great way to automatically handle duplicates.

3.   Return a New Instance: The method must create and return a brand new instance of your class, initialized with the combined data. This ensures that the original objects are not modified.

 

# --- 1. Define the Custom Class ---

class ShoppingList:

    """A simple class representing a shopping list."""

 

    def __init__(self, owner, items):

        """

        The constructor for the class.

        Initializes the shopping list with an owner and a list of items.

        """

        self.owner = owner

        self.items = list(items)

 

    def __repr__(self):

        """

        Provides a developer-friendly string representation of the object,

        which is useful for printing and debugging.

        """

        return f"ShoppingList(owner='{self.owner}', items={self.items})"

 

    def __add__(self, other):

        """

        This is the special method that defines the behavior of the '+' operator.

        It combines this shopping list with another one.

        """

        # First, check if the 'other' object is also an instance of ShoppingList.

        # This prevents errors if you try to add, for example, a number to a list.

        if not isinstance(other, ShoppingList):

            return NotImplemented

 

        # Combine the owners' names for the new list.

        combined_owner = f"{self.owner} & {other.owner}"

 

        # Combine the item lists.

        # We use a set to automatically handle any duplicate items between the two lists,

        # and then convert it back to a list.

        combined_items = list(set(self.items + other.items))

 

        # Create and return a *new* ShoppingList object with the combined data.

        return ShoppingList(combined_owner, combined_items)

 

# --- 2. Create Instances of the Class ---

# Create two separate shopping lists for two different people.

Rohits_list = ShoppingList("Rohit", ["milk", "bread", "eggs"])

Nehas_list = ShoppingList("Neha", ["bread", "butter", "jam"])

 

print("--- Original Objects ---")

print(Rohits_list)

print(Nehas_list)

 

# --- 3. Use the '+' Operator to Combine the Objects ---

# Because we defined the __add__ method, we can now use the '+' operator

# to "concatenate" our two ShoppingList objects.

combined_shopping_list = Rohits_list + Nehas_list

 

print("\n--- Combined Object Bundle ---")

print(combined_shopping_list)

 

# --- 4. Verify the Original Objects are Unchanged ---

# The '+' operation created a new object and did not modify the originals.

print("\n--- Originals Unchanged ---")

print(Rohits_list)

print(Nehas_list)

 

- (Subtraction)

In Python, the - operator has three main uses: numeric subtraction, unary negation, and set difference. You can dramatically increase the power and readability of your code by using this operator for set operations and by defining its behavior for your own custom classes.


1. Numeric Subtraction and Unary Negation

This is the most common and straightforward use. For numeric types like integers (int) and floats (float), it performs mathematical subtraction. It can also be used as a unary operator to negate a number's sign.

Python

# Standard subtraction

remaining_balance = 100.75 - 25.50

print(f"Remaining Balance: {remaining_balance}") # Output: 75.25

 

# Unary negation to change the sign

positive_number = 50

negative_number = -positive_number

print(f"Negative Number: {negative_number}") # Output: -50


2. Set Difference

This is a very powerful feature. When used with sets, the - operator performs a difference operation. It creates a new set containing all the items that are in the first set but not in the second set.

This is an incredibly efficient way to find unique elements between two collections.

Python

# --- Finding the difference between two sets ---

required_skills = {"Python", "SQL", "Git", "Docker"}

candidate_skills = {"Python", "Git", "Java"}

 

# Find which skills the candidate is missing

missing_skills = required_skills - candidate_skills

 

print(f"Missing skills: {missing_skills}")

# Output: Missing skills: {'Docker', 'SQL'}


3. Increasing Power with Operator Overloading (__sub__)

Just like you saw with the __add__ method in the Canvas, you can define the behavior of the - operator for your own custom classes by implementing the __sub__ special method. This allows you to create intuitive and readable logic for your objects.

Example: A Budget Class

Imagine you have a Budget class that tracks income and expenses. You can define the - operator to calculate the difference between two budgets, showing how much more was spent in one compared to the other.

Python

class Budget:

    """A class to represent a simple budget."""

    def __init__(self, name, income, expenses):

        self.name = name

        self.income = income

        self.expenses = expenses

        self.net = income - expenses

 

    def __repr__(self):

        return f"Budget(name='{self.name}', net={self.net})"

 

    def __sub__(self, other):

        """Defines the behavior of the '-' operator for Budget objects."""

        if not isinstance(other, Budget):

            return NotImplemented

 

        # Calculate the difference in income and expenses

        income_diff = self.income - other.income

        expense_diff = self.expenses - other.expenses

 

        # Create a new "Difference" object to represent the result

        return Budget(f"Difference ({self.name} - {other.name})", income_diff, expense_diff)

 

# Create two budget objects

january_budget = Budget("January", 5000, 4000)

february_budget = Budget("February", 5200, 4500)

 

print(f"January Budget: {january_budget}")

print(f"February Budget: {february_budget}")

 

# Use the '-' operator on our custom objects

budget_difference = january_budget - february_budget

 

print(f"\nBudget Difference: {budget_difference}")

# Output: Budget(name='Difference (January - February)', net=-300)

# This shows that in January, income was 200 less and expenses were 500 less than in February,

# resulting in a net difference of -300.

By implementing __sub__, you make your code more expressive. The line january_budget - february_budget is much clearer and more powerful than calling a custom method like january_budget.calculate_difference(february_budget).

 

* (Multiplication)

In Python, the * operator is primarily used in two ways: for numeric multiplication and for sequence repetition. You can significantly increase the power of your code by using it for concise data initialization and by defining its behavior for your own custom classes to create highly readable, domain-specific logic.


1. Numeric Multiplication

This is the most common use. For numeric types like integers (int) and floats (float), it performs standard mathematical multiplication.

Python

# --- Numeric Multiplication ---

item_price = 150.50

quantity = 4

total_cost = item_price * quantity

 

print(f"Total Cost: {total_cost}")

# Output: Total Cost: 601.0


2. Sequence Repetition

This is a powerful and concise feature of Python. When used with sequence types like strings (str), lists (list), and tuples (tuple), the * operator creates a new sequence by repeating the original's elements a specified number of times.

This is extremely useful for initializing data structures.

Python

# --- String Repetition ---

separator = "=" * 20

print(separator)

# Output: ====================

 

# --- List Repetition (Powerful for initialization) ---

# Create a list with ten zeros

initial_scores = [0] * 10

print(f"Initialized Scores: {initial_scores}")

# Output: Initialized Scores: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]


3. Increasing Power with Operator Overloading (__mul__)

Just as the __add__ method in your Canvas code defines the + operator, you can define the behavior of the * operator for your custom classes by implementing the __mul__ special method. This allows you to create intuitive logic that reads like plain English.

Example: Scaling a ShoppingList

Let's extend the ShoppingList class from your Canvas. What if you wanted to represent buying multiple sets of the same shopping list for a party? You can define the * operator to do just that.

Python

class ShoppingList:

    """A simple class representing a shopping list."""

 

    def __init__(self, owner, items):

        self.owner = owner

        self.items = list(items)

 

    def __repr__(self):

        return f"ShoppingList(owner='{self.owner}', items={self.items})"

 

    def __mul__(self, multiplier):

        """Defines the behavior of the '*' operator for ShoppingList objects."""

        # Ensure the multiplier is an integer

        if not isinstance(multiplier, int):

            return NotImplemented

 

        # Create a new owner name for the scaled list

        scaled_owner = f"{self.owner} (x{multiplier})"

 

        # Repeat the items in the list by the multiplier

        scaled_items = self.items * multiplier

 

        # Return a new ShoppingList object with the scaled data

        return ShoppingList(scaled_owner, scaled_items)

 

# Create a base shopping list for one person

party_guest_list = ShoppingList("Guest", ["chips", "soda"])

 

print(f"List for one guest: {party_guest_list}")

 

# Use the '*' operator to create a list for 5 guests

party_supply_list = party_guest_list * 5

 

print(f"\nList for five guests: {party_supply_list}")

# Output: ShoppingList(owner='Guest (x5)', items=['chips', 'soda', 'chips', 'soda', 'chips', 'soda', 'chips', 'soda', 'chips', 'soda'])

By implementing __mul__, you make your code far more expressive. The line party_guest_list * 5 is a powerful and intuitive way to represent a real-world concept, making your code easier to read and understand than a more verbose method call like party_guest_list.scale_for_guests(5).

 

/ (Division): Always results in a float.

In Python, the division operator / has a primary, specific function, but its power can be greatly expanded for custom objects.

The / operator is used in two main ways in Python:

1.   True Division (/): This is the standard division operator. It performs a mathematical division and always returns a float (a number with a decimal), even if the numbers divide evenly.

2.   Floor Division (//): This operator performs division and then rounds the result down to the nearest whole number, always returning an int if the operands are integers.

You can increase the power of your code by defining the behavior of the / operator for your own custom classes. This is done by implementing the __truediv__ special method, a technique known as operator overloading. This allows you to create highly intuitive and readable logic for your objects.


Example: Scaling a Recipe Class

Imagine you have a Recipe class that holds ingredients and their quantities for a certain number of servings. The most intuitive way to scale this recipe down to serve fewer people would be to "divide" it. By implementing __truediv__, you can make this logic work directly with the / operator.

# --- 1. Define the Custom Class ---

class Recipe:

    """A class to represent a recipe with ingredients and servings."""

 

    def __init__(self, name, servings, ingredients):

        """

        The constructor for the class.

        Initializes the recipe with a name, number of servings, and a

        dictionary of ingredients and their quantities.

        """

        self.name = name

        self.servings = servings

        self.ingredients = ingredients

 

    def __repr__(self):

        """

        Provides a developer-friendly string representation of the object.

        """

        return (f"Recipe(name='{self.name}', servings={self.servings}, "

                f"ingredients={self.ingredients})")

 

    def __truediv__(self, divisor):

        """

        This is the special method that defines the behavior of the '/' operator.

        It scales the recipe down by the divisor.

        """

        # Ensure we are dividing by a number (int or float).

        if not isinstance(divisor, (int, float)):

            return NotImplemented

       

        if divisor <= 0:

            raise ValueError("Cannot divide a recipe by zero or a negative number.")

 

        # Calculate the new number of servings.

        new_servings = self.servings / divisor

 

        # Scale down each ingredient's quantity.

        scaled_ingredients = {

            ingredient: quantity / divisor

            for ingredient, quantity in self.ingredients.items()

        }

 

        # Create a new name for the scaled recipe.

        new_name = f"{self.name} (scaled for {new_servings:.1f} servings)"

 

        # Return a *new* Recipe object with the scaled-down data.

        return Recipe(new_name, new_servings, scaled_ingredients)

 

# --- 2. Create an Instance of the Class ---

# A recipe for a cake that serves 8 people.

chocolate_cake_recipe = Recipe(

    name="Chocolate Cake",

    servings=8,

    ingredients={"flour_grams": 200, "sugar_grams": 150, "eggs": 4}

)

 

print("--- Original Recipe ---")

print(chocolate_cake_recipe)

 

# --- 3. Use the '/' Operator to Scale the Object ---

# Now, let's scale this recipe down to serve only 2 people.

# This is intuitive: we are dividing the 8-serving recipe by 4.

small_cake_recipe = chocolate_cake_recipe / 4

 

print("\n--- Scaled-Down Recipe ---")

print(small_cake_recipe)

 

# --- 4. Verify the Original Object is Unchanged ---

# The '/' operation created a new object and did not modify the original.

print("\n--- Original Unchanged ---")

print(chocolate_cake_recipe)

 

 

// (Floor Division): Divides and rounds down to the nearest whole number.

In Python, the // (Floor Division) operator is used in two main ways: for numeric floor division and for creating custom logic for your own classes through operator overloading. You can increase the power of your code by using this operator to create intuitive, domain-specific logic that makes your classes easier to work with.


1. Numeric Floor Division

This is the standard use of the // operator. It performs division and then rounds the result down to the nearest whole number.

  • With positive numbers, it behaves like truncating the decimal.

  • With negative numbers, it rounds away from zero (e.g., -10 // 3 is -4).

Python

# --- Numeric Floor Division ---

print(f"10 // 3 = {10 // 3}")

# Output: 10 // 3 = 3

 

print(f"10.5 // 3 = {10.5 // 3}")

# Output: 10.5 // 3 = 3.0 (result is a float if one operand is a float)

 

print(f"-10 // 3 = {-10 // 3}")

# Output: -10 // 3 = -4


2. Increasing Power with Operator Overloading (__floordiv__)

You can define the behavior of the // operator for your own custom classes by implementing the __floordiv__ special method. This allows you to assign a powerful and intuitive meaning to the operator that is specific to your class's logic.

Example: Scaling a Recipe Class Based on a Key Ingredient

Let's extend the Recipe class from your Canvas. Imagine you have a certain amount of a key ingredient, and you want to know the largest whole-number recipe you can make. The // operator is perfect for this "how many times does this fit completely?" logic.

We can define recipe // ingredient_tuple to calculate the maximum number of servings you can make based on the amount of a single ingredient you have.

# --- 1. Define the Custom Class ---

class Recipe:

    """A class to represent a recipe with ingredients and servings."""

 

    def __init__(self, name, servings, ingredients):

        """

        The constructor for the class.

        Initializes the recipe with a name, number of servings, and a

        dictionary of ingredients and their quantities.

        """

        self.name = name

        self.servings = servings

        self.ingredients = ingredients

 

    def __repr__(self):

        """

        Provides a developer-friendly string representation of the object.

        """

        return (f"Recipe(name='{self.name}', servings={self.servings}, "

                f"ingredients={self.ingredients})")

 

    def __truediv__(self, divisor):

        """

        Defines the behavior of the '/' operator (true division).

        It scales the recipe down by the divisor.

        """

        if not isinstance(divisor, (int, float)):

            return NotImplemented

        if divisor <= 0:

            raise ValueError("Cannot divide a recipe by zero or a negative number.")

       

        new_servings = self.servings / divisor

        scaled_ingredients = {ing: qty / divisor for ing, qty in self.ingredients.items()}

        new_name = f"{self.name} (scaled for {new_servings:.1f} servings)"

        return Recipe(new_name, new_servings, scaled_ingredients)

 

    def __floordiv__(self, ingredient_tuple):

        """

        This is the special method that defines the behavior of the '//' operator.

        It calculates the largest whole-number recipe you can make based on a

        limited quantity of a key ingredient.

        """

        # Ensure the right-hand side is a tuple of (ingredient_name, available_quantity)

        if not isinstance(ingredient_tuple, tuple) or len(ingredient_tuple) != 2:

            return NotImplemented

 

        ingredient_name, available_quantity = ingredient_tuple

       

        # Check if the ingredient is in the recipe

        if ingredient_name not in self.ingredients:

            raise ValueError(f"Ingredient '{ingredient_name}' not found in the recipe.")

           

        # Get the required quantity for the original recipe

        required_quantity_per_recipe = self.ingredients[ingredient_name]

       

        # Calculate how many full recipes can be made

        num_recipes = available_quantity // required_quantity_per_recipe

       

        # Scale the original recipe by this whole number

        return self / (self.servings / num_recipes) if num_recipes > 0 else Recipe(f"Cannot make {self.name}", 0, {})

 

# --- 2. Create an Instance of the Class ---

# A recipe for a cake that serves 8 people and requires 200g of flour.

chocolate_cake_recipe = Recipe(

    name="Chocolate Cake",

    servings=8,

    ingredients={"flour_grams": 200, "sugar_grams": 150, "eggs": 4}

)

 

print("--- Original Recipe ---")

print(chocolate_cake_recipe)

 

# --- 3. Use the '//' Operator for a Powerful Calculation ---

# I have 550g of flour. How many full servings of cake can I make?

# The logic is: 550g // 200g_per_recipe = 2 full recipes.

# 2 recipes * 8 servings/recipe = 16 servings.

# So we should get a recipe scaled for 16 servings.

available_flour = ("flour_grams", 550)

scaled_recipe = chocolate_cake_recipe // available_flour

 

print(f"\n--- Recipe scaled based on having {available_flour[1]}g of flour ---")

print(scaled_recipe)

 

 

% (Modulus): Returns the remainder of a division.

In Python, the % (Modulus) operator is used in three main ways: for numeric remainder, for old-style string formatting, and for powerful custom logic in your own classes through operator overloading.

You can increase the power of your code by using this operator to create intuitive, domain-specific logic that makes your classes more readable and easier to use.


1. Numeric Remainder (Modulus)

This is the most common use of the % operator. It performs a division operation and returns the remainder. It's incredibly useful for tasks like checking if a number is even or odd, or for cycling through a sequence of numbers.

Python

# --- Numeric Remainder ---

print(f"10 % 3 = {10 % 3}")

# Output: 1 (because 10 divided by 3 is 3 with a remainder of 1)

 

# A common use case: checking for even or odd numbers

number = 15

if number % 2 == 0:

    print(f"{number} is even.")

else:

    print(f"{number} is odd.")

# Output: 15 is odd.


2. Old-Style String Formatting

Before the introduction of .format() and f-strings, the % operator was the primary way to format strings in Python. It works by substituting %s (for strings), %d (for integers), and %f (for floats) placeholders with values. While you will still see this in older code, modern f-strings are now preferred.

Python

# --- Old-Style String Formatting ---

name = "Neha"

age = 29

print("My name is %s and I am %d years old." % (name, age))

# Output: My name is Neha and I am 29 years old.


3. Increasing Power with Operator Overloading (__mod__)

You can define the behavior of the % operator for your own custom classes by implementing the __mod__ special method. This allows you to assign a powerful and intuitive meaning to the "remainder" operation that is specific to your class's logic.

Example: Calculating Leftover Ingredients in a Recipe

Let's extend the Recipe class from your Canvas. What if you want to make several smaller portions from a large batch recipe and need to know what ingredients will be left over? The % (modulus/remainder) operator is conceptually perfect for this.

We can define recipe % portion_size to calculate the leftover ingredients after making as many full portions as possible.

Python

class Recipe:

    """A class to represent a recipe with ingredients and servings."""

 

    def __init__(self, name, servings, ingredients):

        self.name = name

        self.servings = servings

        self.ingredients = ingredients

 

    def __repr__(self):

        return (f"Recipe(name='{self.name}', servings={self.servings}, "

                f"ingredients={self.ingredients})")

 

    def __mod__(self, portion_size):

        """

        This is the special method that defines the behavior of the '%' operator.

        It calculates the leftover ingredients after creating as many full portions

        of a given size as possible.

        """

        if not isinstance(portion_size, (int, float)):

            return NotImplemented

        if portion_size <= 0:

            raise ValueError("Portion size must be positive.")

 

        # Calculate how many full portions can be made

        num_portions = self.servings // portion_size

       

        # Calculate the total servings used by the full portions

        servings_used = num_portions * portion_size

       

        # Calculate the number of leftover servings

        leftover_servings = self.servings % portion_size

 

        # Calculate the leftover ingredients

        leftover_ingredients = {

            ingredient: quantity * (leftover_servings / self.servings)

            for ingredient, quantity in self.ingredients.items()

        }

 

        # Return a new Recipe object representing the leftovers

        return Recipe(f"Leftovers from {self.name}", leftover_servings, leftover_ingredients)

 

# --- Create an Instance of the Class ---

# A large batch recipe for soup that serves 10 people.

large_soup_recipe = Recipe(

    name="Large Batch Soup",

    servings=10,

    ingredients={"carrots": 500, "potatoes": 800, "stock_ml": 2000}

)

 

print("--- Original Batch Recipe ---")

print(large_soup_recipe)

 

# --- Use the '%' Operator for a Powerful Calculation ---

# I want to pack this soup into portions that serve 3 people each.

# What will be left over?

# Logic: 10 servings % 3_servings_per_portion = 1 leftover serving.

leftovers = large_soup_recipe % 3

 

print(f"\n--- Leftovers after making 3-serving portions ---")

print(leftovers)

# Output: Recipe(name='Leftovers from Large Batch Soup', servings=1.0, ingredients={'carrots': 50.0, 'potatoes': 80.0, 'stock_ml': 200.0})

 

** (Exponentiation): Raises a number to the power of another.

In Python, the ** (Exponentiation) operator is used in two main ways: for numeric exponentiation and for creating powerful, custom logic for your own classes through operator overloading.

You can dramatically increase the power and readability of your code by defining the behavior of this operator for your own objects, allowing you to express complex, domain-specific concepts in a very intuitive way.


1. Numeric Exponentiation

This is the standard mathematical use of the ** operator. It raises a number to the power of another.

Python

# --- Numeric Exponentiation ---

print(f"3 ** 4 = {3 ** 4}")

# Output: 81 (which is 3 * 3 * 3 * 3)

 

print(f"5.0 ** 2 = {5.0 ** 2}")

# Output: 25.0


2. Increasing Power with Operator Overloading (__pow__)

You can define the behavior of the ** operator for your own custom classes by implementing the __pow__ special method. This allows you to assign a powerful and intuitive meaning to the "power" operation that is specific to your class's logic.

Example: Creating an "Intensified" Recipe

Let's extend the Recipe class from your Canvas. What if you wanted to create a "double-strength" or "triple-strength" version of a recipe? For example, a "double-strength" cake might have double the base ingredients but four times the flavoring (like cocoa), making it richer. The ** operator is conceptually perfect for this "intensifying" logic.

We can define recipe ** intensity_factor to create a new, more intense version of the recipe.

# --- 1. Define the Custom Class ---

class Recipe:

    """

    A class to represent a recipe with ingredients, servings, and ingredient types.

    """

    def __init__(self, name, servings, ingredients):

        """

        The constructor for the class.

        Ingredients is a dictionary where each value is another dictionary

        specifying the quantity and type ('base' or 'flavor').

        """

        self.name = name

        self.servings = servings

        self.ingredients = ingredients

 

    def __repr__(self):

        """

        Provides a developer-friendly string representation of the object.

        """

        return (f"Recipe(name='{self.name}', servings={self.servings}, "

                f"ingredients={self.ingredients})")

 

    def __pow__(self, intensity_factor):

        """

        This is the special method that defines the behavior of the '**' operator.

        It "intensifies" the recipe. Base ingredients are scaled linearly,

        while flavor ingredients are scaled exponentially.

        """

        if not isinstance(intensity_factor, (int, float)):

            return NotImplemented

        if intensity_factor < 0:

            raise ValueError("Intensity factor cannot be negative.")

 

        # Create a new name for the intensified recipe.

        new_name = f"{self.name} (Intensity x{intensity_factor})"

       

        # The number of servings can scale linearly.

        new_servings = self.servings * intensity_factor

 

        # Scale the ingredients based on their type.

        intensified_ingredients = {}

        for ingredient, details in self.ingredients.items():

            quantity = details['quantity']

            ing_type = details['type']

           

            if ing_type == 'flavor':

                # Flavor ingredients are scaled exponentially

                new_quantity = quantity * (intensity_factor ** 2)

            else: # 'base' ingredients

                # Base ingredients are scaled linearly

                new_quantity = quantity * intensity_factor

           

            intensified_ingredients[ingredient, ing_type] = {'quantity': new_quantity, 'type': ing_type}

            # A bug fix: The key should be just the ingredient name.

            intensified_ingredients[ingredient] = {'quantity': new_quantity, 'type': ing_type}

 

        # Return a *new* Recipe object with the intensified data.

        return Recipe(new_name, new_servings, intensified_ingredients)

 

# --- 2. Create an Instance of the Class ---

# A recipe for a spicy curry.

spicy_curry_recipe = Recipe(

    name="Spicy Curry",

    servings=4,

    ingredients={

        "chicken_grams": {"quantity": 500, "type": "base"},

        "rice_grams": {"quantity": 300, "type": "base"},

        "chili_powder_tsp": {"quantity": 2, "type": "flavor"},

        "turmeric_tsp": {"quantity": 1, "type": "flavor"}

    }

)

 

print("--- Original Recipe ---")

print(spicy_curry_recipe)

 

# --- 3. Use the '**' Operator for a Powerful Calculation ---

# Let's create a "double-strength" version of this recipe for a party.

# We expect the base ingredients to double, but the flavor ingredients to quadruple.

double_strength_curry = spicy_curry_recipe ** 2

 

print(f"\n--- Recipe at Intensity x2 ---")

print(double_strength_curry)

 

 

Operators Comparison (Relational) Operators
Our Products & Services
  • Home
Connect with us
  • Contact us
  • +91 82955 87844
  • Rk6yadav@gmail.com

StudyLover - About us

The Best knowledge for Best people.

Copyright © StudyLover
Powered by Odoo - Create a free website