Python Interview Questions

1. How does Python manage memory?

Python manages memory through a combination of mechanisms that include automatic memory allocation, garbage collection, and memory pools:

  1. Dynamic Memory Management: Python dynamically allocates memory for objects when they are created. The memory for objects is allocated from a private heap, which Python itself manages.

  2. Garbage Collection: Python employs an automatic garbage collection system to reclaim memory occupied by objects that are no longer in use. This includes reference counting and a cyclic garbage collector to deal with reference cycles.

  3. Reference Counting: Every object in Python maintains a reference count that tracks how many references point to it. When an object's reference count drops to zero, the memory associated with it is immediately deallocated.

  4. Memory Pools: For efficiency, Python uses memory pools to allocate memory for small objects. These pools reduce the overhead of frequent memory allocation and deallocation.

  5. PyObject Allocation: Python manages memory for its objects through a structure called PyObject, which includes metadata like reference counts and type information. This design ensures efficient memory handling specific to Python objects.

  6. Custom Allocators: The memory allocation for objects in Python is fine-tuned with custom allocators like PyMalloc, which optimizes memory usage for small, frequently used objects.

  7. Virtual Machine Role: The Python interpreter (CPython) coordinates memory management tasks, ensuring that memory allocation and deallocation occur seamlessly during runtime.

2. What does "scope" mean in Python?

In Python, "scope" refers to the region in a program where a particular variable or identifier can be accessed. It determines the visibility and lifecycle of variables within the code. Scopes in Python are structured hierarchically, commonly categorized under the LEGB rule:

  1. Dynamic Memory Management: Python dynamically allocates memory for objects when they are created. The memory for objects is allocated from a private heap, which Python itself manages.

  2. Garbage Collection: Python employs an automatic garbage collection system to reclaim memory occupied by objects that are no longer in use. This includes reference counting and a cyclic garbage collector to deal with reference cycles.

  3. Reference Counting: Every object in Python maintains a reference count that tracks how many references point to it. When an object's reference count drops to zero, the memory associated with it is immediately deallocated.

  4. Memory Pools: For efficiency, Python uses memory pools to allocate memory for small objects. These pools reduce the overhead of frequent memory allocation and deallocation.

  5. PyObject Allocation: Python manages memory for its objects through a structure called PyObject, which includes metadata like reference counts and type information. This design ensures efficient memory handling specific to Python objects.

  6. Custom Allocators: The memory allocation for objects in Python is fine-tuned with custom allocators like PyMalloc, which optimizes memory usage for small, frequently used objects.

  7. Virtual Machine Role: The Python interpreter (CPython) coordinates memory management tasks, ensuring that memory allocation and deallocation occur seamlessly during runtime.

3. How would you define a Pandas DataFrame?

A Pandas DataFrame is a two-dimensional, tabular data structure in Python that organizes data in rows and columns, similar to a spreadsheet or SQL table. Each column can hold data of a specific type, and it is labeled, allowing for easy indexing and manipulation. This structure is widely used for data analysis and manipulation due to its flexibility and support for various operations, such as filtering, aggregating, and reshaping data.

4. Can you explain inheritance in Python with an example?

Inheritance in Python is a feature of object-oriented programming that allows a class (called the child class or subclass) to inherit attributes and methods from another class (called the parent class or superclass). This promotes code reuse and the creation of hierarchical relationships between classes. The child class can also add new attributes and methods or override existing ones from the parent class.

# Parent class
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return f"{self.name} makes a sound."

# Child class
class Dog(Animal):
    def speak(self):
        return f"{self.name} barks."

# Child class
class Cat(Animal):
    def speak(self):
        return f"{self.name} meows."

# Using the classes
dog = Dog("Buddy")
cat = Cat("Whiskers")

print(dog.speak())  # Output: Buddy barks.
print(cat.speak())  # Output: Whiskers meows.

In this example, the Dog and Cat classes inherit the Animal class's attributes and methods but provide their own implementation of the speak method, demonstrating method overriding.

5. How can you make a Python script executable on Unix systems?

To make a Python script executable on a Unix-based system, you need to:

  1. Add a shebang line (#!/usr/bin/env python3) at the top of the script to specify the interpreter.
  2. Modify the file's permissions to make it executable by running: chmod + x script_name.py.
  3. Run the script directly using ./script_name.py.

6. What is the difference between deep and shallow copies?

A shallow copy duplicates the structure of an object but keeps references to the original objects' elements, while a deep copy creates a completely independent clone, duplicating all nested objects.

7. How can you delete indices, rows, and columns in a DataFrame?

In a DataFrame, you can use the drop() method:

  • To remove rows: df.drop(index, axis=0)
  • To remove columns: df.drop(columns, axis=1)
  • Ensure to use inplace=True to modify the DataFrame directly or reassign the result.

8. Are arguments in Python passed by value or reference?

Python uses "pass-by-object-reference," meaning arguments are passed as references to objects. Mutable objects can be altered within functions, while immutable objects cannot.

9. How can you reverse a NumPy array in a single line of code?

You can reverse a NumPy array using slicing:

reversed_array = array[::-1]

10. Write a program to match a string containing an 'a' followed by 4 to 8 'b's.

import re
pattern = r'a(b{4,8})'
string = "abbbbbbb"
if re.fullmatch(pattern, string):
    print("Match found!")
else:
    print("No match.")

11. How do you define a class in Python?

Classes in Python are defined using the class keyword, followed by the class name and a colon. For example:

class MyClass:
    def __init__(self, value):
        self.value = value
    def display(self):
        print(self.value)

12. What are negative indexes in Python, and why are they useful?

Negative files in Python are a way to get to components from the conclusion of a arrangement, such as a list, string, or tuple. Instep of checking from the starting with positive lists (beginning at 0), negative files number in reverse from the final component, with -1 alluding to the final thing, -2 to the second-to-last, and so on.

This highlight is especially valuable when you require to work with components at the conclusion of a grouping without knowing its correct length. It kills the require for manual calculations like len(sequence) - n and permits for brief and clear code when managing with trailing components. For case, getting to the final character of a string or the final thing in a list is clear utilizing negative ordering.

13. How would you find the nearest value in a NumPy array?

You can find the closest value using:

nearest_value = array[np.abs(array - target_value).argmin()]

14. What are iterators, and how do they work in Python?

Iterators are objects that empower successive traversal through a collection. They execute the __iter__() and __following__() strategies. The following() work recovers the another thing, raising StopIteration when the grouping closes.

15. What does PEP 8, and why is it important?

PEP 8 is the official style guide for writing Python code, outlining conventions for formatting, structure, and naming to ensure readability and consistency. It helps developers maintain a standardized coding style, making code easier to read, understand, and collaborate on within teams or open-source projects. Following PEP 8 minimizes errors, improves maintainability, and fosters a professional coding approach.

16. How do new and override modifiers differ?

In object-oriented programming:

  • new explicitly hides a base class method, allowing a derived class to define its own implementation.
  • override provides a new definition for an inherited method while maintaining polymorphic behavior.

17. Write a program to solve a given equation with constants a, b, c, m, n, o.

from sympy import symbols, Eq, solve
a, b, c, m, n, o, x = symbols('a b c m n o x')
equation = Eq(a*x**2 + b*x + c, m*n + o)
solution = solve(equation, x)
print(solution)

18. How can you identify and handle missing values in a DataFrame?

You can identify missing values using df.isnull() or df.isna(). Handle them by:

  • Filling: df.fillna(value)
  • Dropping: df.dropna()

19. What is slicing in Python, and how is it used?

Slicing is extricating a subset of components from arrangements like records, strings, or tuples. Language structure: sequence[start:end:step]. For example:

subset = my_list[1:5:2]

20. What are the ways to generate random numbers in Python?

Random numbers can be generated using:

  • The random module: random.randint(), random.random()
  • The numpy module: numpy.random.randint(), numpy.random.rand()
  • The secrets module for cryptographic randomness.