# Lists vs Tuples in Python: Differences and When to Use Each

> Lists vs tuples in Python beyond 'one is mutable': the real differences in hashability, memory, safety and intent, plus a decision rule that works in practice.

- **Author:** Ayushi Kulshreshta — AI Engineer (https://www.1stepgrow.com/authors/ayushi-kulshreshta/)
- **Published:** Jul 25, 2026 · **Updated:** Sep 17, 2026
- **Topic:** Python & Programming · **Format:** Comparison · **Read time:** 8 min
- **Canonical URL:** https://www.1stepgrow.com/articles/lists-vs-tuples-python/

## Key takeaways

- Mutability is the root difference; hashability, memory and intent all follow from it.
- The practical rule: homogeneous and growing means list; fixed-size record means tuple.
- Tuples can be dictionary keys and set members. Lists cannot.
- Performance differences are small enough that they should not drive the decision.

The short answer on lists vs tuples in Python: lists are mutable and tuples are not. Use a list for a collection of similar items that will grow or change, and a tuple for a fixed record, a dictionary key or a value that must not change. Every other difference follows from mutability.

"Tuples are immutable" still leaves traps. A tuple that holds a list cannot be a dictionary key, and a list used as a default argument quietly carries data from one function call to the next. This comparison is for Python learners who know both types exist but are unsure which to reach for. It covers hashability, memory, safety and intent, with a one-question decision rule. For everything you can do with tuples themselves, see the [Python tuples guide](https://www.1stepgrow.com/articles/python-tuples).

| Feature | List | Tuple |
| --- | --- | --- |
| Mutable | Yes | No |
| Hashable (usable as dict key / set member) | No | Yes, if contents are hashable |
| Memory per element | Higher (over-allocates for growth) | Lower (exact size) |
| Creation speed | Slower | Faster |
| Iteration speed | Comparable | Comparable, marginally faster |
| Can grow or shrink | Yes - append, extend, pop | No - concatenation makes a new tuple |
| Sortable in place | Yes - .sort() | No - sorted() returns a list |
| Typical use | A collection of similar things | One record with fixed fields |
| Signals intent | This will change | This will not change |
| Safe as a default argument | No - classic mutable default bug | Yes |

**Verdict — List:** Lists are the right default for most code — the majority of sequences you build are homogeneous collections that grow, and mutability is what you want. Tuples earn their place in three specific situations: fixed-size records, keys for dictionaries and sets, and anywhere you want the language to enforce that something does not change. Choose on intent rather than on the small performance differences.
## What is the real difference between a list and a tuple?

Mutability is the root difference, and three practical consequences follow from it. The Python design FAQ, [why are there separate tuple and list data types](https://docs.python.org/3/faq/design.html#why-are-there-separate-tuple-and-list-data-types), frames tuples like C structs and lists like arrays.

**Hashability.** A hash must stay constant for the lifetime of the object, or dictionary lookups break. Since a list can change, it cannot be hashed. Since a tuple cannot change, it can — provided everything inside it is [hashable](https://docs.python.org/3/glossary.html#term-hashable) too.

```python
valid = {(1, 2): "point"}
invalid = {[1, 2]: "point"}    # TypeError (unhashable type: 'list')

# a tuple containing a list is also unhashable
{(1, [2]): "x"}                # TypeError (unhashable type: 'list')
```

**Memory.** A list over-allocates so that repeated `append` is amortised O(1). By contrast, a tuple allocates exactly what it needs. You can see this with [`sys.getsizeof`](https://docs.python.org/3/library/sys.html#sys.getsizeof):

```python
import sys
sys.getsizeof([1, 2, 3])    # 88 on 64-bit Python 3.14
sys.getsizeof((1, 2, 3))    # 72 on 64-bit Python 3.14
```

These figures were measured as of September 2026 on Python 3.14. The exact numbers change between Python versions and platforms, but the tuple is consistently smaller. That is meaningful at scale — a million small tuples versus a million small lists is a real difference — and irrelevant otherwise.

**Safety as a default argument.** This is the practical one, and the [Python programming FAQ](https://docs.python.org/3/faq/programming.html#why-are-default-values-shared-between-objects) covers it too:

```python
# broken - the default list is created once and shared
def add_item(item, basket=[]):
    basket.append(item)
    return basket

add_item("a")     # ['a']
add_item("b")     # ['a', 'b']   <- surprise

# correct
def add_item(item, basket=None):
    if basket is None:
        basket = []
    basket.append(item)
    return basket
```

Tuples, however, do not have this failure mode, because you cannot mutate them.

## How to decide between lists vs tuples in Python

To decide, ask one question: **is this a collection of similar things, or one record with fixed fields?**

A collection — user IDs, temperatures, rows to process — is a list. It is homogeneous, its length depends on the data, and you will probably append to it or sort it.

On the other hand, a record — a coordinate, an RGB colour, a (name, age, city) triple — is a tuple. Its length is fixed by meaning, its positions have distinct roles, and changing it does not conceptually make sense.

```python
# collection of similar things
temperatures = [18, 25, 31, 12, 28]
temperatures.append(30)

# one record, fixed fields
location = (19.0760, 72.8777)

# a list of records
cities = [
    ("Mumbai", 19.0760, 72.8777),
    ("Delhi", 28.6139, 77.2090),
]
```

That last pattern — a list of tuples — is extremely common, and it shows the rule working in both directions at once.

## When to use a tuple vs a list: quick reference

| Situation | Choose | Why |
|---|---|---|
| Rows you will filter, sort or append to | list | needs mutation |
| A coordinate, colour or date parts | tuple | fixed fields |
| A dictionary key or set member | tuple | must be hashable |
| Several return values from a function | tuple | Python packs them automatically |
| Constants such as allowed extensions | tuple | cannot be changed by accident |
| A default argument value | tuple or `None` | avoids the shared-default bug |

## Where do tuples beat lists in real code?

Tuples win in four situations: compound dictionary keys, set members, multiple return values and constants. Each is shown below with real output.

**Compound dictionary keys:**

```python
from collections import defaultdict

transactions = [("North", "Q1", 1200.0), ("North", "Q1", 300.5), ("South", "Q1", 800.0)]
sales = defaultdict(float)
for region, quarter, amount in transactions:
    sales[(region, quarter)] += amount

dict(sales)   # {('North', 'Q1'): 1500.5, ('South', 'Q1'): 800.0}
```

**Set membership for pairs:**

```python
edges = [(1, 2), (2, 1), (2, 3)]
seen_edges = set()
for a, b in edges:
    key = (min(a, b), max(a, b))
    if key in seen_edges:
        continue
    seen_edges.add(key)

sorted(seen_edges)    # [(1, 2), (2, 3)] - the duplicate edge is skipped
```

**Returning several values:**

```python
def describe(nums):
    return min(nums), max(nums), sum(nums) / len(nums)

lo, hi, avg = describe([3, 1, 4, 1, 5])    # 1, 5, 2.8
```

**Fixed configuration you do not want mutated:**

```python
ALLOWED_EXTENSIONS = (".csv", ".json", ".parquet")
"report.json".endswith(ALLOWED_EXTENSIONS)     # True - endswith accepts a tuple
```

## When is a list the right choice?

Lists are right for anything you build up, filter, sort or modify:

```python
scores = [("Ananya", 91), ("Rohit", 78), ("Meera", 85)]
results = []
for name, score in scores:
    if score >= 80:
        results.append((name, score))

results.sort(key=lambda r: r[1], reverse=True)
results       # [('Ananya', 91), ('Meera', 85)]
```

Note that `sorted()` on a tuple returns a list, because it has to — there is no in-place sort for an immutable type.

## Common mistakes when choosing between lists and tuples

- **Calling list methods on a tuple.** `(1, 2).append(3)` raises `AttributeError: 'tuple' object has no attribute 'append'`.
- **Using a list as a dict key.** Convert it with `tuple()` first.
- **Assuming a tuple is frozen all the way down.** A tuple holding a list can still change.
- **Choosing tuples "for speed".** The gain is marginal; choose on intent.
- **Using a list as a default argument.** Use `None`, or a tuple if the default is read-only.

## What should you use when tuple positions get hard to read?

Use a `NamedTuple`. When `p[2]` no longer tells a reader what the value is, upgrade rather than tolerating it:

```python
# unclear
p = ("Ananya", 28, "Pune")
print(p[2])

# clear
from typing import NamedTuple

class Person(NamedTuple):
    name: str
    age: int
    city: str

p = Person("Ananya", 28, "Pune")
print(p.city)     # Pune
```

As a result, you keep tuple behaviour — immutability, hashability, unpacking — and gain names. Our [tuples guide](https://www.1stepgrow.com/articles/python-tuples) covers named tuples in more depth.

## Should you default to a list or a tuple?

Use a list by default. Then reach for a tuple when you need a key, a record, or enforced immutability.

In short, do not agonise over the performance difference in the lists vs tuples in Python debate. It is real, but it is almost never the thing that matters in your program.



## Related reading

[Mastering Python tuples](https://www.1stepgrow.com/articles/python-tuples) goes deeper on tuple features. [Python basics](https://www.1stepgrow.com/articles/python-basics) covers the other core types, and more head-to-head breakdowns sit in the [comparisons hub](https://www.1stepgrow.com/comparisons).

## Frequently asked questions

### Are tuples faster than lists?

Marginally, for creation, and they use less memory because they do not over-allocate. Iteration speed is essentially the same. The differences are small enough that they should almost never drive your choice, so pick on mutability and intent instead, and measure with timeit if a hot loop genuinely depends on it.

### Why can tuples be dictionary keys but not lists?

Dictionary keys must be hashable, and hashability requires the value not to change. Otherwise the hash computed at insertion would no longer match after a mutation, and lookups would silently fail. Immutability is what makes tuples safe here, provided every element inside the tuple is hashable too, so a tuple holding a list still cannot be a key.

### Can I convert between lists and tuples?

Yes, with list(my_tuple) and tuple(my_list). Both create a new object and copy the references to the same elements, so the conversion is O(n) and the elements themselves are not duplicated. A common pattern is to build a list while collecting data, then call tuple() once at the end to freeze the result.

### Why is a mutable default argument a bug?

Default arguments are evaluated once, when the function is defined, not on each call. A default list is therefore shared across every call, and mutations accumulate from one call to the next. Use None as the default and create the list inside the function. A tuple default avoids the problem, because it cannot be mutated.

---
_Source: 1stepGrow (https://www.1stepgrow.com/articles/lists-vs-tuples-python/). Cite with the title, "1stepGrow" and a link._
