Python - Functions

17.
How do you use the map() and filter() functions with a lambda function?

In Python, the map() and filter() functions are used with lambda functions to perform operations on iterables and filter elements based on a given condition, respectively.

Let's see how to use map() and filter() with lambda functions in the following example:

# Example using map() with lambda
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))

# Example using filter() with lambda
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))

# Print the results
print("Squared numbers:", squared)  # Output: [1, 4, 9, 16, 25]
print("Even numbers:", even_numbers)  # Output: [2, 4]

In this example, map() is used with a lambda function to square each element of the numbers list. filter() is used with a lambda function to filter only the even numbers from the numbers list. The results are printed to the console.


18.
What is a decorator, and how can it be applied to a function in Python?

In Python, a decorator is a design pattern that allows you to extend or modify the behavior of functions or methods without changing their code. Decorators are applied to functions using the @decorator syntax. They are commonly used for tasks such as logging, memoization, access control, and more.

Let's illustrate the concept with an example:

# Example of a decorator
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

# Applying the decorator
@my_decorator
def say_hello():
    print("Hello!")

# Calling the decorated function
say_hello()

In this example, the my_decorator function is a decorator that adds behavior before and after the decorated function say_hello is called. The @my_decorator syntax is used to apply the decorator to the say_hello function.

Output:

Something is happening before the function is called.
Hello!
Something is happening after the function is called.

Let's illustrate the concept with an example that includes a decorator with arguments:

# Example of a decorator with arguments
def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"Repeating {n} times:")
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

# Applying the decorator with arguments
@repeat(3)
def say_hello(name):
    print(f"Hello, {name}!")

# Calling the decorated function
say_hello("Alice")

In this example, the repeat decorator takes an argument n, and the wrapper function repeats the decorated function say_hello n times. The @repeat(3) syntax is used to apply the decorator with the argument 3 to the say_hello function.

Output:

Repeating 3 times:
Hello, Alice!
Hello, Alice!
Hello, Alice!

19.
Discuss the differences between functions and methods in Python.

In Python, both functions and methods are used to define blocks of reusable code, but there are key differences between them. The primary distinction lies in their association with objects.

A function is a block of code that performs a specific task and is not associated with any particular object or class. Functions are defined using the def keyword.

# Example of a function
def greet(name):
    return f"Hello, {name}!"

# Calling the function
result = greet("Alice")
print(result)

Output:

Hello, Alice!

On the other hand, a method is a function that is associated with an object. Methods are called on objects and are defined within classes. They operate on the data contained in the instance of the class.

# Example of a method
class Greeter:
    def greet(self, name):
        return f"Hello, {name}!"

# Creating an instance of the class
greeter_instance = Greeter()

# Calling the method on the instance
result = greeter_instance.greet("Bob")
print(result)

Output:

Hello, Bob!

In summary, functions are standalone blocks of code, while methods are functions associated with objects or instances of a class.


20.
How can you handle exceptions within a function using try and except blocks?

In Python, you can handle exceptions within a function using try and except blocks. This allows you to catch and handle specific errors that may occur during the execution of the function.

Let's illustrate this with an example:

def divide_numbers(x, y):
    try:
        result = x / y
        return result
    except ZeroDivisionError:
        return "Error: Cannot divide by zero"
    except TypeError:
        return "Error: Invalid data types"

# Example usages
result1 = divide_numbers(10, 2)
result2 = divide_numbers(5, 0)
result3 = divide_numbers("abc", 2)

# Print the results
print(result1)
print(result2)
print(result3)

Outputs:

5.0
Error: Cannot divide by zero
Error: Invalid data types

In this example, the divide_numbers function attempts to perform division, but it includes try and except blocks to handle potential errors. If a ZeroDivisionError occurs (division by zero) or a TypeError occurs (incompatible data types), the function returns appropriate error messages.