Learn Python language basics
Python has become the de facto programming language of quantum computing. This guide highlights some basic Python commands and logic; foundational elements to build from.

This guide assumes that you have already installed the UV package manager and latest version of Python on your machine. It also assumes that you are able to open a shell application, and are comfortable editing code. If any of that sounds unfamiliar or outside your expertise, don’t fret! We have a simple guide for that: Setup Python on your machine. Give that guide a thorough look over first, then come back here to start flexing your code muscles.
Running Python
Python runs line-by-line, like a Read-Evaluate-Print Loop (REPL). Python scripts are just plain text files, often with file names ending in a .py suffix. Our code examples rely on the UV package manager. (See our guide for Setting up Python and UV on your machine.) A simple one-line Python script can be run from the command-line shell via uv like so:
uv run python -c "print('Hello, World!')"
To enter a full Python REPL via uv, enter the following into your shell:
uv run python
To exit the Python REPL, type exit() or quit() and press Enter. For Python 3.13 and later, those parenthesis may be omitted.
To run a Python script file via uv, enter the following, replacing main.py with the name of the script you wish to execute.
uv run python main.py
Basic Syntax
Variable creation is implicit. Unlike other scripting languages, there’s no var, let, or const keywords required in order to create a variable handle. Assignment binds a name to a value:
x = 10
y = "hello"
z = [1, 2, 3]
Everything is an object. Variables are labels, not boxes.
Indentation (not curly braces or other visible characters) defines scope blocks:
if cond:
do_something()
else:
do_other()
Indentation is semantic, that is, your negative space carries logical meaning. Therefore, your code must consistenly use either tabs or spaces for indentation without deviation. The offical style guide for Python (“PEP 8”) specifies an indentation level as 4 spaces wide.
Functions
def add(a, b):
return a + b
Python functions capture variables lexically (like JS closures), but the write rules differ, explained in scoping below. Default arguments are evaluated once (careful!):
def append_to_list(value, lst=[]): # BAD
lst.append(value)
return lst
Use:
def append_to_list(value, lst=None):
if lst is None:
lst = []
return lst
Classes (Python-style OOP)
class Car:
def __init__(self, make):
self.make = make
def honk(self):
print("beep")
c = Car("Tesla")
c.honk()
Methods need self explicitly. Inheritance uses the class name:
class SportsCar(Car):
pass
Collections
List (array)
a = [1, 2, 3]
Tuple (immutable)
t = (1, 2, 3)
Dict
d = {"name": "Stewart", "role": "CTO"}
Set
s = {1, 2, 3}
List comprehensions:
squares = [x*x for x in range(10)]
Dictionary comprehensions:
doubles = {x: x*2 for x in range(5)}
Modules / Imports
import math
from pathlib import Path
from mymodule import helper
Scripts are modules. Packages are directories with __init__.py.
Exceptions
try:
risky()
except ValueError:
print("Nope")
except Exception as e:
print("Other error:", e)
finally:
cleanup()
File I/O
with open("data.txt") as f:
text = f.read()
The with block ensures cleanup (context manager).
Python Variable Scoping (LEGB Rule)
Python scoping follows L-E-G-B: - Local, inside current function - Enclosing, outer function scopes (closures) - Global, module-level - Built-in, len, print, etc This is very similar to JavaScript lexical scoping except Python treats assignment differently.
Important Rule
Any variable you assign to inside a function is considered local unless you explicitly declare otherwise. This catches people:
x = 10
def f():
print(x) # ERROR? Actually, UnboundLocalError!
x = 20
Why? Because the presence of x = 20 makes x local to f. Python sees “you assign to x somewhere in the function” → therefore x is local everywhere in that function. To mutate the module-level x:
x = 10
def f():
global x
print(x)
x = 20
Closures (Enclosing scope)
def outer():
x = 10
def inner():
print(x) # OK
inner()
But trying to assign inside the closure fails:
def outer():
x = 10
def inner():
x = 20 # This creates NEW local x
inner()
print(x) # still 10
To mutate the enclosing scope’s variable use nonlocal:
def outer():
x = 10
def inner():
nonlocal x
x = 20
inner()
print(x) # 20
Pythonic Style Cheat Sheet
Idiomatic ways to write things:
Iteration
for x in items:
...
Enumerate with index
for i, x in enumerate(items):
...
Iterate dict
for k, v in d.items():
...
Ternary
msg = "ok" if status else "bad"
With-open file handling
with open("file.txt") as f:
data = f.read()
Write generator expression
total = sum(x*x for x in nums)
Tiny “gotchas” you should know immediately
Mutability matters. Lists, dicts, sets = mutable. Tuples, ints, strings = immutable. Everything is reference by default.
a = [1,2]
b = a
b.append(3)
a == [1,2,3]// True!
Truthiness:
0, "", [], {}, None, False → falsey
Everything else is truthy.
10-line example that uses everything above
def make_counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return inc
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
Stay in the loop.
Get the latest tutorials, demos, and project showcases straight to your inbox. No noise, just the good stuff.
On this page