list.insert()

Insert item BEFORE position i. Negative indexes work; out-of-range indexes clamp to the ends instead of raising.

List methodPython 1.0+Live demo
Common call
items.insert(0, first)
Returns
None — the list itself grows by one at position i
Replaces
the "shift everything and set" index-manipulation pattern
Watch out
out-of-range i does NOT raise — it clamps to 0 or len(list)
list.insert(iiPosition to insert BEFORE. Negative counts from the end. Out-of-range clamps to 0 (very negative) or len(list) (very positive) — no error.type: int · required, itemitemValue to insert. Not unpacked — the whole item goes in as one element.type: Any · required)
None

Demo

Live evaluation
Try:
Inputs
listliststarting list
indexintposition to insert before
itemAnyitem to insert
Output
['b', 'c', 'd'].insert(0, 'a')
None

The demo shows the LIST STATE after inserting. Python actually returns None; the meaningful effect is mutation. Insert places the item BEFORE index i. Out-of-range indexes clamp silently — insert(99, x) is the same as append(x); insert(-99, x) is the same as insert(0, x). Negative indexes count from the end, but insert(-1, x) goes BEFORE the last element, not after.

Parameters

NameTypeRequiredDescription
iintyesPosition to insert BEFORE. Negative counts from the end. Out-of-range clamps to 0 (very negative) or len(list) (very positive) — no error.
itemAnyyesValue to insert. Not unpacked — the whole item goes in as one element.

Return value

NoneReturns None — the useful effect is mutation. The demo shows the list state after inserting.

Common patterns

Prepend to a list
The idiomatic way to add at the front — though costly on big lists (O(n) shift).
items.insert(0, first)
Keep a sorted list sorted
bisect finds the position; insert places the item there in one call.
import bisect
bisect.insort(items, new_value)  # uses insert internally
Guarded insert
Bounds checking is up to you — insert never raises for a bad index.
if 0 <= i <= len(items):
    items.insert(i, x)
else:
    raise IndexError(i)

Examples

1. Prepend
xs = [2, 3] xs.insert(0, 1) xs
Returns
[1, 2, 3]
2. Middle
xs = [1, 2, 4] xs.insert(2, 3) xs
Returns
[1, 2, 3, 4]
3. At length = append
xs = [1, 2] xs.insert(2, 3) xs
Returns
[1, 2, 3]
4. Past length clamps
xs = [1, 2] xs.insert(99, 3) xs
Returns
[1, 2, 3]
5. Negative before last
xs = [1, 2, 4] xs.insert(-1, 3) xs
Returns
[1, 2, 3, 4]
6. Returns None
[1, 2, 3].insert(0, 0)
Returns
None

Pitfalls

1. Out-of-range indexes DO NOT raise
Unlike subscript access or delete, insert clamps silently — huge index means append, huge negative means prepend. Fine for expected behavior; a silent bug when you thought the index was validated.
Silent clamp
xs = [1, 2, 3]
xs.insert(999, "X")
xs
[1, 2, 3, "X"] # no error
Validate first
if 0 <= i <= len(xs):
    xs.insert(i, "X")
else:
    raise IndexError(i)
explicit error on bad index
2. The `xs = xs.insert(...)` bug
insert returns None. Assigning its result back sets your variable to None — the same class of bug as sort and extend.
Now xs is None
xs = [1, 2, 3]
xs = xs.insert(0, 0)
print(xs)
None
Just insert
xs.insert(0, 0)   # mutate, keep name
[0, 1, 2, 3]
3. insert(0, x) is O(n)
Prepending shifts every existing item right by one. Fine for small lists; a hot-loop killer for big ones. Use collections.deque when you prepend often.
Slow at scale
for x in incoming:
    items.insert(0, x)  # O(n) each call — O(n²) total
quadratic time
deque is O(1)
from collections import deque
d = deque(items)
for x in incoming:
    d.appendleft(x)
linear time
4. Confused with subscript assignment
xs[i] = v REPLACES the item at i. xs.insert(i, v) SHIFTS everything from i onward one step right. Different meanings; picking the wrong one silently changes the list length or overwrites data.
Overwrites
xs = [1, 2, 3]
xs[1] = 99
xs
[1, 99, 3] # replaced, not inserted
Insert shifts
xs = [1, 2, 3]
xs.insert(1, 99)
xs
[1, 99, 2, 3]

When to use

Use it
  • Inserting at a known position in a small list
  • Prepending occasionally to a small list
  • Keeping a sorted list sorted after a manual bisect.bisect find
  • Injecting into a fixed-shape output being built up
Reach for something else
  • Frequent prepending on big lists → collections.deque
  • Adding at the end → append (clearer, same speed)
  • Adding multiple items → extend (one call, one grow)
  • When bad indexes should raise → validate before calling

Notes

Complexity
O(n) — every item from i to the end shifts right by one
Return
None; the list is mutated in place
CPython impl
Objects/listobject.c :: ins1 — grows the internal array as needed, then memmove
Memory
May reallocate the underlying array; the shift is in-place
Thread-safe
Not safe under concurrent mutation of the same list

FAQ

It inserts BEFORE the last element, not after it. To insert AFTER the last (i.e., append), use insert(len(xs), x) or just append(x).

xs = [1, 2, 3]
xs.insert(-1, 99)
# [1, 2, 99, 3]

History

1.0
list.insert has been part of the list type since Python 1.0.
2.0
Negative indexes and out-of-range clamping behavior formalized.