Variables

🐍 Variables & Data Types

Python's approach to variables will feel familiar in concept but different in syntax. The biggest shift from Java is that Python is dynamically typed — but as you'll see, that doesn't mean type information disappears, especially when working with FastAPI.

⚡ Coming from Java / JavaScript No type declarations, no semicolons, no var/let/const. In Python you just write name = "Philip" and Python figures out the type. Unlike JavaScript's var hoisting chaos, Python variables are scoped cleanly to their block. Unlike Java, there are no primitives — everything in Python is an object.

🧱 Core Built-in Types

Python has a small set of built-in types that cover most everyday needs. Collections (list, dict, set, tuple) are introduced briefly here and will each get their own lesson.

Numeric
int & float
Integers have unlimited precision. Floats are IEEE 754 doubles — same as Java's double. No long, no casting needed between int sizes.
# No size limit on int calories = 2000 price = 3.99 big = 10 ** 100 # works fine
Text
str
Immutable, Unicode by default (no char type). Single or double quotes are interchangeable. Triple quotes for multi-line strings.
# All equivalent name = 'Chicken Tikka' name = "Chicken Tikka" desc = """A rich, creamy curry dish."""
Boolean
bool
Capitalised: True / False (not lowercase like JavaScript). bool is actually a subclass of int in Python — True == 1 and False == 0.
is_vegetarian = True is_expired = False # Surprising but valid: print(True + True) # → 2
Null equivalent
None
Python's equivalent of null (Java) or null/undefined (JS). It is its own type — NoneType. Always check with is None, not == None.
expiry_date = None # not set yet if expiry_date is None: print("No expiry set")
Ordered collection
list
Mutable, ordered, allows duplicates. Python's equivalent of ArrayList in Java or a plain array in JS. Can hold mixed types (though in practice, keep them consistent).
ingredients = ["eggs", "milk", "flour"] ingredients.append("butter") first = ingredients[0] # "eggs"
Key-value store
dict
Mutable, ordered (Python 3.7+), key-value pairs. Equivalent to HashMap in Java or a plain object {} in JavaScript. Central to FastAPI — JSON maps directly to dicts.
recipe = { "name": "Pasta", "servings": 4, "vegetarian": True } print(recipe["name"])
Immutable sequence
tuple
Like a list but immutable — can't be changed after creation. Good for fixed data like coordinates or a (day, month) date pair. Slightly faster than lists.
# Immutable pair best_before = (2025, 12, 31) year, month, day = best_before # Unpacking — very Pythonic!
Unique values
set
Unordered, no duplicates. Equivalent to Java's HashSet. Great for checking membership quickly or deduplicating a list of ingredients.
allergens = {"gluten", "dairy", "nuts"} allergens.add("eggs") if "nuts" in allergens: print("Contains nuts!")

🏷️ Type Hints — Optional but Important

Python is dynamically typed, but since Python 3.5 you can add optional type annotations. These don't affect runtime behaviour — but FastAPI uses them heavily to validate data, generate API docs, and power editor autocomplete.

🚀 FastAPI relevance — HIGH Type hints are not optional in FastAPI — they are how FastAPI works. FastAPI reads your type annotations to automatically validate request data, convert types, and generate interactive API documentation (Swagger UI). Learning type hints now will make FastAPI feel natural from day one.
Type Hints — Basic Syntax
Add a colon after the variable name for annotations. Use -> for function return types. Python won't enforce these at runtime, but tools and FastAPI will.
# Without type hints (still valid Python) name = "Philip" age = 30 # With type hints (same at runtime, but much more useful) name: str = "Philip" age: int = 30 price: float = 9.99 is_available: bool = True notes: str | None = None # Python 3.10+ — optional string # Function with type hints — this is what FastAPI endpoints look like def get_recipe(recipe_id: int, include_nutrition: bool = False) -> str: return f"Recipe {recipe_id}"
Type Hints with Collections
Use list[type], dict[key, value] etc. to annotate collections. Import Optional from typing for Python < 3.10.
from typing import Optional # needed for Python < 3.10 # List of strings ingredients: list[str] = ["flour", "eggs", "milk"] # Dict with string keys and int values stock: dict[str, int] = {"eggs": 6, "milk": 2} # Optional value — can be str or None description: Optional[str] = None # Python < 3.10 description: str | None = None # Python 3.10+

💬 F-Strings & Dynamic Typing in Practice

F-Strings — Python's Template Literals
F-strings (formatted string literals) work like JavaScript's template literals — prefix with f and use {} for expressions. Far cleaner than Java's String.format().
item = "Milk" quantity = 3 expiry = "2025-08-01" # Simple interpolation print(f"{item} — quantity: {quantity}") # → Milk — quantity: 3 # Expressions inside {} print(f"{item.upper()} expires: {expiry}") # → MILK expires: 2025-08-01 # Formatting numbers price = 2.5 print(f"Price: £{price:.2f}") # → Price: £2.50
Dynamic Typing — and How to Check Types
Variables can change type at runtime (though this is usually bad practice). Use type() to inspect and isinstance() to check — prefer isinstance() as it handles inheritance.
# type() — returns the type object print(type("hello")) # <class 'str'> print(type(42)) # <class 'int'> print(type([1, 2, 3])) # <class 'list'> # isinstance() — preferred for type checking quantity = 5 if isinstance(quantity, int): print("Valid quantity") # Check multiple types at once value = 3.14 if isinstance(value, (int, float)): print("It's a number")
Multiple Assignment & Unpacking
Python allows elegant multiple assignment and tuple unpacking — you'll see this constantly in real Python code.
# Multiple assignment on one line name, quantity, unit = "Rice", 500, "grams" # Swap values — no temp variable needed (unlike Java) a, b = 1, 2 a, b = b, a # a=2, b=1 — very Pythonic # Unpack a list first, *rest = ["eggs", "milk", "flour", "butter"] # first = "eggs", rest = ["milk", "flour", "butter"] # Underscore _ for values you don't need _, month, day = (2025, 8, 15) print(f"Day: {day}, Month: {month}")
Constants — Convention, Not Enforcement
Python has no final or const keyword. The convention is UPPER_SNAKE_CASE for constants — Python won't stop you changing them, but it signals intent to other developers (and your future self).
# Convention: UPPER_CASE = constant (not enforced by Python) MAX_INGREDIENTS = 50 DEFAULT_SERVINGS = 4 DATABASE_URL = "postgresql://localhost/mealplanner" DAYS_BEFORE_EXPIRY_ALERT = 3 # For true constants in larger projects, use an enum: from enum import Enum class MealType(Enum): BREAKFAST = "breakfast" LUNCH = "lunch" DINNER = "dinner" meal = MealType.DINNER print(meal.value) # → "dinner"

📋 Quick Reference

TypeExampleJava equivalentNotes
intage = 30int / longUnlimited precision — no overflow
floatprice = 9.99doubleIEEE 754 — same precision as Java double
strname = "Pasta"StringImmutable, Unicode, no char type
booldone = TruebooleanCapitalised True/False — subclass of int
Noneval = NonenullCheck with is None, not == None
list[1, 2, 3]ArrayListMutable, ordered, allows duplicates
dict{"key": "val"}HashMapMutable, ordered (3.7+), JSON-like
tuple(1, 2, 3)Immutable list — great for fixed data
set{1, 2, 3}HashSetUnordered, unique values only
f-stringf"Hi {name}"String.format()Expressions allowed inside {}
type hintx: int = 5type declarationOptional but required for FastAPI
type(x)type(42)intx.getClass()Returns the type object
isinstance()isinstance(x, int)instanceofPreferred for type checking
⚠ Gotchas for Java / JavaScript Programmers:

Mutable default arguments — never use a mutable object (list, dict) as a default function argument. def add(item, items=[]) shares the same list across all calls. Use None and create inside the function instead.

== vs is== checks value equality (like Java's .equals()); is checks identity (same object in memory, like Java's == for objects). Always use is None and is not None, never == None.

Integers are cached — Python caches small integers (-5 to 256), so a = 100; b = 100; a is b returns True. For larger integers it won't. This is a curiosity, not something to rely on.

No ++ operator — use x += 1 instead of x++. Python has no increment/decrement operator at all.