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
| Type | Example | Java equivalent | Notes |
|---|---|---|---|
int | age = 30 | int / long | Unlimited precision — no overflow |
float | price = 9.99 | double | IEEE 754 — same precision as Java double |
str | name = "Pasta" | String | Immutable, Unicode, no char type |
bool | done = True | boolean | Capitalised True/False — subclass of int |
None | val = None | null | Check with is None, not == None |
list | [1, 2, 3] | ArrayList | Mutable, ordered, allows duplicates |
dict | {"key": "val"} | HashMap | Mutable, ordered (3.7+), JSON-like |
tuple | (1, 2, 3) | — | Immutable list — great for fixed data |
set | {1, 2, 3} | HashSet | Unordered, unique values only |
| f-string | f"Hi {name}" | String.format() | Expressions allowed inside {} |
| type hint | x: int = 5 | type declaration | Optional but required for FastAPI |
type(x) | type(42) → int | x.getClass() | Returns the type object |
isinstance() | isinstance(x, int) | instanceof | Preferred for type checking |
⚠ Gotchas for Java / JavaScript Programmers:
Mutable default arguments — never use a mutable object (list, dict) as a default function argument.
== vs is —
Integers are cached — Python caches small integers (-5 to 256), so
No
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.