Django-Admin.ru

join() в Python: как соединить список в строку

Метод join в Python: как превратить список в строку с разделителем, соединить числа через map(str), чем отличается os.path.join и почему join быстрее +=.

Редакция Django-Admin.ru
· обновлено · 7 мин чтения

Содержание · 10 разделов
  1. Синтаксис str.join
  2. Python: список в строку
  3. Почему не str(list)
  4. Как соединить числа: map(str, …)
  5. join со словарями, строками и другими объектами
  6. join и split — обратные операции
  7. str.join, os.path.join и pathlib: в чём разница
  8. Производительность: join против += в цикле
  9. Частые ошибки
  10. TypeError: sequence item 0: expected str instance, int found
  11. AttributeError: ‘list’ object has no attribute ‘join’
  12. Разделитель в конце строки
  13. Вложенные списки
  14. Частые вопросы
  15. Как вывести список через пробел без скобок?
  16. Как объединить два списка?
  17. Как перечислить элементы через запятую и «и» перед последним?
  18. Можно ли соединить байты через join?
  19. Почему writelines() записал всё в одну строку?
  20. Итог

Метод join() в Python соединяет элементы списка (или любого итерируемого объекта) в одну строку. Короткий ответ: чтобы преобразовать список в строку, вызовите join у разделителя и передайте ему список — ", ".join(["a", "b", "c"]) вернёт 'a, b, c'.

Главное правило: все элементы должны быть строками. Ниже — как соединить список строк и список чисел, какие бывают разделители, чем str.join отличается от os.path.join и почему join быстрее склейки строк в цикле. Примеры проверены на Python 3.12.

Синтаксис str.join

разделитель.join(итерируемый_объект)

Метод принадлежит строке-разделителю, а не списку. Он проходит по элементам, вставляет разделитель между ними (не в начале и не в конце) и возвращает новую строку. Исходный список не меняется.

words = ["Python", "Django", "FastAPI"]
print(", ".join(words))  # → Python, Django, FastAPI
print(" ".join(words))   # → Python Django FastAPI
print("".join(words))    # → PythonDjangoFastAPI
print(" | ".join(words)) # → Python | Django | FastAPI

Если элемент один, разделитель не добавляется; для пустого списка результат — пустая строка ''.

print("-".join(["один"]))  # → один
print(repr("-".join([])))  # → ''

Python: список в строку

Частые варианты разделителей:

lines = ["первая строка", "вторая строка"]
print("\n".join(lines))
первая строка
вторая строка
chars = ["P", "y", "t", "h", "o", "n"]
print("".join(chars))                 # → Python
print("\t".join(["id", "name"]))       # → id	name
print(", ".join(f'"{w}"' for w in ["a", "b"]))  # → "a", "b"

"\n".join(...) — стандартный способ собрать многострочный текст, например перед записью в файл. Пустой разделитель "" склеивает элементы вплотную.

Почему не str(list)

Функция str() тоже превращает список в строку, но вместе со скобками и кавычками — это представление для отладки, а не текст для пользователя:

items = ["яблоко", "груша"]
print(str(items))        # → ['яблоко', 'груша']
print(", ".join(items))  # → яблоко, груша

Как соединить числа: map(str, …)

join не преобразует типы сам. Список чисел приводит к ошибке:

nums = [1, 2, 3]
", ".join(nums)  # → TypeError: sequence item 0: expected str instance, int found

Сначала превратите каждый элемент в строку — через map или генераторное выражение:

nums = [1, 2, 3]
print(", ".join(map(str, nums)))           # → 1, 2, 3
print(" + ".join(str(n) for n in nums))    # → 1 + 2 + 3
print(" ".join(f"{n:02d}" for n in nums))  # → 01 02 03

Вариант с генератором удобен, когда числа нужно ещё и отформатировать. Генератор передаётся прямо в join, без лишних скобок.

join со словарями, строками и другими объектами

join принимает любой итерируемый объект со строковыми элементами:

config = {"host": "localhost", "port": "5432"}
print(", ".join(config))  # → host, port
print("; ".join(f"{k}={v}" for k, v in config.items()))  # → host=localhost; port=5432

print("-".join("abc"))  # → a-b-c
print(" ".join(("кортеж", "тоже", "можно")))  # → кортеж тоже можно

Словарь перебирается по ключам, поэтому join(config) соединяет только ключи. Строка перебирается по символам — так удобно вставить разделитель между буквами. Подробнее о словарях — в статье о dict в Python.

join и split — обратные операции

split делит строку на список, join собирает список в строку. Вместе они решают задачи вроде «заменить разделитель» или «нормализовать пробелы»:

date = "09.10.2026"
print("-".join(date.split(".")[::-1]))  # → 2026-10-09

messy = "  много   лишних    пробелов "
print(" ".join(messy.split()))  # → много лишних пробелов

str.join, os.path.join и pathlib: в чём разница

У str.join и os.path.join похожее имя, но разная задача. os.path.join склеивает части пути и сам подставляет разделитель операционной системы:

import os

path = os.path.join("media", "uploads", "photo.jpg")
print(path)
# Windows:        media\uploads\photo.jpg
# Linux и macOS:  media/uploads/photo.jpg

Не собирайте пути через "/".join(...) или +: на Windows разделитель другой, а лишние или пропущенные слеши легко создают ошибки. Учтите и ловушку: если какая-то часть начинается со слеша, всё, что было до неё, отбрасывается — os.path.join("media", "/photo.jpg") вернёт '/photo.jpg'.

Современный способ работы с путями — модуль pathlib, где части соединяются оператором /:

from pathlib import Path

path = Path("media") / "uploads" / "photo.jpg"
print(path.name)       # → photo.jpg
print(path.suffix)     # → .jpg
print(path.as_posix()) # → media/uploads/photo.jpg

print(path) покажет путь с разделителем вашей ОС, а as_posix() всегда использует /.

Производительность: join против += в цикле

Строки в Python неизменяемы, поэтому каждая операция s = s + part создаёт новую строку и копирует в неё всё накопленное. join сначала вычисляет итоговую длину и собирает результат за один проход.

import timeit

parts = [str(i) for i in range(100_000)]

def concat():
    s = ""
    for p in parts:
        s = s + p + ","
    return s

def with_join():
    return ",".join(parts)

print(concat() == with_join() + ",")
print(timeit.timeit(concat, number=1))
print(timeit.timeit(with_join, number=1))

Скрипт печатает True (результаты совпадают) и время каждого варианта в секундах. На тестовом компьютере редакции (Python 3.12.10, Windows 11, 100 000 элементов) склейка в цикле заняла около 4 секунд, а join — около 2–3 миллисекунд. На другом компьютере и в другой версии Python цифры будут другими. Запись вида s += p CPython в некоторых случаях оптимизирует: в том же замере цикл из s += p и s += "," занял около 30 миллисекунд. Но PEP 8 прямо советует не полагаться на эту оптимизацию и использовать "".join(). Правило простое: если строка собирается в цикле, копите части в список и соединяйте один раз в конце.

report = []
for name, score in [("Анна", 95), ("Иван", 88)]:
    report.append(f"{name}: {score}")
print("\n".join(report))
Анна: 95
Иван: 88

Частые ошибки

TypeError: sequence item 0: expected str instance, int found

В списке есть не строка — число, None или другой объект. Номер в сообщении указывает на первый проблемный элемент. Решение — map(str, items) или генератор с str(). Если в данных встречается None, отфильтруйте его: ", ".join(x for x in items if x is not None).

AttributeError: ‘list’ object has no attribute ‘join’

words = ["a", "b"]
words.join(", ")  # → AttributeError: 'list' object has no attribute 'join'

Порядок обратный: метод вызывается у разделителя — ", ".join(words). Как разбирать такие сообщения, описано в статье об ошибках и traceback.

Разделитель в конце строки

join не добавляет разделитель после последнего элемента. Если он всё же нужен (например, перевод строки в конце файла), добавьте его отдельно: "\n".join(lines) + "\n".

Вложенные списки

join работает только с одним уровнем. Список списков сначала разверните или соедините каждую строку отдельно:

table = [["a", "b"], ["c", "d"]]
print("\n".join(" ".join(row) for row in table))
a b
c d

Частые вопросы

Как вывести список через пробел без скобок?

Если строку нужно только напечатать, распакуйте список в print() звёздочкой. print() сам преобразует элементы в строки, поэтому map(str, ...) не нужен:

items = [1, 2, 3]
print(*items)            # → 1 2 3
print(*items, sep=", ")  # → 1, 2, 3

Для сохранения результата в переменную по-прежнему нужен join().

Как объединить два списка?

join() собирает строку, а для объединения списков используют + (новый список) или extend() (дописывает в существующий):

a = ["a", "b"]
b = ["c"]
print(a + b)  # → ['a', 'b', 'c']
a.extend(b)
print(a)      # → ['a', 'b', 'c']

Как перечислить элементы через запятую и «и» перед последним?

Соедините все элементы, кроме последнего, через запятую и добавьте последний отдельно. Список из одного элемента обработайте отдельно:

def human_join(words):
    if len(words) < 2:
        return "".join(words)
    return ", ".join(words[:-1]) + " и " + words[-1]


print(human_join(["Python", "Django", "FastAPI"]))  # → Python, Django и FastAPI
print(human_join(["Python"]))                       # → Python

Можно ли соединить байты через join?

Да, у bytes есть свой join(), но разделитель тоже должен быть байтовым: b"".join(chunks). Смешивать типы нельзя: "".join([b"a"]) вызовет TypeError: sequence item 0: expected str instance, bytes found.

chunks = [b"GET ", b"/ ", b"HTTP/1.1"]
print(b"".join(chunks))  # → b'GET / HTTP/1.1'

Почему writelines() записал всё в одну строку?

file.writelines(lines) записывает элементы подряд и не добавляет переводы строк. Соберите текст через join() и запишите одним вызовом: f.write("\n".join(lines) + "\n").

Итог

Чтобы превратить список в строку, вызывайте join у разделителя: ", ".join(items). Числа и другие объекты сначала преобразуйте в строки через map(str, ...), для путей используйте pathlib, а строки в циклах собирайте в список и соединяйте один раз. Больше приёмов работы с коллекциями — в статье о списках Python и в шпаргалке по синтаксису Python.

  • #Python
  • #join
  • #Строки
  • #Списки
  • #Синтаксис
↑ ↓ выборEnter открытьEsc закрыть