Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a Python data structure by the operation you do most: use a list for an ordered, changeable sequence, a dict for lookup by key, a set for unique membership, a deque for work at both ends, and heapq when you need the next-smallest priority. Python does not define one canonical list of “the ten” data structures; this guide covers ten useful containers and access patterns, and distinguishes built-in types from patterns implemented with them.

How to choose a Python data structure

Start with the shape of the data and the operations your code repeats. Sequences preserve position and can be traversed in order. Mappings associate keys with values. Sets represent unique elements. A deque is suited to both-end operations, while a heap selects by priority. These choices affect what operations are natural and how their costs grow.

Structure or pattern Best fit Ordering or access Mutable? Duplicates?
list General-purpose sequence; stack Position and index Yes Yes
tuple Fixed sequence or record Position and index No, at the top level Yes
dict Lookup by key Key-to-value mapping Yes Keys are unique; values may repeat
set Uniqueness and membership Membership and set operations Yes No
frozenset Immutable set; hashable set value Membership and set operations No No
array.array Values of one constrained type Position and index Yes Yes
collections.deque Adding and removing at either end Either end; index access is less suited to the middle Yes Yes
Stack pattern Last-in, first-out work Most recent item first Depends on its container Depends on its container
Queue pattern First-in, first-out work Oldest item first Depends on its container Depends on its container
Heap-based priority queue Repeatedly selecting the smallest priority Next item by priority Yes; stored in a list Yes

The costs that most often influence this choice are front removal from a list, end operations on a deque, and heap operations. The Python tutorial explains that inserting or removing at the beginning of a list shifts other elements, making that a poor repeated-queue operation. The Python 3.14 collections reference describes deque appends and pops at either end as approximately O(1). The Python 3.14 heapq reference documents heapify as linear time. These are complexity properties, not guarantees of identical wall-clock speed for every program.

1. List: the flexible ordered default

A list is an ordered, mutable sequence. Use it when you want to retain order, access items by position, iterate, replace values, or add and remove items at the end.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
scores = [91, 84, 97]
scores.append(88)
scores[0] = 93
print(scores)  # [93, 84, 97, 88]

A list can also implement a stack efficiently at its right end: use append() to add and pop() to remove. Avoid repeatedly inserting or popping at index zero for a busy queue, because the remaining elements must shift. For FIFO work, use a deque instead. The Python tutorial’s data-structures chapter describes list operations and this distinction.

2. Tuple: a fixed sequence or record

A tuple is an ordered sequence whose structure cannot be changed after creation. It is useful for a fixed record, such as a point with two coordinates, or for returning several related values.

point = (3, 5)
x, y = point

one = (3,)  # the comma makes this a one-item tuple

The comma, not the parentheses alone, makes a tuple. A tuple is immutable at the top level, but may contain a mutable object; changing that nested object does not replace or resize the tuple. A tuple is hashable only when all of its contents are hashable, so only suitable tuples can be dictionary keys or set members. See the Python tutorial and built-in types reference.

3. Dictionary: values found by key

A dict maps unique, hashable keys to values. Use it when the lookup should be by a meaningful identifier rather than by a sequence position. Dictionary iteration follows insertion order.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
prices = {"tea": 3.5, "coffee": 4.0}
print(prices["tea"])            # 3.5
print(prices.get("juice", 0))   # 0
prices["tea"] = 3.75

Indexing with a missing key raises KeyError; get() can return a default instead. Keys must be hashable, so a list cannot be used as a key. A dictionary allows repeated values, but a key can occur only once. The Python tutorial covers mapping behavior and dictionary operations.

4. Set: unique elements and membership

A set is a mutable collection of distinct, hashable elements. Use one to remove duplicates, test membership, or combine collections using union, intersection, and difference. Sets are unordered; do not rely on a stable iteration order.

unique_tags = set(["python", "data", "python"])
print("data" in unique_tags)  # True

left = {"red", "blue"}
right = {"blue", "green"}
print(left & right)  # {"blue"}: intersection

Use set() for an empty set: {} creates an empty dictionary. Set elements must be hashable, so mutable lists cannot be elements. The Python tutorial documents set operations and membership.

5. Frozenset: an immutable set

frozenset is the immutable counterpart of set. Its contents cannot be added or removed after creation, so a frozenset can itself be used as a dictionary key or as an element of another set, provided its members are hashable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
permissions = frozenset({"read", "write"})
role_permissions = {permissions: "editor"}
print(role_permissions[permissions])  # editor

Choose it when the set of members should be fixed or when a set needs to be represented as a hashable value. The Python data types index lists frozenset among Python’s built-in types.

6. Array: a sequence constrained to one type

array.array is a standard-library option for a sequence of values that share a type code, rather than a general container of arbitrary Python objects. It can suit homogeneous numeric data when a fixed element type is appropriate; it is not automatically faster or smaller for every workload.

from array import array

readings = array("i", [4, 8, 12])
readings.append(16)
print(readings[0])  # 4

The type code, such as "i" in this example, constrains the stored values. Consult the Python data types index for the standard library’s specialized data types.

7. Deque: efficient work at either end

collections.deque is a double-ended queue. Use it when code needs to append or remove items at the left and right ends, particularly for a FIFO queue. Its end operations are approximately O(1); random access slows toward the middle, so a list is a better fit for frequent indexed access.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from collections import deque

tasks = deque(["a", "b"])
tasks.append("c")
first = tasks.popleft()
print(first)  # a

A deque can also be bounded with maxlen. Once full, adding an item at one end discards an item from the opposite end. This is useful for retaining a rolling window, but it means older entries can be dropped automatically.

recent = deque([1, 2, 3], maxlen=3)
recent.append(4)
print(recent)  # deque([2, 3, 4], maxlen=3)

The Python 3.14 collections reference describes deque operations and their performance characteristics.

8. Stack: last in, first out

A stack is an access pattern, not a separate standard built-in container: the newest item is removed first. A list is often all a Python program needs.

stack = []
stack.append("page 1")
stack.append("page 2")
current = stack.pop()
print(current)  # page 2

This pattern works well for undo histories, nested processing, or tracking a path that may need to be retraced. The container is a list; the LIFO rule is what makes its use a stack. The Python tutorial demonstrates lists used this way.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

9. Queue: first in, first out

A queue is an access pattern in which the earliest added item is removed first. For a simple FIFO queue, use collections.deque and remove from the left. The Python Software Foundation’s Python tutorial says: “To implement a queue, use collections.deque which was designed to have fast appends and pops from both ends.”

from collections import deque

queue = deque(["first", "second"])
queue.append("third")
next_item = queue.popleft()
print(next_item)  # first

Do not substitute repeated list.pop(0) calls for this pattern in a busy queue: front removal shifts the remaining list entries. The concrete container in this example is a deque; “queue” describes its FIFO use. See the tutorial’s recommendation.

10. Heap-based priority queue: choose by priority

Use heapq when you need to repeatedly take the smallest item, rather than the earliest arrival. A heap is stored in a regular list, but it is not a fully sorted list: its invariant puts the smallest item at index zero.

import heapq

jobs = [5, 1, 3]
heapq.heapify(jobs)
next_priority = heapq.heappop(jobs)
print(next_priority)  # 1
heapq.heappush(jobs, 2)

The Python 3.14 heapq reference documents heapify() as linear time and provides both min-heap and max-heap APIs. The max-heap functions were added in Python 3.14; do not assume they are available in earlier versions. For equally ranked jobs, consider storing a tie-breaker alongside the priority so comparisons do not need to order arbitrary payload objects.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common selection mistakes and fixes

  • Using a list for frequent FIFO removal: repeated pop(0) shifts the remaining entries. Use a deque and popleft().
  • Expecting a set to retain insertion order: set iteration order is not a stable ordering contract. Use a list if sequence order matters, or a dictionary when keyed insertion-order iteration is suitable.
  • Assuming a tuple freezes everything inside it: it freezes the top-level sequence, not mutable objects referenced by its elements.
  • Using an unhashable value as a key or set member: choose an immutable/hashable representation when appropriate, such as a tuple of hashable fields.
  • Expecting heap contents to be sorted: only the heap invariant is guaranteed. Repeatedly pop to retrieve values in priority order.
  • Using a bounded deque without accounting for eviction: when full, a new item removes one from the opposite end. Omit maxlen if dropping old data is not intended.

Performance and cost in practical terms

Choose based on the operations the program actually performs, rather than assuming one container is universally fastest. Lists suit indexed sequence work and stack operations at the right end; deque suits both-end work; a dictionary suits key lookup; sets suit uniqueness and membership; heaps suit repeated minimum selection. In particular, moving work from a list’s front to a deque’s left end changes the operation’s documented growth behavior. A heap’s heapify() can build a heap from an existing list in linear time, according to the Python 3.14 reference.

For arrays, use the type-constrained representation when its element model is useful; measure the application if memory footprint or speed is decisive. Actual results depend on the data and workload, and the official type descriptions do not establish a universal speed or size advantage for every program.

Or skip the browser setup

If your Python project also needs website screenshots, ScreenshotNeo is a screenshot API and MCP server made by Yorker Media. One GET request returns a PNG, JPEG, WebP, or PDF; see the API documentation for parameters and response details. Here is a runnable Python example:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
  • Cookie banners are accepted before capture; more than 60 known consent platforms, newsletter popups, and chat widgets can be removed. Each step can be turned off.
  • Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Responses identify the page verdict and billing status in X-Page-Verdict and X-Billed headers.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents, including Claude, Cursor, and other MCP clients.
  • The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Every feature is available on every plan.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.