“So, Why Do You Like Python?” — An Interview Reflection¶
How a simple interview question led me to deeply reflect on programming language philosophy
The Interview Moment¶
There I was, sitting in a virtual interview for a Software Engineer position. We’d covered system design, talked through my experience scaling microservices, and discussed architectural trade-offs. Then came a question I wasn’t expecting:
“You’ve worked with many languages throughout your career. Why do you like Python, and what makes it different from the others?”
I paused. Not because I didn’t have an answer. I’ve been writing Python for over six years, but because I realized I’d never truly articulated it before. It’s one thing to use a tool every day; it’s another to explain why that tool feels like an extension of your thinking.
Here’s what I shared, expanded into the reflection I wish I’d given.
Why I Love Python: Beyond the Syntax¶
1. Readability Is Not Just a Feature. It’s a Philosophy¶
Python’s creator, Guido van Rossum, designed the language with a radical idea: code is read more often than it is written. This principle, enshrined in PEP 20 (The Zen of Python), shapes everything about the language.
# The Zen of Python (try running: import this)
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Readability counts.
When I review a Python codebase, I can often understand the intent without extensive documentation. Compare this simple example across languages:
Python:
def get_active_users(users):
return [user for user in users if user.is_active]
Java:
public List<User> getActiveUsers(List<User> users) {
return users.stream()
.filter(User::isActive)
.collect(Collectors.toList());
}
C++:
std::vector<User> getActiveUsers(const std::vector<User>& users) {
std::vector<User> result;
std::copy_if(users.begin(), users.end(),
std::back_inserter(result),
[](const User& u) { return u.isActive(); });
return result;
}
The Python version reads almost like English. This isn’t just aesthetic—it reduces cognitive load during code reviews, debugging, and onboarding new team members.
2. The “Batteries Included” Standard Library¶
Python ships with an incredibly comprehensive standard library. Need to work with JSON? import json. HTTP requests? urllib is built-in. Regular expressions, date handling, file operations, concurrent programming—it’s all there.
# No external dependencies needed for common tasks
import json
import datetime
import pathlib
import concurrent.futures
import urllib.request
# Parse JSON, handle dates, manage files - all built-in
config = json.loads(pathlib.Path("config.json").read_text())
3. The Ecosystem Is Unmatched for Certain Domains¶
┌─────────────────────────────────────────────────────────────────┐
│ Python's Ecosystem Dominance │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Data Science & ML Web Development │
│ ───────────────── ─────────────── │
│ • NumPy • Django │
│ • Pandas • FastAPI │
│ • Scikit-learn • Flask │
│ • TensorFlow • Celery │
│ • PyTorch • SQLAlchemy │
│ │
│ DevOps & Automation Scientific Computing │
│ ────────────────── ──────────────────── │
│ • Ansible • SciPy │
│ • Fabric • Matplotlib │
│ • Boto3 (AWS) • Jupyter │
│ • Docker SDK • SymPy │
│ │
└─────────────────────────────────────────────────────────────────┘
How Python Differs: A Technical Deep Dive¶
When the interviewer asked what sets Python apart, I knew I had to go beyond surface-level observations. Here’s the technical breakdown:
Type System Comparison¶
┌────────────────────────────────────────────────────────────────────────────┐
│ Type System Spectrum │
│ │
│ Static Dynamic │
│ Strongly Typed Weakly Typed │
│ │ │ │
│ ▼ ▼ │
│ ┌───────┐ ┌──────┐ ┌────────┐ ┌────────┐ ┌──────────────┐ │
│ │ Rust │ │ Java │ │ Go │ │ Python │ │ JavaScript │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │Static │ │Static│ │ Static │ │Dynamic │ │ Dynamic │ │
│ │Strong │ │Strong│ │ Strong │ │ Strong │ │ Weak │ │
│ └───────┘ └──────┘ └────────┘ └────────┘ └──────────────┘ │
│ │
│ Compile-time ◄─────────────────────► Runtime │
│ type checking type checking │
└────────────────────────────────────────────────────────────────────────────┘
Python is dynamically typed but strongly typed. This is a crucial distinction:
# Dynamic typing: types are checked at runtime
x = 10 # x is an int
x = "hello" # now x is a str - perfectly valid
# Strong typing: no implicit type coercion
result = "10" + 5 # TypeError! Python won't silently convert
Compare to JavaScript (dynamic + weak typing):
// JavaScript allows this - weak typing
const result = "10" + 5; // "105" - string concatenation!
Memory Management Approaches¶
┌─────────────────────────────────────────────────────────────────────────┐
│ Memory Management Strategies │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Manual │ │ Garbage │ │ Ownership │ │
│ │ Management │ │ Collection │ │ System │ │
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │
│ │ │ │ │ │ │ │
│ │ C, C++ │ │ Python │ │ Rust │ │
│ │ │ │ Java │ │ │ │
│ │ malloc/free │ │ Go │ │ Borrow checker │ │
│ │ new/delete │ │ JavaScript │ │ Zero-cost │ │
│ │ │ │ │ │ abstractions │ │
│ │ ⚠️ Risk of │ │ ✓ Automatic │ │ ✓ No GC pause │ │
│ │ memory leaks │ │ ⚠️ GC pauses │ │ ⚠️ Steep │ │
│ │ and dangling │ │ possible │ │ learning │ │
│ │ pointers │ │ │ │ curve │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ Developer Control ◄──────────────────────────► Safety & Convenience │
└────────────────────────────────────────────────────────────────────────┘
Python uses reference counting combined with a cyclic garbage collector:
import sys
# Reference counting in action
a = [1, 2, 3]
print(sys.getrefcount(a)) # 2 (one for 'a', one for the getrefcount argument)
b = a # Another reference
print(sys.getrefcount(a)) # 3
del b # Reference removed
print(sys.getrefcount(a)) # Back to 2
Execution Model Comparison¶
┌────────────────────────────────────────────────────────────────────────┐
│ Execution Model Flow │
└────────────────────────────────────────────────────────────────────────┘
COMPILED LANGUAGES (C, C++, Rust, Go)
─────────────────────────────────────
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Source Code │───►│ Compiler │───►│ Machine │───► Execution
│ (.c/.rs) │ │ │ │ Code │
└──────────────┘ └──────────────┘ └──────────────┘
JIT COMPILED (Java, C#)
───────────────────────
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐
│ Source Code │───►│ Compiler │───►│ Bytecode │───►│ JIT │───►
│ (.java) │ │ │ │ (.class) │ │ Compiler │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────┘
│
▼
┌──────────┐
│ Machine │
│ Code │
└──────────┘
INTERPRETED (Python - CPython)
──────────────────────────────
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Source Code │───►│ Bytecode │───►│ Python │───► Execution
│ (.py) │ │ Compiler │ │ Virtual │
│ │ │ │ │ Machine │
└──────────────┘ │ (.pyc) │ │ (Interpreter)│
└──────────────┘ └──────────────┘
Performance Characteristics¶
Let’s be honest. Python isn’t the fastest language. But context matters:
┌─────────────────────────────────────────────────────────────────────────┐
│ Relative Performance (Lower is Faster) │
│ Benchmark: Fibonacci(40) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ C ████ 0.15s │
│ │
│ Rust █████ 0.16s │
│ │
│ Go ███████ 0.28s │
│ │
│ Java ████████ 0.32s │
│ │
│ JavaScript ██████████████ 0.58s (V8) │
│ │
│ Python ████████████████████████████████████████████████ 22.5s │
│ │
│ PyPy ███████████ 0.45s (JIT-compiled Python) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Note: These are illustrative benchmarks. Real-world performance depends
heavily on the specific workload and optimization techniques used.
But here’s what I told the interviewer: Raw computation speed rarely matters in real-world applications. Most backend services are I/O bound—waiting on databases, APIs, and file systems. Python’s async capabilities handle this beautifully:
import asyncio
import aiohttp
async def fetch_all_users(user_ids: list[int]) -> list[dict]:
"""Fetch multiple users concurrently - I/O bound operation"""
async with aiohttp.ClientSession() as session:
tasks = [fetch_user(session, uid) for uid in user_ids]
return await asyncio.gather(*tasks)
async def fetch_user(session: aiohttp.ClientSession, user_id: int) -> dict:
async with session.get(f"https://api.example.com/users/{user_id}") as resp:
return await resp.json()
The Global Interpreter Lock (GIL)¶
I can’t discuss Python’s differences without mentioning the GIL—the most misunderstood aspect of CPython:
┌─────────────────────────────────────────────────────────────────────────┐
│ Understanding the GIL │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ What the GIL Does: │
│ ────────────────── │
│ Only ONE thread can execute Python bytecode at a time │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Time ───────► │ │
│ │ │ │
│ │ Thread 1: ████████░░░░░░░░████████░░░░░░░░████████ │ │
│ │ │ │ │ │ │ │
│ │ Thread 2: ░░░░░░░░████████░░░░░░░░████████░░░░░░░░ │ │
│ │ │ │ │ │ │ │
│ │ GIL: ────────┴───────┴───────┴───────┴────── │ │
│ │ (threads take turns holding the lock) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ When GIL Matters: When GIL Doesn't Matter: │
│ ─────────────────── ───────────────────────── │
│ • CPU-bound tasks • I/O-bound tasks │
│ • Pure Python number • Database queries │
│ crunching • Network requests │
│ • Image processing • File operations │
│ (without NumPy) • Web servers │
│ • NumPy operations (releases GIL) │
│ │
│ Solutions for CPU-bound: │
│ ──────────────────────── │
│ • multiprocessing module (separate processes, no shared GIL) │
│ • Cython or Numba (compile to native code) │
│ • PyPy (JIT compilation) │
│ • Python 3.13+ free-threaded builds (experimental) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
# CPU-bound: Use multiprocessing to bypass GIL
from multiprocessing import Pool
def cpu_intensive_task(n):
return sum(i * i for i in range(n))
if __name__ == "__main__":
with Pool(processes=4) as pool:
results = pool.map(cpu_intensive_task, [10_000_000] * 4)
Modern Python: Type Hints and Beyond¶
One thing I emphasized in the interview: Python has evolved dramatically. Modern Python (3.10+) with type hints feels like a different language:
from dataclasses import dataclass
from typing import Optional
from datetime import datetime
@dataclass
class User:
id: int
email: str
created_at: datetime
last_login: Optional[datetime] = None
def is_recently_active(self, days: int = 30) -> bool:
if self.last_login is None:
return False
delta = datetime.now() - self.last_login
return delta.days <= days
def process_users(users: list[User]) -> dict[str, list[User]]:
"""Categorize users by activity status."""
return {
"active": [u for u in users if u.is_recently_active()],
"inactive": [u for u in users if not u.is_recently_active()]
}
Combined with tools like mypy, Pydantic, and FastAPI, you get the best of both worlds: Python’s flexibility during development with static analysis catching bugs before production.
When NOT to Use Python¶
Being a Staff Engineer means knowing when not to use your favorite tool. I told the interviewer:
┌─────────────────────────────────────────────────────────────────────────┐
│ Language Selection Guide │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Use Case Recommended Language(s) │
│ ───────────────────────────── ───────────────────────────────── │
│ │
│ Systems programming Rust, C, C++ │
│ (OS, drivers, embedded) │
│ │
│ High-frequency trading C++, Rust │
│ (nanosecond latency) │
│ │
│ Mobile applications Swift (iOS), Kotlin (Android) │
│ │
│ Browser/Frontend JavaScript/TypeScript │
│ │
│ Game engines C++, C# │
│ │
│ ────────────────────────────────────────────────────────────────── │
│ │
│ PYTHON EXCELS AT: │
│ │
│ ✓ Backend services & APIs ✓ DevOps & automation │
│ ✓ Data science & ML ✓ Scientific computing │
│ ✓ Rapid prototyping ✓ Scripting & tooling │
│ ✓ ETL pipelines ✓ Testing frameworks │
│ │
└─────────────────────────────────────────────────────────────────────────┘
The Interview Outcome¶
After my response, the interviewer smiled and said something I’ll remember: “You clearly don’t just use Python—you understand it.”
That’s the difference between a developer and an engineer. Tools are just tools. What matters is understanding:
- Why a tool was designed the way it was
- When to use it versus alternatives
- How to push its limits when needed
Python’s greatest strength isn’t any single feature—it’s the philosophy behind it. A language that prioritizes human readability, developer happiness, and “one obvious way to do things” creates codebases that teams can maintain for years.
Key Takeaways¶
┌─────────────────────────────────────────────────────────────────────────┐
│ Summary: Python's Identity │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Philosophy │ │ Practicality │ │ Evolution │ │
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │
│ │ • Readability │ │ • Batteries │ │ • Type hints │ │
│ │ first │ │ included │ │ • Async/await │ │
│ │ • Explicit > │ │ • Massive │ │ • Pattern │ │
│ │ implicit │ │ ecosystem │ │ matching │ │
│ │ • One obvious │ │ • Quick │ │ • Performance │ │
│ │ way │ │ prototyping │ │ improvements │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ The best tool is the one your team can read, maintain, and ship with. │
│ │
└─────────────────────────────────────────────────────────────────────────┘
References¶
-
Van Rossum, G., & Drake, F. L. (2023). The Python Language Reference. Python Software Foundation. https://docs.python.org/3/reference/
-
PEP 20 – The Zen of Python. Python Enhancement Proposals. https://peps.python.org/pep-0020/
-
PEP 484 – Type Hints. Python Enhancement Proposals. https://peps.python.org/pep-0484/
-
Beazley, D. M. (2010). Understanding the Python GIL. PyCon 2010. https://www.dabeaz.com/python/UnderstandingGIL.pdf
-
The Benchmarks Game. Programming Language Benchmarks. https://benchmarksgame-team.pages.debian.net/benchmarksgame/
-
Python Developer Survey 2023 Results. JetBrains & Python Software Foundation. https://lp.jetbrains.com/python-developers-survey-2023/
-
Lutz, M. (2013). Learning Python (5th ed.). O’Reilly Media.
-
Ramalho, L. (2022). Fluent Python (2nd ed.). O’Reilly Media.
-
PEP 703 – Making the Global Interpreter Lock Optional. Python Enhancement Proposals. https://peps.python.org/pep-0703/
-
Python 3.13 Release Notes – Free-threaded CPython. Python Software Foundation. https://docs.python.org/3.13/whatsnew/3.13.html
Written from the perspective of Software Engineer reflecting on what makes Python unique—not just as a language, but as a way of thinking about code.
Last updated: December 2025