Concepts Beginner Free 13/53 in series 15 min read

Python for Quantum Computing: A Practical Setup Guide

Everything you need to set up Python for quantum computing: virtual environments, NumPy fundamentals, and your first quantum program from scratch.

What you'll learn

  • python
  • numpy
  • setup
  • qiskit
  • jupyter

Prerequisites

  • Basic Python (variables, functions, loops)
  • No quantum physics background needed

Why Python?

Every major quantum computing framework runs on Python. Qiskit (IBM), Cirq (Google), PennyLane (Xanadu), PyQuil (Rigetti), and Amazon Braket all expose Python APIs. If you want to write quantum programs, Python is not just a reasonable choice; it is the de facto standard.

The reason goes beyond convention. Quantum states are complex vectors and quantum gates are matrices. NumPy, Python’s numerical computing library, handles complex numbers, matrix multiplication, and tensor products natively and efficiently. The mathematical structure of quantum mechanics maps cleanly onto NumPy arrays, which is why every framework uses NumPy under the hood.

Other languages exist. Julia has strong numerical computing credentials and some quantum libraries. C++ is used for performance-critical simulator internals. But for learning, research, and working with real quantum hardware, Python is where the ecosystem lives. This guide gets your Python environment production-ready for quantum work.

Python Version and Virtual Environments

Which Python version to use

Most quantum packages require Python 3.9 or later. Qiskit in particular has dropped support for older versions, and some packages use type hints and syntax that require 3.9 as a minimum. Python 3.11 or 3.12 is a good choice as of 2026: stable, fast, and fully supported by the major frameworks.

Check what you have:

python3 --version

If you need to install or manage multiple Python versions, use pyenv. It lets you install any Python version and switch between them per-project without touching your system Python.

# Install pyenv (macOS / Linux)
curl https://pyenv.run | bash

# Install a specific Python version
pyenv install 3.11.9

# Use it in your current project directory
pyenv local 3.11.9

Virtual environments

Always work inside a virtual environment. This is not optional for quantum computing work. Qiskit and TensorFlow Quantum, for example, have conflicting dependency requirements: installing both into the same global Python environment will break one or both. Virtual environments keep each project’s packages isolated.

Create and activate a virtual environment for your quantum work:

python -m venv qenv
source qenv/bin/activate    # macOS / Linux
# qenv\Scripts\activate     # Windows

Your shell prompt will show (qenv) when the environment is active. From this point, everything you install with pip stays inside qenv and will not affect any other project.

To deactivate when you are done:

deactivate

Installing the Essential Packages

With your virtual environment active, install the core packages:

pip install numpy matplotlib jupyter qiskit

What each one does:

  • numpy: complex number arithmetic, matrix operations, and tensor products. Quantum states are complex vectors; NumPy is how you work with them directly.
  • matplotlib: plotting measurement histograms and probability distributions. Almost every quantum tutorial uses it for visualising results.
  • jupyter: interactive notebooks that mix code, output, and formatted text in one document. The standard working environment in quantum research.
  • qiskit: IBM’s quantum computing framework, the most widely used in the field. Covers circuit construction, simulation, and access to real quantum hardware.

Depending on your Qiskit version, you may also need the Aer simulator separately:

pip install qiskit-aer

NumPy for Quantum: What You Actually Need

You do not need to be a NumPy expert, but a few operations come up constantly when working with quantum states and gates. Here they are with runnable examples.

Complex numbers

Python has native complex number support. The imaginary unit is j.

import numpy as np

z = 1 + 2j
print(z.real)      # 1.0
print(z.imag)      # 2.0
print(abs(z))      # 2.23... (the modulus)

# Euler's formula: e^(i*pi) = -1
print(np.exp(1j * np.pi))  # (-1+0j), within floating point precision

Probability amplitudes in quantum mechanics are complex numbers, so you will use j notation and np.exp with imaginary arguments constantly.

State vectors

A qubit’s state is a two-element complex vector. The |+⟩ state (equal superposition) looks like this:

import numpy as np

# |+> state: (|0> + |1>) / sqrt(2)
plus_state = np.array([1 / np.sqrt(2), 1 / np.sqrt(2)])
print(plus_state)  # [0.70710678 0.70710678]

# Verify normalisation: probabilities must sum to 1
probabilities = np.abs(plus_state) ** 2
print(probabilities.sum())  # 1.0

Checking unitarity

Quantum gates are unitary matrices: applying the gate and then its conjugate transpose returns the identity. You can verify this with np.allclose, which checks for equality within floating-point tolerance.

import numpy as np

# Hadamard gate
H = (1 / np.sqrt(2)) * np.array([[1,  1],
                                   [1, -1]])

# A matrix U is unitary if U @ U†  = I
identity_check = H @ H.conj().T
print(np.allclose(identity_check, np.eye(2)))  # True

This check is useful when you define custom gates or want to verify that a matrix you have constructed is physically valid.

Tensor products

When combining multiple qubits, their joint state is the tensor product (Kronecker product) of the individual states. NumPy provides np.kron for this.

import numpy as np

# |0> and |1> basis states
ket0 = np.array([1, 0])
ket1 = np.array([0, 1])

# Two-qubit state |01> = |0> tensor |1>
ket01 = np.kron(ket0, ket1)
print(ket01)  # [0, 1, 0, 0]

# Two-qubit state |10> = |1> tensor |0>
ket10 = np.kron(ket1, ket0)
print(ket10)  # [0, 0, 1, 0]

A two-qubit system has four basis states: |00>, |01>, |10>, |11>. The full state vector has four elements. For n qubits, the state vector has 2^n elements, which is why classical simulation of quantum systems becomes expensive quickly.

Your First Real Program: Building a Bell State

The Bell state |Phi+> is one of the most important states in quantum computing. It is a two-qubit entangled state:

|Phi+> = (|00> + |11>) / sqrt(2)

Measuring either qubit always gives a random result, but the two results are always identical. This is entanglement. Let’s build this state in two ways: manually with NumPy, then with Qiskit.

Building the Bell state with NumPy

The Bell state is created by applying a Hadamard gate to the first qubit and then a CNOT gate to both qubits.

import numpy as np

# Start in the |00> ground state
state = np.array([1, 0, 0, 0], dtype=complex)

# Hadamard on qubit 0, Identity on qubit 1
# H tensor I (4x4 matrix)
H = (1 / np.sqrt(2)) * np.array([[1,  1],
                                   [1, -1]])
I = np.eye(2)
H_I = np.kron(H, I)

state = H_I @ state
print("After H on qubit 0:", state)
# [0.707, 0, 0.707, 0]  -- superposition of |00> and |10>

# CNOT gate (control: qubit 0, target: qubit 1)
CNOT = np.array([[1, 0, 0, 0],
                 [0, 1, 0, 0],
                 [0, 0, 0, 1],
                 [0, 0, 1, 0]], dtype=complex)

state = CNOT @ state
print("Bell state |Phi+>:", state)
# [0.707, 0, 0, 0.707]  -- (|00> + |11>) / sqrt(2)

# Verify normalisation
print("Norm:", np.linalg.norm(state))  # 1.0

# Measurement probabilities
probs = np.abs(state) ** 2
labels = ['|00>', '|01>', '|10>', '|11>']
for label, p in zip(labels, probs):
    if p > 0:
        print(f"{label}: {p:.3f}")
# |00>: 0.500
# |11>: 0.500

The state vector [0.707, 0, 0, 0.707] encodes exactly what we expect: 50% probability of |00> and 50% probability of |11>, with no probability of |01> or |10>.

Verifying with Qiskit

Now build the same circuit using Qiskit and run it on the Aer simulator to confirm:

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator

# Create a 2-qubit circuit with 2 classical bits for measurement
qc = QuantumCircuit(2, 2)

# Hadamard on qubit 0
qc.h(0)

# CNOT: qubit 0 controls qubit 1
qc.cx(0, 1)

# Measure both qubits
qc.measure([0, 1], [0, 1])

# Run 1000 shots on the simulator
simulator = AerSimulator()
job = simulator.run(qc, shots=1000)
result = job.result()
counts = result.get_counts()

print(counts)
# Example output: {'00': 497, '11': 503}
# Only |00> and |11> appear -- never |01> or |10>

The Qiskit output matches the NumPy calculation. Only 00 and 11 appear in the results, confirming entanglement: the two qubits are always correlated. The NumPy approach shows you the math; Qiskit handles it for you at scale.

Jupyter Notebooks

Start a Jupyter notebook server from your project directory:

jupyter notebook

Your browser will open with a file browser. Create a new notebook and you can write Python code in cells, run them one at a time, and see output (including plots) appear inline.

Notebooks dominate quantum computing work for several reasons:

  • Inline LaTeX: write mathematical expressions like $|\psi\rangle = \alpha|0\rangle + \beta|1\rangle$ and they render as formatted equations alongside the code that implements them.
  • Plots next to code: a matplotlib histogram of your measurement results appears directly below the code that generated it, making it easy to see how parameters affect outcomes.
  • Sharable and reproducible: a notebook file captures code, outputs, and narrative in one document. You can share .ipynb files and collaborators can re-run them exactly.

IBM Quantum Learning and the PennyLane Codebook both deliver their tutorials as Jupyter notebooks. Getting comfortable with the notebook workflow now means those resources will feel natural immediately.

A useful shortcut: press Shift+Enter to run a cell and move to the next one. Press B in command mode (when a cell is not selected for editing) to insert a new cell below.

Next Steps

With your environment set up and the Bell state under your belt, you are ready to go deeper into specific frameworks.

  • Getting Started with Qiskit, covering circuits, gates, simulators, and connecting to real IBM quantum hardware
  • PennyLane Hello World, covering PennyLane’s differentiable approach to quantum circuits, built for quantum machine learning
  • Getting Started with Cirq, covering Google’s framework for near-term quantum algorithms, with fine-grained control over circuit structure

Was this tutorial helpful?