Python Interview Questions & Answers (2026) – RankWeb3
RankWeb3β€Ί Interview Questionsβ€Ί Python
🐍 Python 3.x All Levels 30 Questions Updated 2026

Python Interview
Questions & Answers

πŸ“… Updated: March 2026
⏱️ Read time: ~20 min
🎯 30 questions β€” Beginner to Advanced
✍️ By RankWeb3 Team
30
Total Questions
10
Beginner
11
Intermediate
9
Advanced

🌱Beginner QuestionsQ1–Q10

1
What is Python and what makes it popular?
BeginnerVery Common
+

Python is a high-level, interpreted, general-purpose programming language created by Guido van Rossum in 1991. It emphasises code readability and simplicity β€” Python code often reads almost like plain English.

  • Readable syntax: Indentation-based structure forces clean, consistent code.
  • Versatile: Used in web development, data science, AI/ML, automation, scripting, and more.
  • Huge ecosystem: PyPI has over 400,000 packages β€” there's a library for almost everything.
  • Interpreted: No compilation step β€” run code directly, making development faster.
  • Cross-platform: Runs on Windows, macOS, and Linux without modification.
  • Strong community: One of the most popular languages in the world with vast documentation.
πŸ’‘Why interviewers ask this: To confirm genuine understanding, not just "I've used it." Mention specific use cases (web dev with Django/Flask, data science with pandas/NumPy, automation) to show breadth.
2
What are Python's built-in data types?
BeginnerVery Common
+

Python has several built-in data types grouped by category:

Python
# Numeric x = 42 # int y = 3.14 # float z = 2+3j # complex # Text s = "hello" # str # Sequence lst = [1, 2, 3] # list β€” mutable, ordered tpl = (1, 2, 3) # tuple β€” immutable, ordered rng = range(5) # range # Mapping dct = {"a": 1} # dict # Set st = {1, 2, 3} # set β€” unique, unordered fst = frozenset({1}) # frozenset β€” immutable set # Boolean b = True # bool (subclass of int) # Binary by = bytes(5) # bytes ba = bytearray(5) # bytearray # None n = None # NoneType
πŸ’‘Key distinction to mention: Mutable types (list, dict, set, bytearray) can be changed after creation. Immutable types (int, float, str, tuple, frozenset, bytes) cannot.
3
What is the difference between a list, tuple, and set in Python?
BeginnerVery Common
+
FeatureListTupleSet
Syntax[1, 2, 3](1, 2, 3){1, 2, 3}
Mutableβœ… Yes❌ Noβœ… Yes
Orderedβœ… Yesβœ… Yes❌ No
Duplicatesβœ… Allowedβœ… Allowed❌ Not allowed
Indexableβœ… Yesβœ… Yes❌ No
Use caseOrdered mutable dataFixed data, dict keysUnique items, fast lookup
Python
lst = [1, 2, 2, 3] # duplicates kept, ordered tpl = (1, 2, 2, 3) # duplicates kept, immutable st = {1, 2, 2, 3} # β†’ {1, 2, 3} (duplicate removed) # Tuple as dict key (works because immutable): coords = {(0,0): "origin", (1,2): "point A"} # List as dict key β€” TypeError (unhashable): # bad = {[0,0]: "origin"} ← raises TypeError
4
What are list comprehensions and how do they work?
BeginnerVery Common
+

A list comprehension is a concise, Pythonic way to create lists from existing iterables in a single line. Syntax: [expression for item in iterable if condition]

Python
# Traditional loop: squares = [] for n in range(10): squares.append(n ** 2) # List comprehension (equivalent, cleaner): squares = [n ** 2 for n in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # With condition (filter): evens = [n for n in range(20) if n % 2 == 0] # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] # Nested (flatten 2D list): matrix = [[1,2],[3,4],[5,6]] flat = [n for row in matrix for n in row] # [1, 2, 3, 4, 5, 6] # Dict comprehension: squared = {n: n**2 for n in range(5)} # {0:0, 1:1, 2:4, 3:9, 4:16}
5
What is the difference between == and is in Python?
BeginnerVery Common
+
  • == (equality): Checks if two objects have the same value.
  • is (identity): Checks if two variables point to the same object in memory (same id()).
Python
a = [1, 2, 3] b = [1, 2, 3] c = a print(a == b) # True β€” same values print(a is b) # False β€” different objects in memory print(a is c) # True β€” c points to same object as a # Small integers are cached by Python (-5 to 256): x = 100 y = 100 print(x is y) # True β€” same cached object x = 1000 y = 1000 print(x is y) # False β€” outside cache range
πŸ’‘Best practice: Use is only to compare against None, True, or False. Use == for everything else. Never use is to compare strings or integers.
6
What are *args and **kwargs in Python?
BeginnerVery Common
+

*args and **kwargs let functions accept a variable number of arguments.

Python
# *args β€” collects extra positional args as a TUPLE: def add(*args): return sum(args) add(1, 2, 3) # 6 add(10, 20, 30, 40) # 100 # **kwargs β€” collects extra keyword args as a DICT: def describe(**kwargs): for key, val in kwargs.items(): print(f"{key}: {val}") describe(name="Meraj", role="dev", lang="Python") # name: Meraj # role: dev # lang: Python # Combined (order matters: normal β†’ *args β†’ **kwargs): def example(a, b, *args, **kwargs): print(a, b, args, kwargs)
7
What is the difference between mutable and immutable objects?
BeginnerVery Common
+

Mutable objects can be changed after creation. Immutable objects cannot β€” any "modification" creates a new object.

Python
# MUTABLE β€” list changes in place: lst = [1, 2, 3] print(id(lst)) # 140234... lst.append(4) print(id(lst)) # 140234... same id! # IMMUTABLE β€” string creates new object: s = "hello" print(id(s)) # 140111... s = s + " world" # creates a NEW string print(id(s)) # 140999... different id! # Mutable: list, dict, set, bytearray # Immutable: int, float, str, tuple, bool, frozenset, bytes
⚠️Common trap: Mutable default arguments in functions are shared across all calls. Always use None as default, then assign the mutable inside the function.
8
What is a lambda function in Python?
Beginner
+

A lambda is an anonymous, single-expression function defined with the lambda keyword. It's used when you need a short function for a brief period β€” typically as an argument to higher-order functions.

Python
# Syntax: lambda arguments: expression square = lambda x: x ** 2 print(square(5)) # 25 # Equivalent regular function: def square(x): return x ** 2 # Common use β€” sorting with custom key: people = [("Alice", 30), ("Bob", 25), ("Meraj", 28)] people.sort(key=lambda p: p[1]) # sort by age # [('Bob', 25), ('Meraj', 28), ('Alice', 30)] # With map and filter: doubled = list(map(lambda x: x*2, [1,2,3])) # [2, 4, 6] evens = list(filter(lambda x: x%2==0, [1,2,3,4])) # [2, 4]
9
How does exception handling work in Python?
BeginnerCommon
+

Python uses try/except/else/finally blocks to handle runtime errors gracefully without crashing the program.

Python
try: result = 10 / 0 # code that might fail except ZeroDivisionError as e: print(f"Error: {e}") # handle specific error except (TypeError, ValueError) as e: print(f"Type/Value error: {e}") except Exception as e: print(f"Unexpected: {e}") # catch-all fallback else: print("No error occurred") # runs only if no exception finally: print("Always runs") # cleanup, always executes # Raising exceptions: def validate_age(age): if age < 0: raise ValueError(f"Age cannot be negative: {age}")
10
What are Python's range() and enumerate() functions?
Beginner
+

range() generates a sequence of numbers. enumerate() adds a counter to an iterable β€” both are commonly used in loops.

Python
# range(stop) β€” 0 to stop-1 range(5) # 0, 1, 2, 3, 4 # range(start, stop) range(2, 8) # 2, 3, 4, 5, 6, 7 # range(start, stop, step) range(0, 20, 5) # 0, 5, 10, 15 range(10, 0, -2) # 10, 8, 6, 4, 2 # enumerate β€” get index + value together: fruits = ["apple", "banana", "cherry"] # Without enumerate (clunky): for i in range(len(fruits)): print(i, fruits[i]) # With enumerate (Pythonic): for i, fruit in enumerate(fruits): print(i, fruit) # 0 apple # 1 banana # 2 cherry # Start counting from 1: for i, fruit in enumerate(fruits, start=1): print(i, fruit)

⚑Intermediate QuestionsQ11–Q21

11
What are Python decorators and how do they work?
IntermediateVery Common
+

A decorator is a function that wraps another function to add behaviour before or after it runs, without modifying the original function's code. They use the @ syntax.

Python
import time def timer(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) # call original end = time.time() print(f"{func.__name__} took {end-start:.4f}s") return result return wrapper @timer # same as: greet = timer(greet) def greet(name): time.sleep(0.1) print(f"Hello, {name}!") greet("Meraj") # Hello, Meraj! # greet took 0.1001s # Common built-in decorators: class MyClass: @staticmethod def static_method(): ... # no self/cls @classmethod def class_method(cls): ... # gets class, not instance @property def value(self): ... # access like attribute
πŸ’‘Why interviewers ask this: Decorators are fundamental to Python frameworks (Django, Flask use them extensively). Understanding the mechanics β€” not just the syntax β€” separates good candidates from great ones.
12
What are generators in Python and how are they different from regular functions?
IntermediateVery Common
+

A generator is a function that uses yield instead of return. It produces values one at a time, pausing and resuming execution β€” making it memory-efficient for large sequences.

Python
# Regular function β€” builds entire list in memory: def get_squares(n): return [i**2 for i in range(n)] # Generator β€” produces one value at a time: def gen_squares(n): for i in range(n): yield i ** 2 # pauses here, remembers state gen = gen_squares(5) print(next(gen)) # 0 print(next(gen)) # 1 print(next(gen)) # 4 # Generator expression (like list comprehension but lazy): gen_exp = (x**2 for x in range(1000000)) # Uses almost no memory β€” values computed on demand! # Infinite generator: def counter(start=0): while True: yield start start += 1
πŸ’‘Memory advantage: A list of 1 million items takes ~8MB. A generator producing the same values takes ~200 bytes. Use generators whenever you don't need all values at once.
13
What is OOP in Python? Explain classes, objects, and the four pillars.
IntermediateVery Common
+

Object-Oriented Programming organises code around objects β€” instances of classes. Python's four OOP pillars are Encapsulation, Inheritance, Polymorphism, and Abstraction.

Python
class Animal: def __init__(self, name, sound): self.name = name # public attribute self._sound = sound # protected (convention) def speak(self): # method return f"{self.name} says {self._sound}" def __str__(self): # dunder β€” string repr return f"Animal({self.name})" # Inheritance: class Dog(Animal): def __init__(self, name): super().__init__(name, "Woof") # call parent self.tricks = [] def learn_trick(self, trick): self.tricks.append(trick) # Polymorphism β€” same method, different behaviour: class Cat(Animal): def speak(self): # overrides parent return f"{self.name} says Meow softly" dog = Dog("Rex") cat = Cat("Whiskers", "Meow") for animal in [dog, cat]: print(animal.speak()) # polymorphic calls
14
What is the difference between shallow copy and deep copy?
Intermediate
+
Python
import copy original = [[1, 2], [3, 4]] # Shallow copy β€” top level copied, nested still shared: shallow = copy.copy(original) shallow[0].append(99) print(original) # [[1, 2, 99], [3, 4]] β€” modified! # Deep copy β€” fully independent clone: original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0].append(99) print(original) # [[1, 2], [3, 4]] β€” unchanged βœ“ # Shallow copy methods for lists: lst_copy1 = original[:] # slice lst_copy2 = original.copy() # .copy() lst_copy3 = list(original) # list()
15
What are Python's map(), filter(), and reduce() functions?
IntermediateCommon
+
Python
from functools import reduce nums = [1, 2, 3, 4, 5] # map β€” apply function to EVERY item, return iterator: squared = list(map(lambda x: x**2, nums)) # [1, 4, 9, 16, 25] # filter β€” keep items WHERE function returns True: evens = list(filter(lambda x: x % 2 == 0, nums)) # [2, 4] # reduce β€” accumulate to a single value: total = reduce(lambda acc, x: acc + x, nums) # 15 (1+2+3+4+5) product = reduce(lambda acc, x: acc * x, nums) # 120 (1Γ—2Γ—3Γ—4Γ—5) # Modern Pythonic alternatives: squared = [x**2 for x in nums] # map evens = [x for x in nums if x%2==0] # filter total = sum(nums) # reduce sum
16
What is the Global Interpreter Lock (GIL) in Python?
IntermediateCommon
+

The GIL (Global Interpreter Lock) is a mutex in CPython that allows only one thread to execute Python bytecode at a time, even on multi-core processors. It exists to protect Python's memory management from race conditions.

  • Impact on CPU-bound tasks: Threading doesn't give true parallelism for CPU-heavy code. Use multiprocessing instead.
  • Impact on I/O-bound tasks: The GIL is released during I/O operations, so threading works well for network requests, file reading, etc.
  • Workarounds: Use multiprocessing (separate processes, each with own GIL), or asyncio for I/O concurrency.
Python
# I/O-bound β†’ use threading (GIL released during I/O): import threading t = threading.Thread(target=fetch_url, args=(url,)) # CPU-bound β†’ use multiprocessing (bypasses GIL): import multiprocessing p = multiprocessing.Process(target=heavy_computation) # Or use asyncio for concurrent I/O: import asyncio async def main(): await asyncio.gather(task1(), task2())
πŸ’‘Note: Python 3.13+ has experimental support for a "free-threaded" mode (no GIL). This is a significant ongoing change to watch for in interviews.
17
What is the difference between @staticmethod and @classmethod?
Intermediate
+
Python
class Database: _instances = 0 def __init__(self, host): self.host = host Database._instances += 1 @staticmethod def validate_host(host): # No access to class or instance β€” pure utility return isinstance(host, str) and len(host) > 0 @classmethod def get_instance_count(cls): # Gets the class (cls), not instance (self) return cls._instances @classmethod def from_url(cls, url): # Alternative constructor pattern host = url.split("//")[1] return cls(host) # Usage: Database.validate_host("localhost") # staticmethod β€” no class needed Database.get_instance_count() # classmethod β€” accesses class db = Database.from_url("db://myhost") # alternative constructor
Feature@staticmethod@classmethod
First parameterNone (no implicit)cls (the class)
Access to class❌ Noβœ… Yes via cls
Access to instance❌ No❌ No
Use caseUtility/helper functionsAlternative constructors, class-level ops
18
What are Python's dunder (magic) methods?
Intermediate
+

Dunder (double underscore) methods, also called magic methods, allow classes to define how they behave with built-in Python operations like +, len(), print(), and comparisons.

Python
class Vector: def __init__(self, x, y): # constructor self.x, self.y = x, y def __repr__(self): # developer repr return f"Vector({self.x}, {self.y})" def __str__(self): # user-facing str return f"({self.x}, {self.y})" def __add__(self, other): # + operator return Vector(self.x+other.x, self.y+other.y) def __len__(self): # len() return int((self.x**2 + self.y**2)**0.5) def __eq__(self, other): # == operator return self.x == other.x and self.y == other.y v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) # (4, 6) print(len(v2)) # 5
19
What is Python's with statement and context managers?
Intermediate
+

The with statement ensures that setup and teardown code runs reliably β€” even if an exception occurs. It's used for resource management (files, database connections, locks).

Python
# Without context manager β€” file might not close on error: f = open("file.txt") data = f.read() f.close() # might be skipped if exception occurs! # With context manager β€” always closes, even on exception: with open("file.txt") as f: data = f.read() # file automatically closed here βœ“ # Custom context manager using __enter__ / __exit__: class Timer: import time def __enter__(self): self.start = __import__("time").time() return self def __exit__(self, *args): elapsed = __import__("time").time() - self.start print(f"Elapsed: {elapsed:.4f}s") with Timer(): # code being timed sum(range(1000000))
20
What is the difference between append(), extend(), and insert() for lists?
Intermediate
+
Python
lst = [1, 2, 3] # append β€” adds ONE item to the end: lst.append(4) print(lst) # [1, 2, 3, 4] lst.append([5, 6]) print(lst) # [1, 2, 3, 4, [5, 6]] ← list nested as one item lst = [1, 2, 3] # extend β€” adds EACH item from iterable: lst.extend([4, 5, 6]) print(lst) # [1, 2, 3, 4, 5, 6] ← items merged in lst = [1, 2, 3] # insert β€” adds item at SPECIFIC index: lst.insert(1, 99) print(lst) # [1, 99, 2, 3] lst.insert(0, 0) print(lst) # [0, 1, 99, 2, 3]
21
What are Python's zip() and any() / all() built-ins?
Intermediate
+
Python
# zip β€” pair up items from multiple iterables: names = ["Alice", "Bob", "Meraj"] scores = [90, 85, 95] for name, score in zip(names, scores): print(f"{name}: {score}") # zip stops at the shortest iterable # Use zip_longest for different-length iterables # Create dict from two lists: result = dict(zip(names, scores)) # {"Alice": 90, "Bob": 85, "Meraj": 95} # any β€” True if AT LEAST ONE item is truthy: any([False, False, True]) # True any([False, False, False]) # False any(x > 90 for x in scores) # True (95 > 90) # all β€” True only if ALL items are truthy: all([True, True, True]) # True all([True, False, True]) # False all(x > 80 for x in scores) # True (all > 80)

πŸ”₯Advanced QuestionsQ22–Q30

22
What are Python metaclasses?
Advanced
+

A metaclass is the "class of a class" β€” it defines how classes themselves are created. Just as objects are instances of classes, classes are instances of metaclasses. The default metaclass in Python is type.

Python
# type is the default metaclass: print(type(int)) # <class 'type'> print(type(str)) # <class 'type'> # Custom metaclass β€” auto-uppercase all method names: class UpperMeta(type): def __new__(mcs, name, bases, namespace): upper_ns = { k.upper() if not k.startswith("__") else k: v for k, v in namespace.items() } return super().__new__(mcs, name, bases, upper_ns) class MyClass(metaclass=UpperMeta): def hello(self): return "hi" obj = MyClass() print(obj.HELLO()) # "hi" β€” method was renamed to HELLO
πŸ’‘Real-world use: Django's ORM models use metaclasses to turn class attributes into database column definitions. ORMs, API frameworks, and abstract base classes are the main use cases.
23
What is Python's memory management and garbage collection?
Advanced
+

Python manages memory automatically through two mechanisms:

  • Reference counting: Every object tracks how many references point to it. When the count drops to zero, the memory is immediately freed.
  • Cyclic garbage collector: Handles reference cycles (where two objects reference each other) that reference counting alone can't clean up.
Python
import sys import gc x = [1, 2, 3] print(sys.getrefcount(x)) # 2 (x + argument to getrefcount) y = x print(sys.getrefcount(x)) # 3 del y print(sys.getrefcount(x)) # 2 (y removed) # Reference cycle β€” reference counting can't handle this: a = {} b = {} a['b'] = b b['a'] = a del a, b # Both still in memory! GC detects and cleans up the cycle # Manual GC control: gc.collect() # force collection gc.disable() # disable automatic GC
24
What are Python descriptors and how do they work?
Advanced
+

A descriptor is an object that defines how attribute access works on another class, by implementing __get__, __set__, and/or __delete__. They power Python's @property, @classmethod, and @staticmethod.

Python
class ValidatedAge: """Descriptor that validates age on set""" def __set_name__(self, owner, name): self._name = name def __get__(self, obj, objtype=None): if obj is None: return self return obj.__dict__.get(self._name) def __set__(self, obj, value): if not isinstance(value, int) or value < 0: raise ValueError(f"Age must be non-negative int") obj.__dict__[self._name] = value class Person: age = ValidatedAge() # descriptor as class attribute def __init__(self, name, age): self.name = name self.age = age # triggers __set__ p = Person("Meraj", 25) # βœ“ p.age = -5 # βœ— raises ValueError
25
What is asyncio and how does Python handle asynchronous programming?
AdvancedCommon
+

asyncio is Python's built-in library for writing concurrent I/O-bound code using coroutines β€” functions defined with async def and awaited with await. It runs in a single thread using an event loop.

Python
import asyncio async def fetch_data(url, delay): print(f"Fetching {url}...") await asyncio.sleep(delay) # simulate I/O wait (non-blocking) return f"Data from {url}" async def main(): # Run concurrently β€” total ~2s, not 1+2=3s: results = await asyncio.gather( fetch_data("api.com/users", 1), fetch_data("api.com/posts", 2), ) print(results) asyncio.run(main()) # Key concepts: # coroutine β€” async def function # await β€” pause until awaitable completes # task β€” scheduled coroutine # gather() β€” run multiple coroutines concurrently
πŸ’‘When to use: asyncio is ideal for I/O-bound tasks (HTTP requests, database queries, file ops). For CPU-bound tasks, use multiprocessing or concurrent.futures.ProcessPoolExecutor.
26
What are Python's __slots__ and when should you use them?
Advanced
+

By default, Python stores instance attributes in a per-instance __dict__ dictionary β€” flexible but memory-heavy. __slots__ replaces this with a fixed, compact array, reducing memory usage significantly.

Python
# Normal class β€” uses __dict__ per instance: class Point: def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) print(p.__dict__) # {'x': 1, 'y': 2} p.z = 3 # can add any attribute dynamically # With __slots__ β€” fixed attributes, no __dict__: class PointSlot: __slots__ = ['x', 'y'] def __init__(self, x, y): self.x = x self.y = y ps = PointSlot(1, 2) # ps.__dict__ ← AttributeError, no __dict__! # ps.z = 3 ← AttributeError, can't add new attrs # Memory comparison (1 million objects): # Normal Point: ~56 bytes/instance # PointSlot: ~32 bytes/instance (~43% less)

Use __slots__ when: creating many instances of a class (e.g., data records, coordinates, nodes in a large graph), and you don't need to add arbitrary attributes dynamically.

27
What is the difference between __new__ and __init__?
Advanced
+
  • __new__: Called first β€” responsible for creating and returning the new object instance. Takes cls as first argument.
  • __init__: Called after β€” responsible for initialising the already-created instance. Takes self.
Python
# Singleton using __new__: class Singleton: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance # always return same instance def __init__(self): self.value = 42 a = Singleton() b = Singleton() print(a is b) # True β€” same object βœ“ # __new__ also needed for immutable types: class PositiveInt(int): def __new__(cls, value): if value < 0: raise ValueError("Must be positive") return super().__new__(cls, value)
28
What are Python type hints and why are they useful?
AdvancedCommon
+

Type hints (PEP 484, Python 3.5+) let you annotate variables and function signatures with expected types. Python doesn't enforce them at runtime, but they improve code readability, catch bugs early via static analysis tools like mypy, and power IDE autocompletion.

Python
from typing import Optional, Union, List, Dict, Tuple # Function with type hints: def greet(name: str, age: int) -> str: return f"Hello {name}, you are {age}" # Optional β€” can be None: def find_user(user_id: int) -> Optional[str]: return None # or a string # Union β€” multiple possible types: def process(data: Union[str, bytes]) -> str: ... # Modern Python 3.10+ syntax: def process(data: str | bytes) -> str: ... def find_user(user_id: int) -> str | None: ... # Variable annotations: name: str = "Meraj" scores: List[int] = [90, 85, 95] user: Dict[str, Union[str, int]] = {"name": "Bob", "age": 25}
29
What is the difference between deepcopy, pickling, and serialisation in Python?
Advanced
+
MethodPurposeOutputUse case
copy.deepcopy()Clone object in memoryPython objectAvoid shared references in RAM
pickleSerialize to bytesBinary bytesSave/send Python objects
jsonSerialize to stringJSON stringAPIs, cross-language interchange
Python
import pickle, json, copy data = {"name": "Meraj", "scores": [90, 85]} # pickle β€” Python-only, can handle any Python object: binary = pickle.dumps(data) restored = pickle.loads(binary) # json β€” cross-language, only basic types: json_str = json.dumps(data) parsed = json.loads(json_str) # ⚠️ Never unpickle data from untrusted sources! # Pickle can execute arbitrary code on load
30
What is a Python dataclass and when should you use it over a regular class?
AdvancedCommon
+

Dataclasses (Python 3.7+) automatically generate boilerplate methods (__init__, __repr__, __eq__) for classes that primarily store data.

Python
from dataclasses import dataclass, field from typing import List # Regular class β€” lots of boilerplate: class UserOld: def __init__(self, name: str, age: int, roles: list): self.name = name self.age = age self.roles = roles def __repr__(self): return f"User({self.name}, {self.age})" def __eq__(self, o): return self.name == o.name and self.age == o.age # Dataclass β€” same result, much less code: @dataclass class User: name: str age: int roles: List[str] = field(default_factory=list) u1 = User("Meraj", 25) u2 = User("Meraj", 25) print(u1) # User(name='Meraj', age=25, roles=[]) print(u1 == u2) # True β€” __eq__ auto-generated # Frozen dataclass (immutable, hashable): @dataclass(frozen=True) class Point: x: float y: float p = Point(1.0, 2.0) # p.x = 5 ← FrozenInstanceError {p: "origin"} # βœ“ usable as dict key (hashable)
πŸ’‘Use dataclass when: the primary purpose is storing data with clear fields. Use regular classes when you have complex logic, heavy customisation of __init__, or inheritance hierarchies where dataclass inheritance gets complex.

Up Next: React Interview Questions

You've covered Python. Next in the series is React β€” hooks, virtual DOM, state management, and component patterns. Coming soon to RankWeb3.

← Git & GitHub Q&A