Variables without let or const
Byte: You already know how to program. This is just a new accent.
Python has no let, const or var. You assign with = and the name exists. Types are still dynamic, like JavaScript.
Backend code adds type hints after a colon. Python itself doesn't enforce them, but FastAPI and Pydantic read them to validate data, which is why you'll see them everywhere in this city.
name = "Neo" # like: let name = "Neo"age: int = 25 # type hint: age should be an intis_admin: bool = False # True / False are capitalisednothing = None # Python's null
Quick check: Which line is valid Python?
let age = 25age = 25const age = 25
Python has no declaration keyword. age = 25 creates the variable.
Dicts are objects, lists are arrays
Byte: JSON maps straight onto these two.
A dict is Python's version of a JavaScript object, and a list is an array. A JSON request body becomes dicts and lists.
One big difference: you read dict keys with square brackets and quotes. Dot access (user.name) works on objects and classes, not on dicts.
user = {"name": "Neo", "roles": ["admin", "editor"]}user["name"] # "Neo"user["roles"][0] # "admin"len(user["roles"]) # 2 (like .length)
Quick check: With user = {"name": "Neo"}, how do you read the name?
user.nameuser["name"]
Dicts use square brackets. user.name would raise an AttributeError.
Functions and indentation
Byte: Indentation is the braces.
Functions start with def, and the body is whatever is indented under the colon. There are no curly braces, so indentation is part of the syntax: four spaces per level.
if, for and class work the same way: a colon, then an indented block.
def greet(name: str) -> str:if name == "":return "Hello, stranger"return f"Hello, {name}" # f-string, like `Hello, ${name}`
Quick check: What marks where a Python function body ends?
- A closing curly brace
- The indentation going back out
- The word end
When the indentation returns to the outer level, the block is over.
Classes with type hints
Byte: Pydantic models are just classes like these.
A class groups data and behaviour. In backend code you'll often write classes that are mostly a list of typed fields. That's exactly what a Pydantic model is.
BaseModel in the brackets means the class extends it, like class User extends BaseModel in JavaScript.
from pydantic import BaseModelclass User(BaseModel): # extends BaseModelname: strage: intneo = User(name="Neo", age=25)neo.name # "Neo" (dot access works on classes)
Quick check: In class User(BaseModel):, what is BaseModel?
- A parameter passed to User
- The class User extends
- A decorator
The brackets after a class name list what it inherits from.
async and await
Byte: Same idea as in JavaScript.
Python has async functions and await, and they mean what you expect: wait for slow work (a database, a network call) without blocking the server.
FastAPI route handlers are usually async def. You'll see them in every district from here on.
@app.get("/users/{user_id}")async def get_user(user_id: int):user = await db.fetch_user(user_id) # like: await db.fetchUser(id)return user
Quick check: What is async def closest to in JavaScript?
- async function
- new Promise
- setTimeout
An async def function returns something you can await, just like an async function.