Most Asked Python Interview Questions — Part-1 (Classes)

Zilay
6 min readJul 19, 2023

--

Photo by Tim Swaan on Unsplash

Parts

  1. Most Asked Python Interview Questions — Part-1 (Classes)
  2. Most Asked Python Interview Questions — Part-2 (Exception Handling)

If you’re preparing for a Python interview, it’s essential to have a solid understanding of the language’s fundamental concepts. To help you with that, I have categorized this interview question series into different parts, each focusing on a specific area. today we will dive into classes in Python and explore some frequently asked interview questions related to this topic.
In this part, we will discuss

  • Name Mangling
  • Class Variables
  • MRO

Name mangling

Name mangling is a technique used to change the name of a class variable to avoid naming conflicts between parent and child classes.

In Python, when a variable is prefixed with double underscores (e.g., __variable), the interpreter automatically changes its name to include the class name. This modification helps prevent accidental overriding of variables in inherited classes.
Such variables are also treated as a private member of a class.

Exercise-1

What will be the output of the following code?

class MyClass:
def __init__(self):
self.__variable = 42
obj = MyClass()
print(obj.__variable)

Expected Output:

AttributeError: 'MyClass' object has no attribute '__variable'

You maybe wondering why it is raising an error?
BECAUSE! Name mangling changes the name of the variable __variable to _MyClass__variable. Therefore, attempting to access __variable directly raises an AttributeError. To access the variable, you need to use the modified name _MyClass__variable. Here’s an example that demonstrates how to access a name-mangled variable:

class MyClass:
def __init__(self):
self.__variable = 42
obj = MyClass()
print(obj._MyClass__variable)

Exercise-2

class A:
def __init__(self):
self.__variable = 42
    def display(self):
print(self.__variable)
class B(A):
def __init__(self):
super().__init__()
self.__variable = 99
obj = B()
obj.display()

Expected Output:

42

You may guessed that it will print 99 but in actual, it will print 42 and it is because of name mangling.
During name mangling, the interpreter renames the variable by adding _classname as a prefix to the variable name.
In this case,
in Class A, __variable is modified to _A__variable. Similarly,
in Class B, __variable is modified to _B__variable.
Since the display method is defined in Class A, when it accesses self.__variable, it is actually accessing self._A__variable.

Bonus Question: Will it work if we remove super().__init__() from class B?

Class Variables

A class variable in Python is a variable that is shared among all instances (objects) of a class. Class variables are associated with the class itself rather than with any specific instance of the class.

Exercise-1

class A:
count = 0
    def __init__(self):
A.count += 1
@classmethod
def get_count(cls):
return cls.count
obj_one = A()
obj_two = A()
print(obj_one.get_count())
print(obj_two.get_count())

Expected Output:

2
2

Becausecount is class variable so the increment on count will impact all the instances of class A

Exercise-2

class A:
count = 0
    def __init__(self):
self.count += 1
@classmethod
def get_count(cls):
return cls.count
obj_one = A()
obj_two = A()
print(obj_one.get_count())
print(obj_two.get_count())

Expected Output:

0
0

The reason why it is returning 0 for both obj_one.get_count() and obj_two.get_count() is because of the self keyword inside__init__ method.
In the __init__ method, self.count += 1 is attempting to increment the count variable for each instance. However, since count is a class variable (declared directly within the class), it is not specific to any instance and is shared by all instances of the class. Therefore, when you create obj_one and obj_two, both of them share the same count variable, and the value of count remains 0.

Exercise-3

class A:
count = 0
    def __init__(self):
A.count += 1
@classmethod
def get_count(cls):
return cls.count
class B(A):
pass
def __init__(self):
B.count += 1
a = A()
b = B()
print(a.get_count())
print(b.get_count())

Expected Output:

1
2

Ever wonder why it is not returning 2 2for both instances?
The reason why it is returning 1 for a.get_count() and 2 for b.get_count() is due to the way the __init__ method is defined in class B.

In the class A, the __init__ method increments the count variable using A.count += 1, which increments the class variable count every time a new instance of class A is created. Therefore, when you create the instance a, it increments the count to 1.

In class B, we have not defined the count variable explicitly, so it inherits the count variable from class A. However, the __init__ method in class B tries to increment B.count, which is not a class variable. Instead, it creates a new instance variable specific to class B, leaving the class variable count of class A unaffected.

MRO (Method Resolution order)

MRO, a most favorite topic of all interviewers. MRO refers to the order in which classes are searched for a requested method or attributein the presence of multiple inheritance.
Python uses the C3 linearization Algorithmto determine the MRO. The MRO is important because it defines the order in which the methods of different classes are invoked when using inheritance. It ensures that the methods are resolved in a consistent and predictable manner.
Just memorize that the MRO follows a depth-first left-to-right traversal.

Exercise-1

class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
print(D.mro())

Expected Output:

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

As I told you earlier, MRO perform depth-first left-to-right.
In this case, the MRO is: D -> B -> C -> A -> object.
This order ensures that when a method or attribute is called on an instance of class D, Python will first search in class D, then in class B, followed by class C, then class A, and finally in the built-in object class.

Exercise-2:

class A:
def greet(self):
return "Hello from A"
class B(A):
pass
class C(A):
def greet(self):
return "Hello from C"
class D(B, C):
pass
d = D()print(d.greet())

Expected Output:

Hello from C

Class D inherits from both classes B and C, and both B and C inherit from class A.
And the MRO is D -> B -> C -> A -> object. Python first checks if greet() exists in class D, then in class B, but finds it in class C. As a result, the output of d.greet() is "Hello from C", as the greet() method from class C takes precedence in the MRO over the method in class A.

Exercise-3

class A:
def greet(self):
return "Hello from A"
class B:
def greet(self):
return "Hello from B"
class C(A, B):
pass
class D(C, B):
pass
d = D()
print(d.greet())

Expected Output:

Hello from A

If we print the MRO, it will be

[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

As you can see, it is D -> C -> A -> B -> object.
Python first checks if greet() exists in class D, then in class C, and eventually finds it in class A. Thus, the output of d.greet() is "Hello from A", as the greet() method from class A takes precedence in the MRO over the method in class B.

Final words

I hope these three concepts i.e Name mangling ,Class Variables and MRO helps you out either to prepare for the interview or to refresh your concepts. See ya till next part. HAPPY CODING!
Don’t forget to connect on LinkedIn

--

--