Python Fundamentals
A working reference for the core building blocks, control flow, data-interchange concepts, and the tooling around them that show up in almost every Python program — with runnable examples for each. Want to quiz yourself instead? Head to the flashcards.
Variable
coreA variable is a name that points to a value stored in memory. Python variables aren't typed themselves — the value they point to has a type, and a variable can be reassigned to a value of a different type at any time.
age = 32 # age points to an int
age = "thirty-two" # now it points to a str — totally legal
print(age, type(age))
Tip: use snake_case names that describe the value's purpose (total_cost, not tc).
Key
coreA key is the label used to look a value up. It's different from a variable — a key only works as a lookup inside a dictionary, it isn't a standalone name in memory the way a variable is.
capitals = {"peru": "lima"}
print(capitals["peru"]) # "peru" is the key
Think of a key as the question you ask a dictionary ("what's the capital of Peru?"). It only makes sense in that lookup context — you can't reference "peru" on its own the way you'd reference a variable.
Value
coreA value is any concrete piece of data in Python — it can be of any type. Different structures reach the same kind of value in different ways: a variable looks it up by name, a list by index, and a dictionary by key.
age = 32 # variable → looks up by name
fruits = ["mango", "lime"]
fruits[0] # list → looks up by index
capitals = {"peru": "lima"}
capitals["peru"] # dict → looks up by key
The value itself doesn't care how it's found — "lima" is "lima" whether you reach it through a variable, an index, or a key.
List
coreA list is an ordered, mutable collection of values, written with square brackets. There are no keys — items are accessed purely by position (index), starting at 0.
fruits = ["mango", "lime", "guava"]
fruits.append("papaya") # add to the end
print(fruits[0]) # index 0 = first item
print(len(fruits)) # how many items
→ 4
Ordered + mutable: items keep their position, and you can change, add, or remove them after creation.
Dictionary
coreA dictionary (dict) is a collection of key → value pairs, written with curly braces. Unlike a list, there's no numeric index — every value is stored under a key, and that key is what you use to look it up.
student = {
"name": "Kurt",
"role": "tutor",
"languages": ["python", "spanish"]
}
print(student["name"])
student["role"] = "teacher" # update an existing value
Since Python 3.7, dicts preserve insertion order — but you should still look items up by key, not position.
Syntax
coreSyntax is the set of rules that defines how code must be structured for a language to understand it — indentation, punctuation, keyword placement. Code that breaks these rules won't run at all; Python stops before the program even starts.
# valid syntax
if age > 18:
print("adult")
# invalid syntax — missing the colon
if age > 18
print("adult")
A syntax error is caught before anything runs — different from a runtime error, which only shows up once that specific line actually executes.
For loop
coreA for loop iterates over the items of a sequence (list, dict, string, range, etc.) one at a time, running the loop body once per item. Use it when you know what you're iterating over — a collection or a fixed count.
for i in range(3):
print("lap", i)
for fruit in ["mango", "lime"]:
print(fruit.upper())
→ lap 1
→ lap 2
→ MANGO
→ LIME
Ends automatically when the sequence runs out — no manual counter required.
While loop
coreA while loop repeats its body as long as a condition stays True. Use it when you don't know in advance how many iterations you need — you're waiting for something to become true.
battery = 3
while battery > 0:
print("running... battery:", battery)
battery -= 1
print("shutting down")
→ running... battery: 2
→ running... battery: 1
→ shutting down
Watch out: if the condition never becomes False, you get an infinite loop.
JSON
formatJSON (JavaScript Object Notation) is a lightweight text format for representing structured data — objects, arrays, strings, numbers, booleans, and null — that's easy for both humans and machines to read. It maps almost directly onto Python dicts and lists.
{
"name": "Kurt",
"role": "tutor",
"active": true,
"languages": ["python", "spanish"]
}
JSON is the default format for APIs, config files, and data exchanged over the web.
YAML
formatYAML (YAML Ain't Markup Language) represents the same kind of structured data as JSON, but uses indentation instead of braces and quotes — making it more readable for humans. Common in config files (Ansible, Docker Compose, Kubernetes, CI pipelines).
name: Kurt
role: tutor
active: true
languages:
- python
- spanish
Same data as the JSON example above — YAML is a superset concept, and most YAML parsers can read JSON too.
Serialization
processSerialization is converting an in-memory object (a Python dict, list, or custom object) into a format — like JSON or YAML text — that can be stored in a file, sent over a network, or saved in a database.
import json
config = {"host": "localhost", "port": 8080}
text = json.dumps(config) # dict → JSON string
print(text, type(text))
Think "packing a suitcase" — turning a live Python object into portable bytes/text.
Deserialization
processDeserialization is the reverse of serialization: taking that stored/transmitted text (JSON, YAML, etc.) and reconstructing it back into a live Python object you can work with.
import json
text = '{"host": "localhost", "port": 8080}'
config = json.loads(text) # JSON string → dict
print(config["port"], type(config))
uv
tooluv is a modern Python package and project manager, written in Rust for speed. It replaces the old pip + venv + pip-tools combo with a single tool, using a lock file to pin exact dependency versions.
$ uv venv # create a virtual environment
$ uv add requests # add + install a dependency, updates the lock file
$ uv sync # install exactly what's in the lock file
The lock file (uv.lock) is what makes builds reproducible — everyone installs the exact same versions, not just versions that happen to satisfy a range.
Dependency
conceptA dependency is code from outside your project that your project relies on to run — a library someone else wrote and published, rather than code you wrote yourself.
[project]
dependencies = ["requests>=2.31"]
# in your code
import requests
response = requests.get("https://api.example.com")
Dependencies can have their own dependencies ("transitive dependencies") — a package manager's real job is resolving that whole tree consistently.
Package Manager
toolA package manager is a tool that finds, installs, updates, and removes the packages your project depends on, usually resolving version conflicts between them automatically. In Python: pip, conda, and increasingly uv.
$ pip install requests # traditional package manager
$ uv add requests # newer, faster alternative