I Gave Python a Shot (And Here's What I Learned)
Six or seven years ago, Python and I had a very short, very polite relationship. Class 11. Basics. Exams. Goodbye. Then life happened. JavaScript happened. Startups happened. Until last month, when I picked it up again for an ETL project. Here's what I learned.
Published on January 20, 2025

Table of contents
- The Short Relationship
- Picking It Up Again
- Refreshing the Basics
- Indentation: The Surprise
- Named Arguments: Delight
- Standard Library: Quiet Flex
- Dataframes: Thinking in Tables
- Understanding JavaScript Better
- Tooling: From Chaos to Order
- FastAPI: The Smile Moment
- SQLAlchemy: Trust Broke
- The Pattern: Friction Reduction
- Zed Editor and DSAs
- Clarification, Not Replacement
The Short Relationship
Six or seven years ago, Python and I had a very short, very polite relationship.
Class 11. Basics. Exams. Goodbye.
Then life happened. JavaScript happened. Startups happened. APIs, infra, deadlines, production fires. Python stayed untouched — not rejected, just… irrelevant.
Until last month.
Picking It Up Again
I was building an ETL project. Real data. Ugly CSVs. Files that looked like they were generated by chaos itself. I needed dataframes, analytics, something that wouldn't fight me while I was trying to move data from A to B and maybe make some money along the way.
So I picked up Python again.
Not casually. Properly.
Refreshing the Basics
I spent the first week just refreshing basics — arithmetic, conditionals, functions, classes, dunder methods, packages, modules. Stuff I technically “knew” but had never truly used back when it was exam material. This time, it landed differently.
Classes stopped feeling academic. Dunder methods stopped feeling like spells. They felt like agreements. Clear, intentional behavior. Python wasn't being magical — it was being honest.
Even revisiting basics like dunder methods felt different this time.
class Job:
def __init__(self, name: str):
self.name = name
def __str__(self):
return f"Job({self.name})"Not magic. Just clearly defined behavior.
Indentation: The Surprise
I went in fully prepared to hate indentation. No curly braces felt illegal at first. Years of muscle memory screaming for {}. But weirdly… it didn't bother me.
After a few days, indentation stopped being something I noticed and started being something that helped. The code looked exactly how it ran. No hidden scope. No surprises. If it was ugly, it looked ugly. Fair enough.
Named Arguments: Delight
Then there were named arguments.
This one genuinely delighted me.
Calling a function and saying exactly what I meant — without wrapping everything into an object just to keep my sanity — felt like relief. The intent sat right there at the call site. No guessing. No scrolling. No mental tax. Clarity, by default.
def process_data(limit: int, retry: bool, timeout: int):
...
process_data(limit=100, retry=True, timeout=5)No object wrapping gymnastics. No guessing argument order. The call site tells the truth about what's happening.
Standard Library: Quiet Flex
And the standard library?
That was a quiet flex.
Math, dates, time, decimals, statistics — things I usually patch together in JavaScript with libraries and prayers — were just… there. Python felt like a language that had seen real-world problems and decided to help instead of staying minimal for philosophical reasons.
Dataframes: Thinking in Tables
That's when dataframes entered the picture.
Pandas made me stop thinking in loops and start thinking in tables. Polars felt sharp and opinionated. DuckDB felt straight-up illegal — analytical SQL, locally, directly on files, without spinning up infra or begging for permissions. Suddenly, ETL didn't feel like plumbing. It felt like asking good questions and getting fast answers.
Working with DuckDB felt borderline unfair.
import duckdb
con = duckdb.connect()
df = con.execute("""
SELECT country, COUNT(*) as users
FROM 'users.csv'
GROUP BY country
""").df()No server. No setup. Just SQL on a file, locally, fast enough to make you suspicious.
And with Polars, dataframes finally felt sharp instead of bloated.
import polars as pl
df = pl.read_csv("events.csv")
result = (
df
.filter(pl.col("status") == "success")
.group_by("type")
.count()
)No loops. No mutation soup. Just transformations that read like intent.
Understanding JavaScript Better
Somewhere in this process, something unexpected happened.
Python made me understand JavaScript better.
Coming back to a synchronous, predictable execution model made the JS event loop finally click. The call stack stopped being abstract. Async stopped feeling random. The contrast clarified everything. Python gave me calm. JavaScript showed me chaos — but intentional chaos. I stopped blaming myself for async bugs and started respecting the environment JS operates in.
Tooling: From Chaos to Order
Then came tooling.
At first, pip scared me. Global installs everywhere. One project breaking another. Pure anxiety. Then I found venv, and order was restored. Isolated environments. Clear boundaries. Sanity.
And then… uv.
As a JS dev raised on npm and lock files, this felt like home. Fast installs. Deterministic behavior. Reproducibility without rituals. It removed a kind of background stress I didn't even realise I was carrying.
Environment sanity check — venv + uv, the combo that saved my mental health.
python -m venv .venv
source .venv/bin/activate
uv pip install fastapi polars duckdbLocked. Isolated. Reproducible. As a JS dev, this finally felt… civilized.
FastAPI: The Smile Moment
FastAPI was the moment I genuinely smiled.
This was literally my FastAPI hello world. No generator. No scaffolding sermon.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def hello():
return {"message": "hello"}That's it. No hidden magic. No “you'll understand this later.” You read it once and your brain says: okay, I get it.
Then came Pydantic, where my inner TypeScript dev finally relaxed.
from pydantic import BaseModel
class User(BaseModel):
id: int
email: str
is_active: bool = TruePass bad data into this and it doesn't “kinda work.” It fails. Immediately. Loudly. At the boundary.
That's not strictness — that's respect for production.
No drama. No ceremony. No “enterprise-ready” lecture before hello world. Just trust. And quietly — validation, typing, OpenAPI docs, async support — all there when needed. It felt designed by people who had shipped under pressure and remembered what friction costs.
SQLAlchemy: Trust Broke
And then… SQLAlchemy.
That trust broke a little.
Powerful? Absolutely.
Developer-friendly? Not immediately.
It felt like it wanted me to understand databases as a concept before letting me save a row. Sessions, engines, mappers — a lot of abstraction before momentum. Not bad. Just heavy. Especially after tools that had been working so hard to stay out of my way.
The Pattern: Friction Reduction
At that point, the pattern was obvious.
The tools I enjoyed most weren't the fanciest.
They were the ones that reduced friction.
Polars. DuckDB. Pydantic. FastAPI. uv.
They didn't try to impress me. They tried to unblock me.
None of this code is impressive on its own.
That's the point.
It's boring in the best way — the “this will work at 2 a.m.” way.
Python didn't make me feel smarter. It made me feel calmer.
And when your tools stop fighting you, you stop wasting time proving things — and start shipping things that earn their keep.
Zed Editor and DSAs
I even gave Zed editor an honest shot — no AI, no copilots. Just me and the code. It felt uncomfortable at first. Then strangely calming. I started thinking more before typing. Writing less junk. Being more deliberate.

Alongside all this, I started revisiting DSAs. Not for interviews. Not for flexing. Just to sharpen instincts. To understand why things are fast, slow, expensive, or elegant. Quiet confidence, not loud preparation.
Clarification, Not Replacement
This whole Python journey didn't replace JavaScript for me.
It clarified it.
It didn't make me obsessed with theory.
It made me obsessed with outcomes.
Python didn't make me feel clever.
It made me feel effective.
And that's the biggest compliment I can give a tool.
I'm still learning. Still breaking things. Still discovering sharp edges. But this has been one of the most satisfying learning curves I've had in a while — not because it's trendy, but because it's practical.
I'll keep sharing updates as I go.
And if any of this resonated — if you're juggling stacks, questioning tools, or just trying to ship without losing your sanity — reach out to me over email.
Because at the end of the day, software has only one real job:
To work.
And to earn its keep.