Как добавить элемент в список в Python: append, insert, extend
Как добавить элемент в список Python: append в конец, insert по индексу и в начало, extend и += для нескольких элементов, без дубликатов, bisect и deque.
Содержание · 14 разделов
- Какой способ выбрать
- append: добавить элемент в конец списка
- insert: вставить элемент по индексу
- extend и +=: добавить несколько элементов
- Чем += отличается от +
- Добавление через срез и распаковку
- Как добавить элемент в начало списка
- Добавление элементов в цикле
- Ввод с клавиатуры
- Не добавляйте в список, который обходите
- Один и тот же объект в нескольких местах
- Как добавить элемент без дубликатов
- Вставка в отсортированный список: bisect.insort
- Добавление в список внутри словаря и во вложенный список
- Производительность: append, insert и deque
- Частые ошибки
- Частые вопросы
- Почему список изменился снаружи функции?
- Как добавить элемент в кортеж или строку?
- Как добавить элемент в массив array или NumPy?
- Как добавить элементы двух списков по очереди?
- Как объединить несколько списков в один?
- Что быстрее: append в цикле или генератор списка?
- Итог
Чтобы добавить элемент в список в Python, вызовите метод append(): items.append(x) кладёт x в конец списка. Для вставки на конкретную позицию есть insert(индекс, x), а несколько элементов сразу добавляет extend() или оператор +=. Все три способа меняют сам список и ничего не возвращают.
fruits = ["яблоко", "груша"]
fruits.append("слива") # в конец
fruits.insert(0, "киви") # в начало (перед индексом 0)
fruits.extend(["манго", "лайм"]) # несколько элементов в конец
print(fruits) # → ['киви', 'яблоко', 'груша', 'слива', 'манго', 'лайм']
Ниже — как выбрать способ под задачу: добавление в начало и в середину, в цикле, без повторов, в отсортированный список, а также чем медленный insert(0, x) заменить на больших данных. Общие операции со списками (срезы, удаление, сортировка, копирование) разобраны в статье о списках в Python. Примеры проверены на Python 3.12, вывод показан комментарием # →.
Какой способ выбрать
| Способ | Куда добавляет | Сколько элементов | Результат | Скорость |
|---|---|---|---|---|
a.append(x) | в конец | один | меняет a, вернёт None | быстро, O(1) |
a.insert(i, x) | перед индексом i | один | меняет a, вернёт None | O(n), медленно в начале |
a.extend(iterable) | в конец | все из итерируемого | меняет a, вернёт None | O(k), k — число новых |
a += iterable | в конец | все из итерируемого | меняет a | как extend |
a[i:i] = [x, y] | в позицию i | несколько | меняет a | O(n) |
a + [x], [*a, x] | куда угодно | любое | новый список | O(n), копирует всё |
bisect.insort(a, x) | в нужное место | один | меняет a, порядок сохранён | O(n) |
deque.appendleft(x) | в начало | один | меняет очередь deque | O(1) |
O(1) значит «за постоянное время, независимо от длины списка», O(n) — время растёт пропорционально числу элементов. Для повседневных задач хватает append и extend; остальные способы нужны в конкретных случаях, разобранных ниже.
append: добавить элемент в конец списка
append(x) добавляет один объект в конец и увеличивает длину списка на единицу. Если передать список, он станет одним вложенным элементом:
nums = [1, 2, 3]
nums.append(4)
print(nums) # → [1, 2, 3, 4]
nums.append([5, 6])
print(nums) # → [1, 2, 3, 4, [5, 6]]
print(len(nums)) # → 5
Метод изменяет список на месте и возвращает None. Поэтому результат вызова не присваивают:
nums = [1, 2, 3]
nums = nums.append(4)
print(nums) # → None
Правильно — просто nums.append(4) отдельной строкой.
insert: вставить элемент по индексу
insert(i, x) вставляет x перед элементом с индексом i; остальные элементы сдвигаются вправо.
letters = ["a", "c", "d"]
letters.insert(1, "b")
print(letters) # → ['a', 'b', 'c', 'd']
letters.insert(len(letters), "e") # то же, что append("e")
print(letters) # → ['a', 'b', 'c', 'd', 'e']
letters.insert(100, "f") # индекс больше длины — ошибки нет, вставка в конец
print(letters) # → ['a', 'b', 'c', 'd', 'e', 'f']
Важно:
insert(-1, x)вставляет элемент перед последним, а не в конец. Для добавления в конец используйтеappend.
letters = ["a", "b", "c"]
letters.insert(-1, "X")
print(letters) # → ['a', 'b', 'X', 'c']
Присвоить значение по несуществующему индексу нельзя: a[len(a)] = x вызывает IndexError: list assignment index out of range. Список растёт только через методы добавления.
extend и +=: добавить несколько элементов
extend() принимает любой итерируемый объект — список, кортеж, range, множество, генератор — и добавляет его элементы по одному:
a = [1, 2]
a.extend([3, 4])
a.extend((5, 6))
a.extend(range(7, 9))
print(a) # → [1, 2, 3, 4, 5, 6, 7, 8]
Из-за этого extend со строкой добавит отдельные символы, со словарём — ключи, а число вызовет ошибку:
tags = ["python"]
tags.extend("go")
print(tags) # → ['python', 'g', 'o']
keys = ["x"]
keys.extend({"k1": 1, "k2": 2})
print(keys) # → ['x', 'k1', 'k2']
[1].extend(5) # → TypeError: 'int' object is not iterable
Одну строку или число добавляют через append, несколько одинаковых значений — через extend с умножением: a.extend([0] * 3).
Чем += отличается от +
Оператор += для списка работает как extend: меняет список на месте и принимает любой итерируемый объект. Оператор + склеивает только два списка и создаёт новый объект:
a = [1, 2]
a += [3]
a += (4, 5)
a += "ab"
print(a) # → [1, 2, 3, 4, 5, 'a', 'b']
b = [1, 2] + (3, 4) # → TypeError: can only concatenate list (not "tuple") to list
Разница заметна, когда на список ссылаются несколько переменных:
a = [1, 2]
alias = a
a += [3] # изменили тот же объект
print(alias) # → [1, 2, 3]
a = a + [4] # создали новый список, alias его не видит
print(alias, a) # → [1, 2, 3] [1, 2, 3, 4]
Добавление через срез и распаковку
Присваивание срезу вставляет сразу несколько элементов в любое место списка. Пустой срез a[i:i] означает «позиция перед индексом i»:
nums = [1, 5]
nums[1:1] = [2, 3, 4] # в середину
print(nums) # → [1, 2, 3, 4, 5]
nums[:0] = [-1, 0] # в начало
print(nums) # → [-1, 0, 1, 2, 3, 4, 5]
nums[len(nums):] = [6] # в конец, как append(6)
print(nums) # → [-1, 0, 1, 2, 3, 4, 5, 6]
Распаковка звёздочкой собирает новый список и оставляет исходный без изменений. Это удобно, когда оригинал нужен дальше:
base = [2, 3]
print([1, *base, 4]) # → [1, 2, 3, 4]
print([*base, *range(5, 7)]) # → [2, 3, 5, 6]
print(base) # → [2, 3]
Как добавить элемент в начало списка
Для коротких списков подходят три записи:
queue = [2, 3]
queue.insert(0, 1) # меняет список
print(queue) # → [1, 2, 3]
queue = [0] + queue # создаёт новый список
print(queue) # → [0, 1, 2, 3]
queue[:0] = [-2, -1] # несколько элементов в начало
print(queue) # → [-2, -1, 0, 1, 2, 3]
Каждая из них сдвигает все элементы списка, поэтому на тысячах вставок в начало работает медленно. Если элементы часто добавляются слева, возьмите deque (двустороннюю очередь) из модуля collections:
from collections import deque
dq = deque([2, 3])
dq.appendleft(1)
dq.extendleft([0, -1]) # добавляет по одному, поэтому порядок разворачивается
print(dq) # → deque([-1, 0, 1, 2, 3])
print(list(dq)) # → [-1, 0, 1, 2, 3]
У deque есть и append, extend, pop, popleft, но доступ по индексу в середине очереди медленнее, чем у списка, а срезы не поддерживаются. Подробности — в документации collections.deque.
Добавление элементов в цикле
Классический способ собрать список — создать пустой и вызывать append на каждой итерации цикла for:
squares = []
for n in range(1, 6):
squares.append(n * n)
print(squares) # → [1, 4, 9, 16, 25]
Добавление по условию:
words = ["Django", "api", "FastAPI", "orm"]
upper = []
for w in words:
if w[0].isupper():
upper.append(w)
print(upper) # → ['Django', 'FastAPI']
Когда тело цикла — одно выражение, его короче записать генератором списка: [n * n for n in range(1, 6)] или [w for w in words if w[0].isupper()]. Цикл с append остаётся удобнее, если нужны несколько шагов, try/except или break.
Ввод с клавиатуры
Список, который пользователь заполняет до команды «стоп»:
numbers = []
while True:
value = input("Число или «стоп»: ")
if value == "стоп":
break
numbers.append(int(value))
print(numbers)
Число или «стоп»: 10
Число или «стоп»: 20
Число или «стоп»: стоп
[10, 20]
Если числа вводятся одной строкой через пробел, цикл не нужен: numbers.extend(map(int, input().split())).
Не добавляйте в список, который обходите
for n in nums: nums.append(...) никогда не закончится: каждый новый элемент тоже попадает в обход. Обходите копию:
nums = [1, 2, 3]
for n in nums[:]:
nums.append(n * 10)
print(nums) # → [1, 2, 3, 10, 20, 30]
Один и тот же объект в нескольких местах
append кладёт в список ссылку на объект, а не его копию. Если добавить в цикле один и тот же изменяемый список, все элементы окажутся одним объектом:
row = [0, 0]
grid = []
for _ in range(2):
grid.append(row)
grid[0][0] = 1
print(grid) # → [[1, 0], [1, 0]]
Создавайте новый объект на каждой итерации: grid.append([0, 0]) или grid.append(row.copy()). Подробнее о таблицах из списков — в статье про двумерные списки.
Как добавить элемент без дубликатов
Простой вариант — проверить наличие через in:
tags = ["python", "django"]
for tag in ["django", "fastapi", "python", "orm"]:
if tag not in tags:
tags.append(tag)
print(tags) # → ['python', 'django', 'fastapi', 'orm']
Проверка in по списку перебирает все элементы, поэтому на больших данных держите рядом множество уже добавленных значений — поиск в set выполняется за O(1):
items = ["b", "a", "b", "c", "a"]
unique = []
seen = set()
for x in items:
if x not in seen:
seen.add(x)
unique.append(x)
print(unique) # → ['b', 'a', 'c']
print(list(dict.fromkeys(items))) # → ['b', 'a', 'c']
dict.fromkeys() убирает повторы одной строкой и сохраняет порядок первого появления. list(set(items)) тоже уберёт дубликаты, но порядок элементов не гарантирует.
Вставка в отсортированный список: bisect.insort
Если список уже отсортирован, sort() после каждого append не нужен. Функция insort из модуля bisect находит место двоичным поиском и вставляет элемент так, что порядок сохраняется:
import bisect
scores = [10, 20, 40, 50]
bisect.insort(scores, 30)
print(scores) # → [10, 20, 30, 40, 50]
bisect.insort(scores, 20) # равный элемент встаёт после существующих
print(scores) # → [10, 20, 20, 30, 40, 50]
С Python 3.10 есть параметр key — для сортировки по полю:
import bisect
users = [("Анна", 19), ("Борис", 25), ("Вера", 31)]
bisect.insort(users, ("Глеб", 27), key=lambda u: u[1])
print(users) # → [('Анна', 19), ('Борис', 25), ('Глеб', 27), ('Вера', 31)]
Поиск места занимает O(log n), но сама вставка сдвигает элементы, поэтому итоговая сложность — O(n). Для списка, который сначала полностью заполняется, а потом читается, быстрее добавить всё через extend и один раз вызвать sort().
Добавление в список внутри словаря и во вложенный список
Частая задача — сгруппировать значения по ключу: у каждого ключа словаря свой список. setdefault создаёт пустой список при первом обращении к ключу, defaultdict(list) делает это автоматически:
from collections import defaultdict
pairs = [("python", "list"), ("django", "orm"), ("python", "dict")]
groups = {}
for key, value in pairs:
groups.setdefault(key, []).append(value)
print(groups) # → {'python': ['list', 'dict'], 'django': ['orm']}
groups2 = defaultdict(list)
for key, value in pairs:
groups2[key].append(value)
print(dict(groups2)) # → {'python': ['list', 'dict'], 'django': ['orm']}
Во вложенный список добавляют, обратившись к нему по индексу:
matrix = [[1, 2], [3, 4]]
matrix.append([5, 6]) # новая строка
matrix[0].append(99) # элемент в первую строку
print(matrix) # → [[1, 2, 99], [3, 4], [5, 6]]
Производительность: append, insert и deque
Список в Python хранит элементы в непрерывном массиве с запасом свободного места. Поэтому добавление в конец почти всегда быстрое, а вставка в начало или середину сдвигает все последующие элементы.
| Операция | Сложность |
|---|---|
list.append(x) | O(1) амортизированно |
list.extend(k элементов) | O(k) |
list.insert(i, x) | O(n) |
deque.append(x), appendleft(x) | O(1) |
«Амортизированно» означает: изредка список перевыделяет память и отдельный вызов длится дольше, но в среднем время на одно добавление постоянное. Замер на 100 000 добавлений:
from collections import deque
from timeit import timeit
N = 100_000
def list_append():
a = []
for i in range(N):
a.append(i)
def deque_appendleft():
d = deque()
for i in range(N):
d.appendleft(i)
def list_insert_front():
a = []
for i in range(N):
a.insert(0, i)
for f in (list_append, deque_appendleft, list_insert_front):
print(f"{f.__name__:18} {timeit(f, number=1):.4f} с")
list_append 0.0036 с
deque_appendleft 0.0040 с
list_insert_front 1.5187 с
Точные цифры зависят от компьютера, но соотношение устойчиво: insert(0, x) на таком объёме в сотни раз медленнее. Для очереди «добавить с одной стороны, забрать с другой» используйте deque, для обычного накопления — append или генератор списка.
Частые ошибки
a = a.append(x)— переменная становитсяNone. Методыappend,insert,extendвозвращаютNone.appendвместоextend—a.append([3, 4])добавит вложенный список; чтобы добавить элементы, нуженa.extend([3, 4])илиa += [3, 4].extendсо строкой —a.extend("django")добавит шесть символов; для одной строки —append.a + [x]без присваивания — новый список создаётся и теряется, исходный не меняется.insert(-1, x)для добавления в конец — элемент встанет перед последним.- Изменяемое значение по умолчанию в функции копит элементы между вызовами:
def add_tag(tag, tags=[]):
tags.append(tag)
return tags
print(add_tag("a")) # → ['a']
print(add_tag("b")) # → ['a', 'b']
Список по умолчанию создаётся один раз при определении функции. Используйте None и создавайте список внутри:
def add_tag(tag, tags=None):
if tags is None:
tags = []
tags.append(tag)
return tags
print(add_tag("a")) # → ['a']
print(add_tag("b")) # → ['b']
Про аргументы функций подробнее — в статье о функциях в Python.
Частые вопросы
Почему список изменился снаружи функции?
Функция получает ссылку на тот же список, поэтому append внутри неё меняет оригинал. Присваивание items = items + [x] создаёт новый локальный список, и снаружи изменений не видно:
def add_item(items, item):
items.append(item)
def add_item_wrong(items, item):
items = items + [item]
cart = ["хлеб"]
add_item(cart, "молоко")
add_item_wrong(cart, "сыр")
print(cart) # → ['хлеб', 'молоко']
Как добавить элемент в кортеж или строку?
Никак: кортеж и строка неизменяемы, методов append у них нет (AttributeError: 'tuple' object has no attribute 'append'). Создайте новый объект: t = t + (3,) для кортежа, s += "c" для строки. Если элементы часто меняются, храните их в списке.
Как добавить элемент в массив array или NumPy?
У array.array есть те же append, insert и extend, что у списка. np.append(arr, 4) в NumPy возвращает новый массив и не меняет исходный, причём каждый раз копирует данные. Поэтому значения удобнее собрать в список, а затем один раз преобразовать: np.array(values).
Как добавить элементы двух списков по очереди?
Пройдите по парам через zip и добавьте хвост более длинной последовательности:
w1, w2 = "ABCD", "XYZ"
result = []
for a, b in zip(w1, w2):
result.extend([a, b])
result.extend(w1[len(w2):] or w2[len(w1):])
print(result) # → ['A', 'X', 'B', 'Y', 'C', 'Z', 'D']
Как объединить несколько списков в один?
Распаковка собирает новый список из любого числа списков, itertools.chain делает то же для любых итерируемых объектов:
from itertools import chain
a, b, c = [1, 2], [3], [4, 5]
print([*a, *b, *c]) # → [1, 2, 3, 4, 5]
print(list(chain(a, b, c))) # → [1, 2, 3, 4, 5]
Чтобы дописать списки в уже существующий, вызовите extend для каждого из них.
Что быстрее: append в цикле или генератор списка?
На Python 3.12 разница небольшая: в нашем замере на 200 000 элементов оба варианта заняли одинаковое время с точностью до погрешности. Выбирайте по читаемости: простое преобразование — генератор, логика с несколькими шагами — цикл с append.
Итог
Один элемент в конец — append, в конкретную позицию — insert, несколько элементов — extend или +=, несколько элементов в середину — присваивание срезу. Для частых вставок в начало берите deque, для отсортированного списка — bisect.insort, для добавления без повторов — проверку через множество. Остальной синтаксис языка собран в шпаргалке по синтаксису Python.
- #Python
- #list
- #Списки
- #append
- #Синтаксис