Python for JavaScript Devs: A Side-by-Side Syntax and Toolchain Map
Frontend Developers Quickly Getting Started with Python
I have some previous Python development experience, but I haven't written it much for two or three years. Recently, while working on some AI-related projects, I've been using Python frequently. As a frontend developer, I don't want to spend a lot of time learning Python from scratch, so I plan to quickly get up to speed by comparing frontend and Python syntax. This analogical learning approach can be applied in many fields beyond just learning Python. Besides introducing how to quickly pick up Python, the more important point of this article is to share this rapid learning mindset.
Small print reminder: This sharing is just a quick-start, basic introduction, not anything advanced. Experts, please go easy. I will also continue to supplement this sharing during my learning process.
Preface
Python and JavaScript are actually very similar; both are weakly typed languages, and their ecosystems share many similarities. My habit is that whenever I want to achieve a certain effect during Python development, I first think about it using a frontend mindset.
For example, in frontend development, I can quickly switch between multiple Node.js versions using nvm to flexibly run projects with different versions. How is this done in Python projects? Answer: pyenv or conda.
Another example: In frontend, third-party packages are referenced and managed through npm. How is this done in Python projects? Answer: pip.
Or a reverse analogy: What are Python lists and dictionaries? A Python list can be understood as an array in JavaScript, and a dictionary is like an object in JavaScript.
With this kind of analogy, you'll find that frontend developers actually don't need to spend a lot of time learning to quickly get started with Python. You can perfectly well learn while developing.
1. Environment and Toolchain
1.1 Environment Installation
Frontend uses nvm to manage multiple Node.js versions. The Python ecosystem has two mainstream solutions: the built-in venv and anaconda (I habitually use anaconda). So, I'll first introduce the installation of anaconda here. Personally, I don't recommend installing Python directly, just as I don't recommend installing Node directly for frontend development; instead, I recommend installing version management tools like nvm.
If you don't like using anaconda, you can also choose to use venv. Here is some comparison content:
Download from the Anaconda official website
Download and install directly from the official website. Anaconda has two versions: a full version and a mini version. If you are not a heavy user, my suggestion is to download miniconda, which is sufficient. After downloading, you can use the following commands:
# Create an environment with a specified Python version, equivalent to nvm's `nvm install v20.xx.xx` for installing a version
conda create -n myenv python=3.12
# Activate environment (analogous to nvm use), equivalent to `nvm use xxx` version
conda activate myenv
# Deactivate environment
conda deactivate
# List all environments, equivalent to `nvm list`
conda env list
# Export environment (analogous to package.json + node version lock)
conda env export > environment.yml
# Restore environment from file
conda env create -f environment.yml
Note:
The commands above use nvm for analogy. It's also necessary to supplement the differences from nvm. Conda's environment activation is terminal-specific. For example, when you open a terminal and execute conda activate myenv, the next time you open a terminal, you will still need to activate it again. It's a one-time effect, unlike nvm, where after executing nvm use xxx, the global node version is switched.
If you must set the Python version globally like nvm, find conda's installation directory, locate the Python executable for the specified version, and add it to your global environment variables.
1.2 Core Tool Comparison Table
| Python Ecosystem | Node.js Ecosystem | Description |
|---|---|---|
python |
node |
Runtime |
pip |
npm |
Package manager |
conda / pyenv |
nvm / fnm |
Version management tool |
pip install xxx |
npm install xxx |
Install dependency package |
pip uninstall xxx |
npm uninstall xxx |
Uninstall dependency package |
pip freeze > requirements.txt |
npm ls --depth=0 |
Export currently installed packages |
requirements.txt |
package.json |
Project dependency manifest (simple scenario) |
pyproject.toml |
package.json |
Project dependency manifest (standard scenario) |
pip install -r requirements.txt |
npm install |
Install all dependencies from manifest |
python -m venv .venv |
npm install (creates node_modules) |
Initialize project local dependency environment |
.venv/ |
node_modules/ |
Project local dependency directory |
python --version |
node --version |
Check runtime version |
pip --version |
npm --version |
Check package manager version |
python script.py |
node script.js |
Run script |
python -i |
node (REPL) |
Interactive interpreter |
which python |
which node |
Check current interpreter path |
1.3 Virtual Environment ↔ node_modules
Core Analogy:
Node.js: Project root/node_modules/ ← Generated after npm install, local dependencies
Python: Project root/.venv/ ← Generated after python -m venv .venv, local interpreter + dependencies
The difference is that Python's virtual environment not only isolates dependencies but also isolates the Python interpreter itself and pip. Each project has a completely independent copy of Python.
# Create virtual environment (analogous to the effect of npm init + npm install)
python -m venv .venv
# Activate virtual environment (Windows)
.venv\Scripts\activate
# Activate virtual environment (macOS / Linux)
source .venv/bin/activate
# After activation, `which python` will point to the Python in .venv/
# Packages installed via pip will also only be installed into .venv/
# Deactivate virtual environment
deactivate
Frontend Habit Analogy: Activating venv ≈ entering an npm workspaces sub-package directory; npm install will only affect the current workspace.
2. Basic Syntax Comparison
2.1 Variables and Basic Types
# ---------- Python ---------- # ---------- JavaScript ----------
# Variable declaration (no need for let/const/var)
name = "hello" # let name = "hello";
count = 42 # let count = 42;
PI = 3.14 # const PI = 3.14;
is_done = True # let isDone = true;
nothing = None # let nothing = null; (None ≈ null)
# Type checking
type(name) # <class 'str'> # typeof name // 'string'
isinstance(name, str) # True # name instanceof String // false (primitive type)
2.2 Strings
# ---------- Python ---------- # ---------- JavaScript ----------
name = "Alice"
f"Hello, {name}!" # `Hello, ${name}!`
"Hello, {}!".format(name) # "Hello, " + name + "!"
# Multi-line strings
text = """ # const text = `
Multi-line # Multi-line
text # text
""" # `;
# Common methods
"hello".upper() # "HELLO" # "hello".toUpperCase()
"HELLO".lower() # "hello" # "HELLO".toLowerCase()
" hi ".strip() # "hi" # " hi ".trim()
"a,b,c".split(",") # ['a','b','c'] # "a,b,c".split(",")
",".join(["a","b","c"]) # "a,b,c" # ["a","b","c"].join(",")
"abc".startswith("a") # True # "abc".startsWith("a")
"abc".endswith("c") # True # "abc".endsWith("c")
"hello" in "hello world" # True # "hello world".includes("hello")
len("hello") # 5 # "hello".length
2.3 Numbers and Booleans
# ---------- Python ---------- # ---------- JavaScript ----------
# Operations are the same: + - * / // (floor division) % **
10 / 3 # 3.333... # 10 / 3 // 3.333...
10 // 3 # 3 (floor division) # Math.floor(10 / 3) // 3
10 % 3 # 1 # 10 % 3 // 1
2 ** 10 # 1024 # 2 ** 10 // 1024
# Booleans (note capitalization)
True, False # true, false
not True # False # !true
True and False # False # true && false
True or False # True # true || false
# "Falsy" values in boolean context (Python is stricter)
# Falsy: False, None, 0, 0.0, "", [], {}, set(), ()
# Note: [] and {} are falsy in Python — use `if my_list:` directly to check
2.4 Lists ↔ Arrays
# ---------- Python ---------- # ---------- JavaScript ----------
items = [1, 2, 3] # const items = [1, 2, 3];
items[0] # 1 # items[0]
items[-1] # 3 (last element) # items[items.length - 1]
items[0:2] # [1, 2] (slicing) # items.slice(0, 2)
# Common operations
items.append(4) # [1,2,3,4] # items.push(4)
items.pop() # 4, items becomes [1,2,3] # items.pop()
items.insert(0, 0) # [0,1,2,3] # items.unshift(0)
items.remove(2) # [0,1,3] # No direct equivalent method, need splice+indexOf
len(items) # 3 # items.length
3 in items # True # items.includes(3)
# List comprehensions (one of Python's most practical syntax sugars)
[x*2 for x in range(5)] # [0,2,4,6,8] # [0,1,2,3,4].map(x => x*2)
[x for x in range(10) if x % 2 == 0] # [0,2,4,6,8] # Equivalent to .filter().map()
2.5 Dictionaries ↔ Objects / Map
# ---------- Python ---------- # ---------- JavaScript ----------
user = { # const user = {
"name": "Alice", # name: "Alice",
"age": 25 # age: 25
} # };
user["name"] # "Alice" # user["name"] or user.name
user.get("name") # "Alice" # user?.name
user.get("email", "N/A") # "N/A" # user.email ?? "N/A"
# Iteration
for key in user: # for (const key in user)
print(key, user[key]) # console.log(key, user[key])
for key, val in user.items(): # for (const [key, val] of Object.entries(user))
print(key, val) # console.log(key, val)
# Merging dictionaries
{**a, **b} # Python 3.5+ # { ...a, ...b }
a | b # Python 3.9+ # { ...a, ...b }
# keys / values
user.keys() # dict_keys # Object.keys(user)
user.values() # dict_values # Object.values(user)
2.6 Tuples ↔ Immutable Arrays (readonly tuple)
# ---------- Python ---------- # ---------- TypeScript ----------
point = (3, 4) # const point: [number, number] = [3, 4];
x, y = point # Destructuring # const [x, y] = point;
# Tuples are immutable
# point[0] = 5 # ❌ Error # point[0] = 5; // JS arrays can be modified...
# Single-element tuple note the comma
single = (42,) # Comma is required, otherwise (42) is just the number 42
2.7 Sets ↔ Set
# ---------- Python ---------- # ---------- JavaScript ----------
tags = {"a", "b", "c"} # const tags = new Set(["a", "b", "c"]);
tags.add("d") # tags.add("d")
"a" in tags # True # tags.has("a")
# Set operations
a = {1, 2, 3}
b = {2, 3, 4}
a & b # {2, 3} Intersection # No built-in intersection operation
a | b # {1,2,3,4} Union #
a - b # {1} Difference #
2.8 Control Flow
# ---------- Python ---------- # ---------- JavaScript ----------
# if / elif / else
if score >= 90: # if (score >= 90) {
grade = "A" # grade = "A";
elif score >= 80: # } else if (score >= 80) {
grade = "B" # grade = "B";
else: # } else {
grade = "C" # grade = "C";
# }
# Ternary expression
x = "yes" if ok else "no" # const x = ok ? "yes" : "no";
# for loop (Python's for only iterates, not C-style three-part)
for item in items: # for (const item of items)
print(item) # console.log(item);
for i in range(5): # for (let i = 0; i < 5; i++)
print(i) # console.log(i);
for i, val in enumerate(items): # items.forEach((val, i) => { ... })
print(i, val)
# while
while count > 0: # while (count > 0) {
count -= 1 # count--;
# }
# No do-while, no switch-case (Python 3.10 introduced match-case similar to switch)
match status:
case 200:
print("OK")
case 404:
print("Not Found")
case _: # default
print("Unknown")
2.9 Functions
# ---------- Python ---------- # ---------- JavaScript ----------
def greet(name): # function greet(name) {
return f"Hello, {name}" # return `Hello, ${name}`;
# }
# Default parameters
def greet(name="World"): # function greet(name = "World") {
return f"Hello, {name}" # return `Hello, ${name}`;
# }
# Variadic parameters *args ↔ ...rest
def sum_all(*args): # function sumAll(...args) {
return sum(args) # return args.reduce((a,b) => a+b, 0);
# }
# Keyword arguments **kwargs ↔ object destructuring
def create_user(**kwargs): # function createUser({ name, age } = {}) {
print(kwargs.get("name")) # console.log(name);
# }
# Anonymous functions lambda ↔ arrow functions
square = lambda x: x * x # const square = x => x * x;
# Common use case: sort key
items.sort(key=lambda x: x["age"]) # items.sort((a, b) => a.age - b.age);
# No hoisting! Functions must be defined before they are called
2.10 Exception Handling
# ---------- Python ---------- # ---------- JavaScript ----------
try: # try {
result = 10 / 0 # const result = 10 / 0;
except ZeroDivisionError as e: # } catch (e) {
print(f"Division by zero error: {e}") # console.log(`Error: ${e.message}`);
except Exception as e: # }
print(f"Other error: {e}") # // JS can only catch one, need instanceof to differentiate
else: # // Python-specific else: executes when no exception occurs
print("Everything is fine")
finally: # } finally {
print("Executes whether there is an exception or not") # console.log("finally");
# }
# Raise exception
raise ValueError("Invalid parameter") # throw new Error("Invalid parameter");
2.11 Classes
# ---------- Python ---------- # ---------- JavaScript ----------
class Animal: # class Animal {
def __init__(self, name): # constructor(name) {
self.name = name # this.name = name;
# }
def speak(self): # speak() {
return f"{self.name}..." # return `${this.name}...`;
# }
# }
class Dog(Animal): # class Dog extends Animal {
def __init__(self, name, breed): # constructor(name, breed) {
super().__init__(name) # super(name);
self.breed = breed # this.breed = breed;
# }
def speak(self): # speak() {
return f"{self.name} woof" # return `${this.name} woof`;
# }
# }
# All methods require the self parameter (analogous to JS's this, but explicitly passed)
# Private attribute convention: prefix _ or __
# self._secret = 1 # Conventionally private (analogous to JS _secret convention)
# self.__private = 1 # Name mangling, truly private (but can be bypassed)
3. Modules and Package Management
3.1 import ↔ require / import
# ---------- Python ---------- # ---------- JavaScript ----------
# Import entire module
import os # const os = require("os");
os.path.join("a", "b") # os.path.join("a", "b")
# Import specific content
from os import path # const { join } = require("path");
from os.path import join, exists # const { join, exists } = require("path");
# Alias
import numpy as np # const np = require("numpy"); // No native alias support
from math import sqrt as sq # // JS requires manual: const sq = Math.sqrt;
# Import all (not recommended, pollutes namespace)
from math import * # // No direct equivalent in JS
3.2 Package Management Comparison
| Python | Node.js | Description |
|---|---|---|
pip install requests |
npm install axios |
Install and write to dependencies |
pip install requests==2.28 |
npm install [email protected] |
Install specific version |
requirements.txt |
package.json (dependencies) |
Project dependency manifest |
pip freeze |
npm ls --depth=0 |
View installed packages |
pip install -r requirements.txt |
npm install |
Install from manifest |
.venv/ |
node_modules/ |
Local dependency directory |
pip list |
npm list --depth=0 |
List installed packages |
pip uninstall requests |
npm uninstall axios |
Uninstall package |
3.3 pyproject.toml (Modern Python Project Standard)
Earlier, requirements.txt was used as an analogy for package.json, but a more accurate comparison is pyproject.toml:
# pyproject.toml # package.json
[project] # {
name = "my-project" # "name": "my-project",
version = "1.0.0" # "version": "1.0.0",
dependencies = [ # "dependencies": {
"fastapi>=0.100", # "fastapi": "^0.100",
"uvicorn>=0.23", # "uvicorn": "^0.23"
] # },
#
[project.optional-dependencies] # "devDependencies": {
dev = [ # "pytest": "^7.0",
"pytest>=7.0", # "ruff": "^0.1"
"ruff>=0.1", # }
] # }
[tool.pytest.ini_options] # // jest config is usually in jest.config.js
testpaths = ["tests"] #
4. Common Standard Library Quick Reference
Python "comes with batteries included" — the standard library is much richer than Node.js's, often eliminating the need for third-party packages.
4.1 File and Path Operations
| Python (Standard Library) | Node.js (Standard Library) |
|---|---|
import os |
require("os") |
os.path.join("a", "b") |
path.join("a", "b") |
os.path.dirname(p) |
path.dirname(p) |
os.path.basename(p) |
path.basename(p) |
os.path.exists(p) |
fs.existsSync(p) |
os.makedirs("a/b", exist_ok=True) |
fs.mkdirSync("a/b", { recursive: true }) |
os.listdir(".") |
fs.readdirSync(".") |
For file reading and writing, pathlib (Python 3.4+, more modern) is recommended:
from pathlib import Path
# Path joining (analogous to path.join)
p = Path("src") / "app" / "main.py" # src/app/main.py
# Read and write files
text = Path("file.txt").read_text(encoding="utf-8")
Path("file.txt").write_text("hello", encoding="utf-8")
# Traverse directory (analogous to fs.readdirSync recursive)
for f in Path("src").rglob("*.py"):
print(f)
5. Project Structure
5.1 Typical Project Layout Comparison
Node.js Project:
my-project/
├── node_modules/ # Dependencies
├── src/
│ ├── routes/
│ ├── services/
│ └── index.js # Entry point
├── package.json
├── .env
├── .gitignore
└── README.md
Python Project:
my-project/
├── .venv/ # Dependencies (analogous to node_modules)
├── src/ # Source code (or use package name)
│ ├── __init__.py # Marks as a package (analogous to package.json's "main" + ESM)
│ ├── routes/
│ │ ├── __init__.py
│ │ └── users.py
│ ├── services/
│ │ ├── __init__.py
│ │ └── user_service.py
│ └── main.py # Entry point
├── tests/
│ ├── __init__.py
│ └── test_users.py
├── pyproject.toml # Project configuration (analogous to package.json)
├── requirements.txt # Dependency manifest (old style, still common)
├── .env
├── .gitignore
└── README.md
5.2 __init__.py ↔ package.json exports
__init__.py indicates that the current directory is a package, similar to how a directory in Node.js containing a package.json or index.js identifies it as a module entry point. Python 3.3+ supports implicit namespace packages (can exist without __init__.py), but it's customary to keep it, especially when there is initialization logic.
6. Asynchronous Programming
6.1 Core Concept Comparison
| Python | JavaScript |
|---|---|
async def |
async function |
await |
await |
asyncio.run(main()) |
main().catch(console.error) |
asyncio.gather(*tasks) |
Promise.all(tasks) |
asyncio.create_task() |
Directly fn() returns a Promise |
asyncio.sleep(1) |
setTimeout + Promise |
| Coroutine | Promise |
| Event Loop | Event Loop (libuv) |
6.2 Code Comparison
# ---------- Python ---------- # ---------- JavaScript ----------
import asyncio #
#
async def fetch_user(id: int): # async function fetchUser(id) {
await asyncio.sleep(1) # await new Promise(r => setTimeout(r, 1000));
return {"id": id, "name": "A"} # return { id, name: "A" };
# }
async def main(): # async function main() {
# Concurrent execution #
users = await asyncio.gather( # const users = await Promise.all([
fetch_user(1), # fetchUser(1),
fetch_user(2), # fetchUser(2),
) # ]);
print(users) # console.log(users);
# }
asyncio.run(main()) # main();
6.3 Key Differences
| Difference Point | Python | JavaScript |
|---|---|---|
| Coroutine start method | Does not automatically execute before await call |
Promise starts executing upon creation, await just waits for the result |
| Top-level await | Wrapped by asyncio.run() |
Node/Deno natively supports top-level await |
| Concurrency model | Single-threaded + coroutines (truly only one thread running) | Single-threaded + event loop (same) |
| CPU-intensive tasks | Requires multiprocessing or thread pool |
Requires Worker Threads |
| Web framework async support | FastAPI / aiohttp / Sanic (mature) | Express itself is not natively async, Koa is async-first |
7. Build and Deployment
7.1 Bundling vs Non-bundling
Node.js projects are usually bundled (Webpack/Vite/esbuild) before deployment, while Python projects generally do not bundle — deploy source code + dependencies directly.
| Node.js | Python |
|---|---|
npm run build → dist/ |
No build step, deploy source code directly |
| Webpack / Vite / esbuild | No bundler (or compile with Cython/Nuitka) |
.js/.ts → .min.js minified bundle |
.py runs directly |
7.2 Dependency Management (Production)
# Node.js
npm ci --production # Strictly install according to lock file, only install dependencies
# Python
pip install -r requirements.txt # Install all dependencies
# Or use pip-tools to generate precisely locked requirements.txt
pip-compile pyproject.toml # Generate requirements.txt (with exact versions of all transitive dependencies)
pip install -r requirements.txt # Install according to locked versions
7.3 Common Deployment Methods
| Method | Node.js | Python |
|---|---|---|
| Direct run | node server.js |
python app.py |
| Process daemon | PM2 | systemd / supervisor |
| Reverse proxy + WSGI/ASGI | nginx → node | nginx → gunicorn/uvicorn → app |
| Containerization | Docker | Docker |
| Serverless | AWS Lambda / Vercel | AWS Lambda / Google Cloud Functions |
Analogy Summary
When switching from Node.js to Python, just remember these points:
- Indentation is curly braces — Python uses indentation to define code blocks, forget about
{}. - venv ≈ node_modules + an independent copy of node — Isolated per project.
pip install -r requirements.txt≈npm install— Install dependencies.pyproject.toml≈package.json— Project configuration (modern way).defdefines functions,classdefines classes — Same as JS, but syntax slightly differs.- Python comes with batteries included — The standard library is extremely rich; check the standard library first when you need something.
- Type annotations are optional but highly recommended — Combined with Pydantic, Python can have runtime safety far exceeding TS.
- No bundling, deploy source code directly — Say goodbye to Webpack/Vite.
uv pip install xxxis faster and more modern — Analogous topnpm add xxx.
Mindset Summary
This learning method is for when you want to get up to speed quickly. When you need to become an expert in a certain field, I still hope that after getting started, you can maintain a humble attitude, study and learn more, and solidify your foundation.
The analogical learning method is just to help everyone get started quickly, get feedback quickly, and make it easier to persist. Otherwise, for programmers, with so many languages, how much time would it take to learn several more? Moreover, you don't necessarily need to be proficient in every language at work. We only need to be proficient in the ones we commonly use at work, and then use analogical learning for other languages.
Top 1 from juejin.cn, machine-translated. The original thread is authoritative.
Great article, thanks for sharing.