Data Science Python Interview Questions

author image Hirely
at 05 Jan, 2025

Question: How do you handle exceptions in Python?

Answer:

In Python, exceptions are handled using the try, except, else, and finally blocks. These blocks allow you to catch errors and handle them gracefully without crashing your program. Here’s a detailed breakdown of how you can handle exceptions:


1. try Block:

  • The try block is used to wrap the code that may raise an exception.
  • If an exception occurs within the try block, Python will stop executing the rest of the code in the block and move to the except block.

Example:

try:
    # Code that may raise an exception
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")

In this example, dividing by zero raises a ZeroDivisionError, which is caught by the except block.


2. except Block:

  • The except block is used to catch and handle specific exceptions.
  • You can specify the type of exception you want to catch (e.g., ZeroDivisionError, ValueError, etc.).
  • If no exceptions occur in the try block, the except block is skipped.

Example (Catching a specific exception):

try:
    num = int(input("Enter a number: "))
except ValueError:
    print("Invalid input, please enter a valid integer.")

In this example, if the user enters a non-integer, a ValueError will be raised, and the message “Invalid input…” will be printed.


3. else Block:

  • The else block, if present, will be executed if no exceptions are raised in the try block.
  • It is typically used to run code that should only be executed when the try block is successful.

Example:

try:
    result = 10 / 2
except ZeroDivisionError:
    print("Cannot divide by zero!")
else:
    print(f"Result is {result}")

In this case, since no exception occurs, the else block will execute, printing “Result is 5.0”.


4. finally Block:

  • The finally block, if present, will always execute after the try and except blocks, regardless of whether an exception was raised or not.
  • It is typically used for cleanup operations, like closing files, releasing resources, or ensuring that certain code is always run.

Example:

try:
    file = open('example.txt', 'r')
    content = file.read()
except FileNotFoundError:
    print("File not found!")
finally:
    file.close()  # This will always execute, even if an exception is raised.
    print("File is closed.")

In this example, the finally block ensures that the file is closed even if an error occurs while reading the file.


5. Catching Multiple Exceptions:

You can catch multiple exceptions in a single except block or use multiple except blocks for different exceptions.

Example (Multiple exceptions):

try:
    x = int(input("Enter a number: "))
    y = 10 / x
except ValueError:
    print("That's not a valid number!")
except ZeroDivisionError:
    print("You can't divide by zero!")

In this example:

  • If the user enters a non-integer, the ValueError block will handle it.
  • If the user enters 0, the ZeroDivisionError block will handle it.

You can catch all exceptions using a generic except clause, but it is generally not recommended because it may catch unexpected exceptions, making debugging difficult.

Example (Catching all exceptions):

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

This will catch any exception, and the error message will be displayed.

Note: It’s better to catch specific exceptions to handle different types of errors appropriately.


7. Raising Exceptions:

You can also raise exceptions intentionally using the raise keyword. This is useful when you want to trigger an error condition in your code.

Example:

def divide(a, b):
    if b == 0:
        raise ValueError("The denominator cannot be zero.")
    return a / b

try:
    result = divide(10, 0)
except ValueError as e:
    print(e)

In this case, a ValueError is raised if the denominator is zero, and the error message is printed.


Summary of Exception Handling Blocks:

  • try: Wraps the code that might raise an exception.
  • except: Handles exceptions that occur in the try block.
  • else: Runs if no exception occurs in the try block.
  • finally: Always runs, whether an exception occurred or not.

Conclusion:

Exception handling in Python allows you to gracefully manage errors, ensuring that your program continues to run smoothly even when unexpected situations arise. By using the try, except, else, and finally blocks, you can handle different kinds of errors, clean up resources, and keep your program robust and user-friendly.

Question: What are Python’s namespaces?

Answer:

A namespace in Python refers to a container where names (identifiers) are mapped to objects. In simple terms, it is a space that holds all the variable names and their corresponding objects (values). These namespaces are used to keep track of variable names in a way that allows Python to know what each variable refers to.

Namespaces help in preventing naming conflicts by ensuring that each variable name is unique within its specific namespace. When you refer to a variable or function in Python, the interpreter uses the namespace to figure out what value that name points to.


Types of Namespaces in Python:

  1. Built-in Namespace:

    • This is the namespace that contains built-in objects like functions, exceptions, and other standard Python objects (e.g., print(), len(), int(), etc.).
    • It is created when Python starts and exists as long as the interpreter is running.
  2. Global Namespace:

    • This namespace refers to the top-level environment where functions and variables are defined. It exists for the duration of the program’s execution.
    • The global namespace is created when the program is executed, and variables/functions defined at the top level are part of this namespace.
  3. Local Namespace:

    • This namespace exists inside a function or method. It contains the names of variables and functions local to that specific function or block of code.
    • A new local namespace is created when a function is called, and it is destroyed when the function execution is complete.
  4. Enclosing Namespace:

    • This namespace refers to variables that are in the outer (enclosing) scope of a function. It is relevant when working with nested functions, where an inner function can access variables from an outer function’s scope.
    • It lies between the global and local namespaces in terms of scope.

How Python Resolves Names: LEGB Rule

Python uses the LEGB rule (Local, Enclosing, Global, Built-in) to resolve the names of variables and functions. When Python encounters a name, it searches for that name in the following order:

  1. Local: The namespace of the current function or method.
  2. Enclosing: The namespace of any enclosing functions (if the current function is nested inside another).
  3. Global: The top-level namespace, where variables and functions are defined in the main program.
  4. Built-in: The built-in namespace, which contains Python’s built-in functions and objects.

Example of LEGB Rule:

x = "global x"

def outer():
    x = "outer x"
    
    def inner():
        x = "inner x"
        print(x)  # This will print the value of 'x' in the local namespace of inner function
    inner()

outer()
  • In this case:
    • The inner function inner() first looks for x in its local scope (and finds "inner x").
    • If it didn’t find x there, it would check the enclosing scope, i.e., the outer() function (and find "outer x").
    • If still not found, it would check the global scope (and find "global x").
    • Finally, if not found in any of the above, it would look in the built-in namespace (but there is no built-in x).

The output of the code will be:

inner x

This is because Python first looks in the local namespace of the inner() function, finds the variable x, and prints it.


Modifying Variables in Different Namespaces:

  • Global Variables: You can modify a global variable inside a function using the global keyword.

    x = 10  # global variable
    
    def modify_global():
        global x
        x = 20  # modifies the global 'x'
    
    modify_global()
    print(x)  # Output: 20
  • Nonlocal Variables: You can modify a variable in the enclosing (non-global) namespace using the nonlocal keyword, typically in the case of nested functions.

    def outer():
        x = 10  # variable in the enclosing namespace
        
        def inner():
            nonlocal x
            x = 20  # modifies the enclosing 'x'
        
        inner()
        print(x)  # Output: 20
    
    outer()

How Python Uses Namespaces:

  • Function Calls: When a function is called, a new local namespace is created, and any local variables inside that function are stored there.
  • Global Scope: Variables declared outside any function or class are stored in the global namespace. The global namespace is accessible throughout the program unless shadowed by a local or enclosing namespace.
  • Built-in Scope: Python comes with many built-in objects, such as exceptions, functions, and types, which are available across the program through the built-in namespace.

Namespaces and Memory Management:

Namespaces help Python manage memory more efficiently. When variables go out of scope, they are removed from their respective namespaces, making the memory available for reuse. For example, local variables in a function are deleted when the function ends.


Conclusion:

Namespaces in Python help organize the various identifiers (variables, functions, etc.) by ensuring that each one is uniquely associated with a specific scope. This organization allows Python to resolve names efficiently and avoid conflicts. Understanding namespaces and the LEGB rule is crucial for managing variable scope and properly accessing and modifying variables in different parts of a program.

Read More

If you can’t get enough from this article, Aihirely has plenty more related information, such as Python interview questions, Python interview experiences, and details about various Python job positions. Click here to check it out.

Related Posts

Trace Job opportunities

Hirely, your exclusive interview companion, empowers your competence and facilitates your interviews.

Get Started Now