Python Full-Stack Interview Questions 16–20 (Metaclasses, Methods, Exceptions, Descriptors, Slots)
This lesson walks through five intermediate-to-advanced Python topics you will often see in interviews. Each explanation uses plain language, relatable analogies, and code examples to build confidence and clarity. Read slowly, try the examples, and use the checklists to craft short interview answers.
16. What are Python metaclasses?
A metaclass is the “class of a class.” If a class is an object you use to make instances, a metaclass is the object you use to make classes. Think of it as the factory that builds classes — it controls how classes are constructed and can modify attributes, add methods, or enforce rules at the moment classes are defined.
- Real-world analogy: A metaclass is like a building code applied to a contractor who builds houses (classes). The contractor must follow the code when constructing each house.
- Typical use cases: adding logging to class creation, registering subclasses automatically, enforcing patterns (e.g., singleton), or injecting methods/attributes.
Simple example — create a metaclass that adds a timestamp attribute to every class it builds:
from datetime import datetime
class TimestampMeta(type):
def __new__(mcls, name, bases, namespace):
namespace['created_at'] = datetime.now()
return super().__new__(mcls, name, bases, namespace)
class MyClass(metaclass=TimestampMeta):
pass
print(MyClass.created_at) # set when the class was defined Interview tip: Keep the definition short — “Metaclasses are classes that create classes; use them when you need to customize class creation or register/enforce behavior across many classes.” Mention that they are powerful but often unnecessary — prefer simpler patterns (decorators or class factories) unless you need metaclass-level control.
17. Difference between @staticmethod, @classmethod, and instance methods.
These are three ways to define functions inside a class. The difference is how they receive context:
- Instance methods: regular methods that receive the instance as the first argument (conventionally named
self). They operate on instance data. - Class methods: marked with
@classmethodand receive the class as the first argument (conventionally namedcls). They operate on class-level state or are alternate constructors. - Static methods: marked with
@staticmethodand receive no implicit first argument. They are namespaced functions placed inside the class because they belong conceptually to the class.
Example showing all three:
class Circle:
pi = 3.14159
def __init__(self, radius):
self.radius = radius
def area(self): # instance method
return Circle.pi * self.radius * self.radius
@classmethod
def from_diameter(cls, diameter): # class method (alternate constructor)
return cls(diameter / 2)
@staticmethod
def validate_radius(r): # static method (utility)
return r >= 0
c = Circle.from_diameter(10)
print(c.area())
print(Circle.validate_radius(3)) Quick interview line: “Instance methods use instance data; class methods receive the class — useful for alternate constructors or class-wide operations; static methods are simple helpers grouped into the class namespace.”
18. Explain Python exception hierarchy.
Python organizes exceptions into a hierarchy rooted at BaseException. Most user-defined and built-in exceptions subclass Exception, which is itself a subclass of BaseException. Some special exceptions (like SystemExit, KeyboardInterrupt) inherit directly from BaseException because they signal interpreter-level events.
- Common nodes:
BaseException➜ top-levelException➜ typical user exceptions- Specialized built-ins:
ValueError,TypeError,KeyError,IndexError,RuntimeError, etc.
- Best practice: catch specific exceptions rather than a bare
except:. Useexcept Exception:only when you truly want to catch most application errors, and avoid catchingBaseException.
Example: choosing which exception to raise and catch:
def parse_int(s):
try:
return int(s)
except ValueError:
raise ValueError("input must be integer-like")
try:
parse_int("x")
except ValueError as e:
print("Caught:", e)
Interview tip: Explain hierarchy briefly and show that you understand why KeyboardInterrupt and SystemExit are special (they shouldn’t be swallowed by normal exception handling).
19. What are Python descriptors?
A descriptor is any object that defines one or more of the methods __get__, __set__, or __delete__. Descriptors are used to manage attribute access on other objects. Common examples include properties and functions (methods are descriptors), but you can write custom descriptors to centralize logic for validation, lazy loading, caching, or access control.
- Types:
- Data descriptors define
__set__(and optionally__get__) — they take precedence over instance attributes. - Non-data descriptors define only
__get__— methods are an example.
- Data descriptors define
- Use cases: attribute validation, computed attributes, type enforcement, or implementing cached properties.
Example descriptor that enforces a minimum value:
class MinValue:
"""
Descriptor that enforces a minimum value for an attribute.
"""
def __init__(self, name, min_value):
self.name = name
self.min_value = min_value
def __get__(self, instance, owner):
# When accessed through the class, return the descriptor itself
if instance is None:
return self
# Otherwise, return the value stored in the instance's dictionary
return instance.__dict__.get(self.name)
def __set__(self, instance, value):
# Enforce the minimum constraint
if value < self.min_value:
raise ValueError(f"{self.name} must be >= {self.min_value}")
# Store the value
instance.__dict__[self.name] = value
class Account:
# balance attribute must always be >= 0
balance = MinValue('balance', 0)
def __init__(self, balance):
# This will trigger validation via the descriptor's __set__
self.balance = balance
a = Account(10)
try:
a.balance = -5 # This should fail
except ValueError as e:
print("Validation caught:", e)
Interview tip: Describe descriptors succinctly — “objects with __get__/__set__ methods that control attribute access; they’re the mechanism behind property, methods, and more advanced patterns.”
20. What are Python __slots__ and their benefits?
__slots__ is a class-level declaration that tells Python to allocate space for a fixed set of attributes and to avoid the per-instance dictionary (__dict__). By using __slots__, instances become more memory-efficient and attribute access can be slightly faster. The trade-off is reduced dynamism: you cannot add arbitrary new attributes to instances (unless a class also defines __dict__ in __slots__).
- Benefits:
- Lower memory usage for many instances.
- Potentially faster attribute access and reduced GC pressure.
- Drawbacks:
- Less flexible — can't add attributes not declared in
__slots__. - Some features (multiple inheritance, descriptors) require care.
- Less flexible — can't add attributes not declared in
Example using __slots__:
class Point:
# __slots__ restricts which attributes can be assigned to instances
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
print(p.x, p.y) # prints: 1 2
try:
p.z = 3 # This will fail because 'z' is not in __slots__
except AttributeError as e:
print("Cannot add new attribute:", e)
Interview tip: Mention memory-savings and a common use-case — many small objects (e.g., nodes, data rows) where attribute sets are fixed. Also note that Python classes without __slots__ allow dynamic attributes through __dict__, which is more flexible for rapid development.
Final checklist — how to answer concisely in an interview
- Metaclasses: “Class that creates classes — used for class-level customization and registration.”
- Methods: “Instance (self) for object state, classmethod (cls) for class-level behavior/alternate constructors, staticmethod for utility functions inside class namespace.”
- Exceptions: “Hierarchy rooted at BaseException; catch specific exceptions; don’t swallow system-level signals.”
- Descriptors: “Objects implementing __get__/__set__/__delete__ to control attribute access — used for validation, caching, properties.”
- __slots__: “Declares fixed attributes to save memory and limit dynamic attributes; useful for many small fixed-shape objects.”
Closing note: Practice explaining these topics out loud in 30–60 seconds each. When asked for code, aim for a short, correct snippet like the ones above. Keep answers practical — mention why you would (and would not) use each feature in real projects.