Python's popularity in software development, data science, and web applications makes it a staple in technical interviews. However, beyond basic syntax and data structures, interviewers often probe deeper into Python's internals, concurrency, and advanced features to gauge a candidate's expertise.
This article explores 10 of the hardest Python interview questions, complete with explanations, sample code, and insights into why they trip up even seasoned developers. These questions test conceptual understanding, problem-solving, and the ability to navigate Python's quirks. Whether you're preparing for a FAANG interview or a senior role, mastering these will set you apart.
1. Explain Metaclasses and How They Work in Python
Metaclasses are often called "classes of classes" because they define the behavior of classes themselves. In Python, everything is an object, including classes, which are instances of metaclasses. The default metaclass is type, but you can create custom ones by inheriting from type and overriding methods like __new__ or __init__.
class Meta(type):
def __new__(cls, name, bases, dct):
dct['added_attr'] = 42
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=Meta):
pass
print(MyClass.added_attr) # Output: 42
This pattern is used in frameworks like Django, where metaclasses enforce model field definitions and validations.
2. What Are Descriptors and How Do They Implement Properties?
Descriptors are objects that define one or more of the methods __get__, __set__, or __delete__. They allow custom attribute access and are the mechanism behind @property, @classmethod, and @staticmethod.
class Descriptor:
def __get__(self, instance, owner):
return instance._value if instance else "Class access"
def __set__(self, instance, value):
instance._value = value
class MyClass:
attr = Descriptor()
obj = MyClass()
obj.attr = 10
print(obj.attr) # 10
print(MyClass.attr) # "Class access"
3. Generators vs Iterators
Iterators implement __iter__ and __next__ manually. Generators are a special type of iterator created using yield, which automatically handles state.
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
for num in fibonacci(5):
print(num)
4. Python Garbage Collection and Reference Cycles
Python primarily uses reference counting, supplemented by a generational garbage collector to detect reference cycles.
weakref.
import gc
class Node:
def __init__(self):
self.ref = None
a = Node()
b = Node()
a.ref = b
b.ref = a
del a, b
gc.collect()
5. The Global Interpreter Lock (GIL)
The GIL ensures that only one thread executes Python bytecode at a time in CPython. This simplifies memory management but limits CPU-bound multithreading.
6. Closures and Variable Scope
Closures occur when an inner function captures variables from its enclosing scope, even after the outer function has returned.
def outer(x):
def inner(y):
return x + y
return inner
closure = outer(10)
print(closure(5)) # 15
7. Decorators with Arguments
Decorators that accept arguments are actually decorator factories—functions that return decorators.
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}")
greet("World")
8. Monkey Patching
Monkey patching dynamically modifies modules or classes at runtime.
import math
def new_sin(x):
return math.cos(x)
math.sin = new_sin
print(math.sin(0)) # 1.0
9. Asyncio and Coroutines
asyncio enables asynchronous programming using an event loop and coroutines defined with async def.
import asyncio
async def fetch_data():
await asyncio.sleep(1)
return "Data"
async def main():
data = await fetch_data()
print(data)
asyncio.run(main())
10. Functional Programming: map, filter, reduce
Python supports functional patterns through map, filter, and reduce, often combined with lambdas.
from functools import reduce
nums = [1, 2, 3, 4]
evens = filter(lambda x: x % 2 == 0, nums)
squared = map(lambda x: x**2, evens)
product = reduce(lambda x, y: x * y, squared)
print(product) # 64
Conclusion
These questions highlight Python's depth beyond surface-level coding. To prepare, practice with real projects: build decorators for logging, use asyncio in web scrapers, or explore the CPython source code.
Resources like Fluent Python by Luciano Ramalho and the official Python documentation are invaluable. Interviews test not just knowledge, but the ability to explain trade-offs clearly. With consistent practice, these “hard” questions become strengths.
(Word count: 912)


