04 - Functions & Exception Handling

Functions

  • A function in Python is a reusable block of code that performs a specific task.

  • Functions are used to organize code, make it more readable, and avoid repetition.

Defining a Function

def function_name(parameters):
    """
    Optional docstring to describe the function.
    """
    # Function body
    return result  # Optional return statement

Function Arguments

  • Functions can take different types of arguments:

Positional Arguments

  • Arguments are matched to parameters by their position.

      def add(a, b):
          return a + b
    
      print(add(3, 5))  # Output: 8
    

Keyword Arguments (Named arguments)

  • Arguments are matched by the parameter name.

      def introduce(name, age):
          return f"I am {name}, and I am {age} years old."
    
      print(introduce(age=30, name="Bob"))  # Output: I am Bob, and I am 30 years old.
    

Default Arguments

  • Provide default values for parameters.

      def greet(name="Guest"):
          return f"Hello, {name}!"
    
      print(greet())         # Output: Hello, Guest!
      print(greet("Alice"))  # Output: Hello, Alice!
    

Arbitrary Arguments (*args)

  • Use *args to accept any number of positional arguments.

      def sum_all(*numbers):
          return sum(numbers)
    
      print(sum_all(1, 2, 3, 4))  # Output: 10
    

Arbitrary Keyword Arguments (**kwargs)

  • Use **kwargs to accept any number of keyword arguments.

      def display_info(**info):
          for key, value in info.items():
              print(f"{key}: {value}")
    
      display_info(name="Alice", age=25, city="New York")
      # Output:
      # name: Alice
      # age: 25
      # city: New York
    

Return Statement

  • The return statement is used to send a result back to the caller.

      def square(num):
          return num * num
    
      result = square(4)
      print(result)  # Output: 16
    
    • If no return statement is used, the function returns None.

Scope of Variables

  • Local Variables: Defined inside a function and accessible only within it.

  • Global Variables: Defined outside any function and accessible anywhere.

      x = 10  # Global variable
    
      def change_x():
          global x                    # make a local variable global using 'global' keyword
          x = 20  # Modify the global variable
    
      change_x()
      print(x)  # Output: 20
    

Lambda Functions

  • Lambda functions are anonymous functions defined using the lambda keyword.

      lambda arguments: expression
    
      # Example
      # Regular function
      def square(x):
          return x * x
    
      # Lambda function
      square = lambda x: x * x
      print(square(5))  # Output: 25
    
      # Lambda with multiple arguments
      add = lambda a, b: a + b
      print(add(3, 7))  # Output: 10
    

Exception Handling

  • Exception handling in Python is a mechanism to gracefully handle errors that occur during program execution, ensuring the program doesn't crash unexpectedly.

  • Python provides the try-except block to manage exceptions.

What is an Exception?

An exception is an event that disrupts the normal flow of a program. Common examples include:

  • ZeroDivisionError: Division by zero.

  • FileNotFoundError: Trying to open a non-existent file.

  • ValueError: Invalid argument to a function.

  • KeyError: Accessing a non-existent dictionary key.

Basic Syntax of try-except

try:
    # Code that may raise an exception
    risky_code()
except ExceptionType:
    # Code to handle the exception
    handle_exception()

Catching Multiple Exceptions

  • You can handle multiple exceptions using multiple except blocks.

      try:
          num = int(input("Enter a number: "))
          result = 10 / num
      except ValueError:
          print("Invalid input. Please enter a number.")
      except ZeroDivisionError:
          print("You cannot divide by zero.")
    

Using else with try-except

  • The else block is executed if no exception is raised in the try block.

      try:
          num = int(input("Enter a number: "))
          result = 10 / num
      except ZeroDivisionError:
          print("You cannot divide by zero.")
      except ValueError:
          print("Invalid input.")
      else:
          print(f"Result: {result}")
    

Using finally

  • The finally block always executes, regardless of whether an exception occurs. It is typically used for cleanup actions.

      try:
          file = open("example.txt", "r")
          print(file.read())
      except FileNotFoundError:
          print("File not found.")
      finally:
          print("Closing file.")
          file.close()
    

Catching Any Exception

  • To catch any exception, use the Exception class.

      try:
          num = int(input("Enter a number: "))
          result = 10 / num
      except Exception as e:
          print(f"An error occurred: {e}")
    

Raising Exceptions

  • You can raise exceptions manually using the raise keyword.

      def validate_age(age):
          if age < 0:
              raise ValueError("Age cannot be negative.")
          return f"Age is {age}"
    
      try:
          print(validate_age(-5))
      except ValueError as e:
          print(e)
    

Exception Hierarchy in Python

  • Exceptions in Python follow a hierarchy:

    • BaseException

      • Exception

        • ArithmeticError

          • ZeroDivisionError
        • ValueError

        • KeyError

Assertion Exception

  • The AssertionError in Python occurs when an assert statement fails.

  • The assert statement is used to debug a program by testing whether a condition is True.

  • If the condition evaluates to False, Python raises an AssertionError exception.

Syntax of assert

assert condition, optional_message
  • condition: A boolean expression that should evaluate to True.

  • optional_message: A message that is displayed if the assertion fails (optional).

How Assertions Work

  • When Python encounters an assert statement:

    1. It evaluates the condition.

    2. If the condition is True, the program continues execution.

    3. If the condition is False, an AssertionError is raised, and the optional message (if provided) is displayed.

Handling AssertionError

  • You can handle an AssertionError using a try-except block.

      try:
          x = -1
          assert x >= 0, "x is negative"
      except AssertionError as e:
          print(f"Assertion failed: {e}")        # Assertion failed: x is negative