Django-Admin.ru

Как добавить элемент в список в Python: append, insert, extend

Как добавить элемент в список Python: append в конец, insert по индексу и в начало, extend и += для нескольких элементов, без дубликатов, bisect и deque.

Редакция Django-Admin.ru
· 14 мин чтения

Содержание · 14 разделов
  1. Какой способ выбрать
  2. append: добавить элемент в конец списка
  3. insert: вставить элемент по индексу
  4. extend и +=: добавить несколько элементов
  5. Чем += отличается от +
  6. Добавление через срез и распаковку
  7. Как добавить элемент в начало списка
  8. Добавление элементов в цикле
  9. Ввод с клавиатуры
  10. Не добавляйте в список, который обходите
  11. Один и тот же объект в нескольких местах
  12. Как добавить элемент без дубликатов
  13. Вставка в отсортированный список: bisect.insort
  14. Добавление в список внутри словаря и во вложенный список
  15. Производительность: append, insert и deque
  16. Частые ошибки
  17. Частые вопросы
  18. Почему список изменился снаружи функции?
  19. Как добавить элемент в кортеж или строку?
  20. Как добавить элемент в массив array или NumPy?
  21. Как добавить элементы двух списков по очереди?
  22. Как объединить несколько списков в один?
  23. Что быстрее: append в цикле или генератор списка?
  24. Итог

Чтобы добавить элемент в список в 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, вернёт NoneO(n), медленно в начале
a.extend(iterable)в конецвсе из итерируемогоменяет a, вернёт NoneO(k), k — число новых
a += iterableв конецвсе из итерируемогоменяет aкак extend
a[i:i] = [x, y]в позицию iнесколькоменяет aO(n)
a + [x], [*a, x]куда угоднолюбоеновый списокO(n), копирует всё
bisect.insort(a, x)в нужное местоодинменяет a, порядок сохранёнO(n)
deque.appendleft(x)в началоодинменяет очередь dequeO(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
  • #Синтаксис
↑ ↓ выборEnter открытьEsc закрыть