Python Tricky Questions

Exploring Python


Python is known for its simplicity and readability, but beneath its clean syntax lie some subtle behaviors that can trip up even seasoned developers. In this post, I’ll walk you through a few tricky Python interview questions I’ve encountered—both as a candidate and an interviewer. These questions test not just syntax knowledge, but a deep understanding of how Python works under the hood.


๐Ÿ” Question 1: The Mutable Default Argument Trap

def func(a, L=[]):
    L.append(a)
    return L

print(func(1))
print(func(2))
print(func(3))

❓What’s the Output?

[1]
[1, 2]
[1, 2, 3]

๐Ÿ’กWhy?

In Python, default arguments are evaluated once at function definition time. So the list L is shared across all calls to func unless explicitly overridden. This is a common pitfall.

✅How to Fix It

def func(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

๐Ÿšซ Question 2: Preventing Subclassing in Python

Sometimes, you want to create a class that cannot be subclassed—a "final" class.

✅Solution Using Metaclasses

class NoSubclassingMeta(type):
    def __init_subclass__(cls, *args, **kwargs):
        raise TypeError(f"Subclassing of class {cls.__name__} is not allowed")

class FinalClass(metaclass=NoSubclassingMeta):
    pass

class SubClass(FinalClass):  # ❌ Raises TypeError
    pass

This technique leverages the __init_subclass__ hook, which is called whenever a class is subclassed. By raising an error here, you effectively make the class "final."


๐Ÿงฌ Question 3: Class vs Instance Variables and Method Resolution

class A:
    x = 5
    def __init__(self):
        self.x = 10
    def foo(self):
        print("A.foo:", self.x)

class B(A):
    x = 15
    def __init__(self):
        super().__init__()
        self.x = 20
    def foo(self):
        print("B.foo:", self.x)
        super().foo()

class C(B):
    x = 25
    def __init__(self):
        super().__init__()
        self.x = 30
    def foo(self):
        print("C.foo:", self.x)
        super().foo()

obj = C()
obj.foo()
print(obj.x)
print(C.x)
print(B.x)
print(A.x)

๐ŸงพOutput:

C.foo: 30
B.foo: 30
A.foo: 30
30
25
15
5

๐Ÿง Explanation:

  • self.x refers to the instance variable, which is set to 30 in C.__init__.
  • C.x, B.x, and A.x refer to class variables.
  • Method resolution follows the MRO (Method Resolution Order), and super() calls the next method in the hierarchy.

Comments

Popular posts from this blog

Travel to Nainital, Haridwar and Rishikesh

Solo_Nainital _from_Mumbai