Skip to content

amarkum/python-datastructures

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

python-datastructures

A hands-on Python repo for data structures and interview topics. Every folder has runnable code, a descriptive example, and Interview Q&A in its README.

Each topic's full walkthrough and 5–6 Q&A pairs live in that folder's README.md. Below is a quick reference with code snippets; see Most Asked Interview Questions for a master Q&A index.

Requirements: Python 3.8+ · No external dependencies

System design

Company-wise detailed designs — each product in its own folder:

Product Folder
Uber system-design/uber/
Instagram system-design/instagram/
Facebook system-design/facebook/
Airbnb system-design/airbnb/
URL Shortener system-design/url-shortener/
Real-Time Coding system-design/realtime-coding/

Index + building blocks: system-design/README.md


Quick run

# Data structures
python3 linkedlist/caller.py
python3 stack/caller.py
python3 queues/caller.py
python3 tree/caller.py

# Python interview topic
cd python/decorator && python3 example.py

Data structures

Linear collection of nodes. Each node holds data and a pointer to the next node.

from linkedlistcustom import LinkedList

ll = LinkedList()
ll.add_at_end(10)
ll.add_at_end(20)
ll.reverse()          # in-place reversal
ll.detect_loop()      # Floyd's cycle detection
ll.find_mid()         # slow/fast pointer

Run: python3 linkedlist/caller.py · Docs: linkedlist/README.md


Last In, First Out (LIFO). Array-backed with fixed capacity.

from stackcustom import Stack

stack = Stack(5)
stack.push(10)
stack.push(20)
print(stack.pop())    # 20
print(stack.get_top())  # peek without removing

Run: python3 stack/caller.py · Docs: stack/README.md


First In, First Out (FIFO). Circular ring buffer.

from queuecustom import Queue

queue = Queue(5)
queue.enqueue(1)
queue.enqueue(2)
print(queue.dequeue())  # 1

Run: python3 queues/caller.py · Docs: queues/README.md


Ordered tree — left subtree < node < right subtree. Supports insert, search, delete.

from binarysearchtreecustom import BinarySearchTree

bst = BinarySearchTree()
bst.add(5)
bst.add(3)
bst.add(7)
print(bst.search(3))   # True
bst.delete(3)
bst.print_tree(bst.root)

Run: python3 tree/caller.py · Docs: tree/README.md


Python interview topics

Full index: python/README.md


Core language

Wrap a function to extend behavior without changing its source.

import functools

def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        print(f"{func.__name__} took {time.perf_counter() - start:.4f}s")
        return result
    return wrapper

@timer
def work():
    ...

Run: python3 python/decorator/example.py


Guarantee setup/teardown with the with statement.

from contextlib import contextmanager

@contextmanager
def temp_value(obj, attr, new_value):
    old = getattr(obj, attr)
    setattr(obj, attr, new_value)
    try:
        yield obj
    finally:
        setattr(obj, attr, old)

with temp_value(config, "debug", True):
    run_tests()

Run: python3 python/context_manager/example.py


Lazy iteration with yield — constant memory for large data.

def fibonacci(limit):
    a, b = 0, 1
    while a < limit:
        yield a
        a, b = b, a + b

for n in fibonacci(100):
    print(n)

Run: python3 python/generator/example.py


Objects with __iter__ and __next__ — the protocol behind for loops.

class CountDown:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        self.current -= 1
        return self.current + 1

Run: python3 python/iterator/example.py


Inner functions that remember variables from an enclosing scope.

def make_multiplier(factor):
    def multiply(x):
        return x * factor
    return multiply

double = make_multiplier(2)
print(double(10))  # 20

Run: python3 python/closure/example.py


Flexible signatures and argument forwarding.

def build_profile(name, **kwargs):
    return {"name": name, **kwargs}

def wrapper(func, *args, **kwargs):
    return func(*args, **kwargs)

build_profile("Alice", role="engineer", city="NYC")
greet(*("Hello", "Bob"), **{"punctuation": "?"})

Run: python3 python/args_kwargs/example.py


Name lookup order: Local → Enclosing → Global → Built-in.

count = 0

def make_counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

Run: python3 python/scope/example.py


Concise way to build lists, dicts, sets, and generators.

squares = [x ** 2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]
word_map = {w: len(w) for w in ["python", "go"]}
total = sum(x ** 2 for x in range(1000))  # generator — lazy

Run: python3 python/comprehension/example.py


Functional-style builtins (often replaced by comprehensions today).

doubled = list(map(lambda x: x * 2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))
for name, score in zip(names, scores):
    print(name, score)

Run: python3 python/lambda_map_filter/example.py


Structured error handling with try/except/else/finally.

try:
    result = divide(a, b)
except ZeroDivisionError as e:
    print(f"Caught: {e}")
else:
    print(f"Result: {result}")
finally:
    cleanup()

Run: python3 python/exception_handling/example.py


Default values are evaluated once at definition time — a classic trap.

# BUG — same list shared across calls
def append_bad(item, target=[]):
    target.append(item)
    return target

# FIX — use None sentinel
def append_good(item, target=None):
    if target is None:
        target = []
    target.append(item)
    return target

Run: python3 python/mutable_default/example.py


== compares values; is compares object identity (same memory).

a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)  # True  — same values
print(a is b)  # False — different objects

x = None
if x is None:  # always use `is` for None
    ...

Run: python3 python/identity_equality/example.py


Shallow copy shares nested objects; deep copy is fully independent.

import copy

original = [[1, 2], [3, 4]]
shallow = copy.copy(original)
deep = copy.deepcopy(original)

original[0].append(99)
# shallow affected, deep unchanged

Run: python3 python/copy_deepcopy/example.py


OOP & classes

Magic methods control operators, printing, and protocol behavior.

class Vector:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

Run: python3 python/dunder_methods/example.py


Method Resolution Order — how Python searches base classes.

class B(A):
    def greet(self):
        return f"B -> {super().greet()}"

class D(B, C):
    pass

print(D.__mro__)  # (D, B, C, A, object)

Run: python3 python/inheritance_mro/example.py


Classes that create classes — control class construction.

class SingletonMeta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class Database(metaclass=SingletonMeta):
    pass

Run: python3 python/metaclass/example.py


Validated attributes and computed fields without breaking the API.

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value <= 0:
            raise ValueError("Radius must be positive")
        self._radius = value

    @property
    def area(self):
        return 3.14159 * self._radius ** 2

Run: python3 python/property_descriptor/example.py


Auto-generated __init__, __repr__, and __eq__ for data objects.

from dataclasses import dataclass, field

@dataclass
class Team:
    name: str
    members: list[str] = field(default_factory=list)

@dataclass(frozen=True)
class Point:
    x: float
    y: float

Run: python3 python/dataclass/example.py


Fixed attributes — saves memory by removing per-instance __dict__.

class Point:
    __slots__ = ("x", "y")

    def __init__(self, x, y):
        self.x = x
        self.y = y

Run: python3 python/slots/example.py


Enforce interfaces with @abstractmethod.

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

class Rectangle(Shape):
    def area(self):
        return self.width * self.height

Run: python3 python/abc/example.py


Concurrency & async

Threads share memory. The GIL limits CPU parallelism in CPython.

import threading

lock = threading.Lock()
counter = 0

def safe_increment():
    global counter
    with lock:
        counter += 1

Run: python3 python/threading/example.py


Separate processes for CPU-bound work — bypasses the GIL.

from concurrent.futures import ProcessPoolExecutor

with ProcessPoolExecutor(max_workers=4) as pool:
    results = list(pool.map(square, range(8)))

Run: python3 python/multiprocessing/example.py


Cooperative I/O concurrency on a single thread.

import asyncio

async def fetch(name):
    await asyncio.sleep(0.1)
    return f"result-{name}"

async def main():
    results = await asyncio.gather(fetch("A"), fetch("B"))
    print(results)

asyncio.run(main())

Run: python3 python/async_await/example.py


Standard library & tooling

Caching, partial application, and function utilities.

import functools

@functools.lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

double = functools.partial(multiply, 2)

Run: python3 python/functools_module/example.py


Static annotations for tooling (mypy, pyright) — not enforced at runtime.

from dataclasses import dataclass
from typing import Optional

def greet(name: str, times: int = 1) -> str:
    return (f"Hello, {name}! " * times).strip()

@dataclass
class User:
    id: int
    name: str
    email: Optional[str] = None

Run: python3 python/type_hints/example.py


Replace dependencies in tests with fakes that record calls.

from unittest.mock import MagicMock, patch

mock_db = MagicMock()
mock_db.get.return_value = {"id": 1, "name": "Alice"}
user = fetch_user(1, mock_db)
mock_db.get.assert_called_once_with(1)

Run: python3 python/unittest_mock/example.py


Reference counting + cyclic GC in CPython.

import gc, sys, weakref

obj = ["data"]
print(sys.getrefcount(obj))
weak = weakref.ref(obj)
del obj
print(weak() is None)  # True — object collected
gc.collect()

Run: python3 python/memory_management/example.py


Most Asked Interview Questions

Master Q&A index — full answers and examples in each folder's README.

Data structures

Q: How do you reverse a linked list in O(n) time and O(1) space?
A: Three pointers (prev, current, next). Flip current.next = prev each step. → linkedlist/README.md

Q: How do you detect a cycle in a linked list?
A: Floyd's algorithm — slow (1 step) and fast (2 steps) pointers meet if cycle exists. → linkedlist/README.md

Q: Stack vs queue — key difference?
A: Stack is LIFO; queue is FIFO. → stack/README.md · queues/README.md

Q: BST average vs worst-case search time?
A: Average O(log n); worst O(n) when tree degenerates to a linked list. → tree/README.md

Core language

Q: What is a Python decorator?
A: Callable that wraps a function: @deco means func = deco(func). → python/decorator/

Q: What do __enter__ and __exit__ do?
A: Setup/teardown for with blocks. __exit__ returning True suppresses exceptions. → python/context_manager/

Q: Generator vs list comprehension?
A: Generator is lazy (constant memory). List comp builds full list in memory. → python/generator/

Q: Iterable vs iterator?
A: Iterable has __iter__(). Iterator has __iter__() + __next__(). → python/iterator/

Q: What is a closure?
A: Nested function capturing variables from enclosing scope after outer function returns. → python/closure/

Q: What are *args and **kwargs?
A: Extra positional args → tuple; extra keyword args → dict. → python/args_kwargs/

Q: Explain LEGB rule.
A: Local → Enclosing → Global → Built-in name lookup order. → python/scope/

Q: Why is def f(a=[]) dangerous?
A: Default evaluated once at definition — same mutable list shared across calls. → python/mutable_default/

Q: is vs ==?
A: == compares values; is compares identity. Use is only for None, True, False. → python/identity_equality/

Q: Shallow vs deep copy?
A: Shallow copies outer container; nested objects shared. Deep copy is fully independent. → python/copy_deepcopy/

OOP & classes

Q: __repr__ vs __str__?
A: __repr__ is unambiguous (developers); __str__ is human-readable (users). → python/dunder_methods/

Q: What is MRO?
A: Method Resolution Order — C3 linearization for multiple inheritance lookup. → python/inheritance_mro/

Q: What is a metaclass?
A: Class of a class — controls how classes are created (type by default). → python/metaclass/

Q: How does @property work?
A: Descriptor providing getter/setter/deleter as attribute-like access. → python/property_descriptor/

Q: Dataclass vs NamedTuple?
A: Dataclass is mutable (unless frozen). NamedTuple is immutable tuple subclass. → python/dataclass/

Q: When use __slots__?
A: Many homogeneous instances where memory matters — removes per-instance __dict__. → python/slots/

Q: ABC vs duck typing?
A: ABC enforces interface at instantiation. Duck typing checks behavior at runtime. → python/abc/

Concurrency

Q: What is the GIL?
A: Global Interpreter Lock — one thread runs Python bytecode at a time per process. → python/threading/

Q: Threading vs multiprocessing vs async?
A: Threading: I/O-bound, shared memory. Multiprocessing: CPU-bound, bypasses GIL. Async: I/O-bound, single-thread cooperative. → python/threading/ · python/multiprocessing/ · python/async_await/

Q: Why if __name__ == "__main__" with multiprocessing?
A: Prevents infinite recursive spawning on Windows/macOS spawn start method. → python/multiprocessing/

Standard library

Q: What does @lru_cache do?
A: Memoizes function results by arguments — LRU eviction when maxsize reached. → python/functools_module/

Q: Do type hints enforce types at runtime?
A: No — they're for static tools (mypy). Runtime ignores them by default. → python/type_hints/

Q: Mock vs stub?
A: Mock verifies interactions (call count/args). Stub returns canned data without verification. → python/unittest_mock/

Q: How does Python free memory?
A: Reference counting (primary) + cyclic garbage collector for circular refs. → python/memory_management/


Run all examples

# Data structures
for d in linkedlist stack queues tree; do python3 $d/caller.py; done

# All Python interview topics
for d in python/*/; do python3 "${d}example.py"; done

Project layout

python-datastructures/
├── README.md                 ← you are here
├── linkedlist/               # Singly linked list
├── stack/                    # LIFO stack
├── queues/                   # FIFO circular queue
├── tree/                     # Binary search tree
└── python/                   # 27 interview topics
    ├── decorator/
    ├── context_manager/
    ├── generator/
    ├── ... (22 more)
    └── README.md             # topic index

Topic checklist (31 total)

# Topic Folder
1 Linked List linkedlist/
2 Stack stack/
3 Queue queues/
4 Binary Search Tree tree/
5 Decorators python/decorator/
6 Context Managers python/context_manager/
7 Generators python/generator/
8 Iterators python/iterator/
9 Closures python/closure/
10 *args & **kwargs python/args_kwargs/
11 Scope (LEGB) python/scope/
12 Comprehensions python/comprehension/
13 map / filter / zip python/lambda_map_filter/
14 Exception Handling python/exception_handling/
15 Mutable Defaults python/mutable_default/
16 is vs == python/identity_equality/
17 Copy & Deepcopy python/copy_deepcopy/
18 Dunder Methods python/dunder_methods/
19 Inheritance & MRO python/inheritance_mro/
20 Metaclasses python/metaclass/
21 Properties & Descriptors python/property_descriptor/
22 Dataclasses python/dataclass/
23 slots python/slots/
24 Abstract Base Classes python/abc/
25 Threading & GIL python/threading/
26 Multiprocessing python/multiprocessing/
27 Async / Await python/async_await/
28 functools python/functools_module/
29 Type Hints python/type_hints/
30 unittest.mock python/unittest_mock/
31 Memory Management python/memory_management/

About

mastering data-structures in python!

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages