---
tags:
- devops
- l2
- flashcard-deck
- python-oop
---
<!-- wiki:breadcrumb:start -->
[Portal](../../../../library/portal/index.md) | **Level:** [L2: Operations](../../../../library/portal/levels.md) | **Topics:** [Python Automation](../../../../library/portal/topics.md) | **Domain:** DevOps & Tooling
<!-- wiki:breadcrumb:end -->

id	category	difficulty	tags	question	answer	source_path
python-oop/2b0107af8c3d	python-oop	hard	python, oop, metaclasses	What are metaclasses and when would you use them?	A metaclass is the class of a class — it controls how classes themselves are created. The default metaclass is `type`.\n\nclass Meta(type):\n    def __new__(mcs, name, bases, namespace):\n        # modify class before creation\n        namespace['created_by'] = 'Meta'\n        return super().__new__(mcs, name, bases, namespace)\n\nclass MyClass(metaclass=Meta):\n    pass\n\nprint(MyClass.created_by)  # 'Meta'\n\nUse cases: ORMs (Django models), API registration, enforcing interfaces. In practice, __init_subclass__ or class decorators cover most use cases more simply.	interview-qa-gap-analysis
python-oop/8645045c9bb7	python-oop	hard	python, oop, design-patterns, singleton	Implement the Singleton pattern in Python (three ways)	1. Module-level instance (Pythonic):\n_instance = MyClass()\n\n2. __new__ override:\nclass Singleton:\n    _instance = None\n    def __new__(cls):\n        if cls._instance is None:\n            cls._instance = super().__new__(cls)\n        return cls._instance\n\n3. Metaclass:\nclass SingletonMeta(type):\n    _instances = {}\n    def __call__(cls, *args, **kw):\n        if cls not in cls._instances:\n            cls._instances[cls] = super().__call__(*args, **kw)\n        return cls._instances[cls]\n\nThe module-level approach is simplest and most Pythonic. Use __new__ for classes that need lazy initialization.	interview-qa-gap-analysis
python-oop/c97e9afa1f95	python-oop	medium	python, oop, functional, currying	What is currying in Python?	Currying transforms a function with multiple arguments into a sequence of functions each taking one argument.\n\nfrom functools import partial\n\ndef multiply(x, y):\n    return x * y\n\ndouble = partial(multiply, 2)\nprint(double(5))  # 10\n\n# Manual currying:\ndef curry_multiply(x):\n    def inner(y):\n        return x * y\n    return inner\n\ntriple = curry_multiply(3)\nprint(triple(5))  # 15\n\nfunctools.partial is the standard way to do partial application in Python. True currying (auto-currying) isn't built-in but libraries like toolz provide it.	interview-qa-gap-analysis
python-oop/68ca466362f6	python-oop	hard	python, oop, mro, inheritance	Explain Python's Method Resolution Order (MRO)	MRO determines the order in which base classes are searched when calling a method. Python uses the C3 linearization algorithm.\n\nclass A: pass\nclass B(A): pass\nclass C(A): pass\nclass D(B, C): pass\n\nprint(D.__mro__)  # (D, B, C, A, object)\n\nRules: (1) children before parents, (2) left-to-right order preserved, (3) each class appears once. Use ClassName.mro() or ClassName.__mro__ to inspect. super() follows the MRO, not just the immediate parent — critical for cooperative multiple inheritance.	interview-qa-gap-analysis
python-oop/456161a3d461	python-oop	medium	python, oop, performance, slots	What is __slots__ and when should you use it?	__slots__ restricts instance attributes to a fixed set, replacing the per-instance __dict__ with a more memory-efficient structure.\n\nclass Point:\n    __slots__ = ('x', 'y')\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n\np = Point(1, 2)\np.z = 3  # AttributeError!\n\nBenefits: ~40% less memory per instance, slightly faster attribute access. Use when creating millions of instances. Drawbacks: no dynamic attributes, complications with multiple inheritance, no __dict__ for introspection. Not needed for most classes.	interview-qa-gap-analysis
python-oop/6a0485f1987b	python-oop	hard	python, oop, descriptors, protocols	What are descriptors in Python?	A descriptor is any object that defines __get__, __set__, or __delete__. They control attribute access on classes.\n\nclass Validator:\n    def __set_name__(self, owner, name):\n        self.name = name\n    def __get__(self, obj, objtype=None):\n        return obj.__dict__.get(self.name)\n    def __set__(self, obj, value):\n        if not isinstance(value, int):\n            raise TypeError(f'{self.name} must be int')\n        obj.__dict__[self.name] = value\n\nclass Order:\n    quantity = Validator()\n\nProperty, classmethod, staticmethod are all implemented as descriptors. Data descriptors (with __set__) take priority over instance __dict__; non-data descriptors don't.	interview-qa-gap-analysis
python-oop/ef86a0f80a4f	python-oop	medium	python, oop, abc, abstract	What is the ABC module and how do you use abstract classes?	The abc module provides Abstract Base Classes — classes that can't be instantiated and enforce method implementation in subclasses.\n\nfrom abc import ABC, abstractmethod\n\nclass Shape(ABC):\n    @abstractmethod\n    def area(self) -> float:\n        ...\n\n    @abstractmethod\n    def perimeter(self) -> float:\n        ...\n\nclass Circle(Shape):\n    def __init__(self, r):\n        self.r = r\n    def area(self):\n        return 3.14159 * self.r ** 2\n    def perimeter(self):\n        return 2 * 3.14159 * self.r\n\nShape()  # TypeError: Can't instantiate abstract class\nCircle(5).area()  # 78.5\n\nUse ABCs to define interfaces and ensure subclasses implement required methods. Also supports @abstractproperty (deprecated — use @property + @abstractmethod).	interview-qa-gap-analysis
python-oop/50ac0061c201	python-oop	medium	python, oop, dataclasses, namedtuple	Dataclasses vs namedtuples — when to use which?	Both reduce boilerplate for data-holding classes but differ in mutability and features.\n\nfrom dataclasses import dataclass\nfrom typing import NamedTuple\n\n@dataclass\nclass PointDC:\n    x: float\n    y: float\n\nclass PointNT(NamedTuple):\n    x: float\n    y: float\n\nNamedTuple: immutable, hashable, tuple-compatible, lighter memory. Use for simple records, dict keys, function returns.\n\nDataclass: mutable by default (frozen=True for immutable), supports default_factory, __post_init__, inheritance, field metadata. Use for domain objects needing methods or validation.\n\nRule of thumb: NamedTuple for simple data, dataclass for everything else.	interview-qa-gap-analysis
python-oop/2e8dd56c78fe	python-oop	medium	python, oop, encapsulation, name-mangling	Explain name mangling with double underscores	Python mangles attributes starting with __ (double underscore) by prepending _ClassName to prevent accidental override in subclasses.\n\nclass Parent:\n    def __init__(self):\n        self.__secret = 42\n\nclass Child(Parent):\n    def __init__(self):\n        super().__init__()\n        self.__secret = 99  # different attribute!\n\nc = Child()\nprint(c._Parent__secret)  # 42\nprint(c._Child__secret)   # 99\n\nThis is NOT access control — it's name collision avoidance. Single underscore (_name) is the convention for 'private'. Use __ only when you need to prevent subclass attribute clashes.	interview-qa-gap-analysis
python-oop/5b46a384b579	python-oop	hard	python, oop, metaclasses, init-subclass	What is __init_subclass__ and how does it replace metaclasses?	__init_subclass__ is a hook called when a class is subclassed, added in Python 3.6. It covers many metaclass use cases more simply.\n\nclass Plugin:\n    registry = {}\n    def __init_subclass__(cls, name=None, **kwargs):\n        super().__init_subclass__(**kwargs)\n        Plugin.registry[name or cls.__name__] = cls\n\nclass PDF(Plugin, name='pdf'):\n    pass\n\nclass CSV(Plugin, name='csv'):\n    pass\n\nprint(Plugin.registry)  # {'pdf': PDF, 'csv': CSV}\n\nThis auto-registers subclasses without metaclasses. Use for plugin systems, validation on subclass creation, or enforcing class-level constraints. Simpler to understand and compose than metaclasses.	interview-qa-gap-analysis
python-oop/e6cf7e2faa98	python-oop	medium	python, oop, super, inheritance	How does super() work in Python 3?	super() returns a proxy object that delegates method calls to the next class in the MRO.\n\nclass A:\n    def greet(self):\n        return 'A'\n\nclass B(A):\n    def greet(self):\n        return 'B->' + super().greet()\n\nclass C(A):\n    def greet(self):\n        return 'C->' + super().greet()\n\nclass D(B, C):\n    def greet(self):\n        return 'D->' + super().greet()\n\nD().greet()  # 'D->B->C->A'\n\nPython 3 super() needs no args (uses __class__ cell). It follows MRO, not parent — crucial for cooperative multiple inheritance. Always call super().__init__() in __init__ for MI to work correctly.	interview-qa-gap-analysis
python-oop/081437da9063	python-oop	easy	python, oop, classmethod, staticmethod	What are class methods and static methods?	@classmethod receives the class as first arg (cls), @staticmethod receives no implicit arg.\n\nclass Date:\n    def __init__(self, year, month, day):\n        self.year, self.month, self.day = year, month, day\n\n    @classmethod\n    def from_string(cls, s):\n        y, m, d = map(int, s.split('-'))\n        return cls(y, m, d)  # works with subclasses too\n\n    @staticmethod\n    def is_valid(s):\n        parts = s.split('-')\n        return len(parts) == 3\n\nDate.from_string('2026-04-01')  # creates Date instance\nDate.is_valid('2026-04-01')     # True\n\nUse classmethod for alternative constructors (factory methods). Use staticmethod for utility functions that don't need class/instance state but logically belong to the class.	interview-qa-gap-analysis
python-oop/72cc239bd880	python-oop	medium	python, oop, property, descriptors	Explain Python's property decorator	@property creates managed attributes with getter/setter/deleter methods.\n\nclass Temperature:\n    def __init__(self, celsius):\n        self._celsius = celsius\n\n    @property\n    def fahrenheit(self):\n        return self._celsius * 9/5 + 32\n\n    @fahrenheit.setter\n    def fahrenheit(self, value):\n        self._celsius = (value - 32) * 5/9\n\nt = Temperature(100)\nprint(t.fahrenheit)    # 212.0\nt.fahrenheit = 32\nprint(t._celsius)      # 0.0\n\nProperties are descriptors under the hood. Use them to add validation, computed attributes, or to migrate from public attributes to managed access without breaking the API.	interview-qa-gap-analysis
python-oop/ad06304f4e6f	python-oop	easy	python, oop, duck-typing, protocols	What is duck typing and how does Python use it?	'If it walks like a duck and quacks like a duck, it's a duck.' Python checks behavior (methods/attributes) rather than type.\n\ndef get_length(obj):\n    return len(obj)  # works with str, list, dict, any object with __len__\n\nget_length('hello')  # 5\nget_length([1,2,3])  # 3\n\nProtocol classes (Python 3.8+) formalize this:\nfrom typing import Protocol\n\nclass Sized(Protocol):\n    def __len__(self) -> int: ...\n\ndef f(x: Sized) -> int:\n    return len(x)\n\nDuck typing enables polymorphism without inheritance. The typing.Protocol class adds optional static checking while preserving runtime duck typing.	interview-qa-gap-analysis
python-oop/82faad897e9a	python-oop	easy	python, oop, dunder, string-representation	What is __repr__ vs __str__?	__repr__ is for developers (unambiguous), __str__ is for users (readable).\n\nclass Point:\n    def __init__(self, x, y):\n        self.x, self.y = x, y\n    def __repr__(self):\n        return f'Point({self.x}, {self.y})'  # eval-able if possible\n    def __str__(self):\n        return f'({self.x}, {self.y})'\n\np = Point(1, 2)\nrepr(p)  # 'Point(1, 2)'\nstr(p)   # '(1, 2)'\nprint(p) # calls __str__: (1, 2)\n\nIf only one is defined, implement __repr__ — str() falls back to __repr__, but not vice versa. f-strings and print() call __str__; the REPL and containers call __repr__.	interview-qa-gap-analysis

<!-- wiki:related:start -->
---

## Wiki Navigation

### Prerequisites

- Python Flashcards *(CLI)* (flashcard_deck, L1)

### Related Content

- Perl Flashcards *(CLI)* (flashcard_deck, L1) — Python Automation
- Python Algorithms Flashcards *(CLI)* (flashcard_deck, L2) — Python Automation
- [Python Async & Concurrency](../../../../library/topics/python-async-concurrency/index.md) (Topic Pack, L2) — Python Automation
- Python Concepts Flashcards *(CLI)* (flashcard_deck, L0) — Python Automation
- [Python Debugging](../../../../library/topics/python-debugging/index.md) (Topic Pack, L1) — Python Automation
- [Python Drills](../../../../library/drills/python_drills.md) (Drill, L0) — Python Automation
- Python Exercises (Quest Ladder) *(CLI)* (Exercise Set, L0) — Python Automation
- Python Flashcards *(CLI)* (flashcard_deck, L1) — Python Automation
- [Python Packaging](../../../../library/topics/python-packaging/index.md) (Topic Pack, L2) — Python Automation
- [Python for Infrastructure](../../../../library/topics/python-infra/index.md) (Topic Pack, L1) — Python Automation

<!-- wiki:related:end -->
