Python interviews span a wide range depending on the role: web development positions test Django/Flask knowledge, data science roles emphasize pandas and scikit-learn, and general software engineering positions focus on language fundamentals, data structures, and object-oriented design. This guide covers the core Python concepts that appear across virtually all Python interview contexts, with the depth of answer that interviewers are looking for.
Python Fundamentals Interviewers Love to Test
"What is the difference between a list and a tuple in Python?" Lists are mutable (can be modified after creation), while tuples are immutable (cannot be changed after creation). Lists use square brackets []; tuples use parentheses (). Beyond syntax, the choice carries semantic meaning: use a list when you have a collection of items that might change; use a tuple when the structure represents a fixed collection (like coordinates (x, y) or database record fields). Tuples are slightly more memory-efficient and hashable (can be dictionary keys or set members), while lists are not.
"Explain Python's mutable vs. immutable types." Immutable types cannot be changed after creation: integers, floats, strings, tuples, frozensets, and booleans. When you "change" a string, Python creates a new string object. Mutable types can be changed in place: lists, dictionaries, sets, and most custom objects. This distinction has important implications: passing a mutable object to a function allows the function to modify it (affecting the caller), while passing an immutable object cannot affect the original. It also explains why mutable objects cannot be dictionary keys โ their hash value could change if they were modified.
"What is a Python decorator and how do you write one?" A decorator is a function that takes another function as an argument, wraps it with additional behavior, and returns the wrapped function. They use Python's @syntax as syntactic sugar. A basic decorator: define an outer function taking the original function as argument, define an inner wrapper function that calls the original with *args and **kwargs and adds behavior before/after, return the wrapper. Decorators are used extensively: for timing function execution, caching results (@lru_cache), authentication checking in web frameworks (@login_required), and logging. The functools.wraps decorator should be applied to the wrapper to preserve the original function's name and docstring.
"What is the GIL (Global Interpreter Lock) and how does it affect Python?" The GIL is a mutex in CPython (the standard Python implementation) that allows only one thread to execute Python bytecode at a time. This means Python threads don't achieve true parallelism for CPU-bound tasks โ threading in Python is useful for I/O-bound work (where threads spend time waiting for network or disk operations) but doesn't improve performance for CPU-intensive tasks. For CPU-bound parallelism, use multiprocessing (separate processes, each with their own GIL) or Python's newer alternatives like asyncio for I/O concurrency, or use extensions like NumPy that release the GIL during computation.
Object-Oriented Python
"Explain the difference between __init__ and __new__ in Python classes." __new__ is responsible for creating a new instance of the class โ it allocates memory and returns the new object. __init__ receives the already-created instance and initializes it. In practice, you almost never override __new__ (only for metaclass work or creating singletons). You almost always override __init__ to set initial values for instance attributes. __new__ runs first and returns the instance that is then passed to __init__.
"What are @classmethod and @staticmethod decorators?" An instance method receives self (the instance) as the first argument and can access and modify instance and class state. A @classmethod receives cls (the class itself) as the first argument instead of an instance โ useful for alternative constructors and factory methods. A @staticmethod receives no implicit first argument โ it's a regular function that happens to live in the class namespace, used when the function logically belongs to the class but doesn't need access to class or instance data.
"What are Python's magic methods (dunder methods)?" Magic methods (double underscore before and after the name) allow custom objects to implement Python's built-in behaviors. __str__ defines the string representation (used by print()). __repr__ defines the developer representation (used in the REPL). __len__ enables len(obj). __getitem__ and __setitem__ enable indexing with []. __iter__ and __next__ enable iteration in for loops. __eq__, __lt__, __gt__ define comparison operators. __enter__ and __exit__ implement context manager protocol for with statements. Understanding magic methods is key to writing Pythonic code.
Common Python Patterns and Pitfalls
"What are list comprehensions and when should you use them?" List comprehensions provide a concise way to create lists: [expression for item in iterable if condition]. They're more readable and typically faster than equivalent for loops with append(). Use them for simple transformations and filtering. When the expression or condition becomes complex enough that the comprehension is hard to read in one line, a regular loop is better. Generator expressions (same syntax but with parentheses) produce items lazily โ useful for large datasets where you don't need all results in memory at once.
"Explain *args and **kwargs." *args collects any number of positional arguments into a tuple; **kwargs collects any number of keyword arguments into a dictionary. They allow functions to accept variable numbers of arguments โ essential for decorator wrappers, forwarding arguments, and creating flexible APIs. They can be combined with regular parameters: regular parameters must come before *args, which must come before **kwargs.
