Перейти к содержанию

192 уроков, 14 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 7 из 20 Средний 40 мин 130 XP

Ширина столбцов и высота строк в openpyxl

Длинные названия больше не обрезаются: column_dimensions задаёт ширины столбцов, row_dimensions — высоты строк, а автоширина считается циклом по самой длинной строке.

Редакция Питоники

Таблица из прошлых уроков окрашена шрифтом и заливкой, заголовок склеен merge_cells — но «Кофе зерновой, 1 кг» всё равно показывается как «Кофе зернов...». Excel ширины столбцов подбирает мышкой, а openpyxl — присваиванием: у каждого столбца есть настройка ширины, у каждой строки — высоты. В этом уроке закрываем внешний вид таблицы полностью, включая автоматический подбор ширин — фирменный приём генераторов прайсов.

Ширина столбца: column_dimensions

Ширины живут в ws.column_dimensions — справочнике столбцов по буквам: "A", "B", "C". Присваивание полю width задаёт ширину.

широкий столбец A
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws["A1"] = "Наименование товара"
ws.column_dimensions["A"].width = 24   # единица - символ шрифта

print("Ширина A:", ws.column_dimensions["A"].width)
print("Ширина B:", ws.column_dimensions["B"].width)
Вывод
Ширина A: 24.0
Ширина B: 13.0

Столбец A получил ширину 24, а B отвечает 13.0 — значение по умолчанию внутри openpyxl для столбца, которому ширину не назначали; в файл оно не пишется, и Excel рисует такой столбец своей стандартной шириной, чуть больше восьми символов. Важна сама единица измерения: ширина считается не в пикселях и не в сантиметрах, а в символах стандартного шрифта книги. Число 24 означает «вмещает примерно 24 символа шрифта по умолчанию».

НастройкаКлючЕдиница
Ширина столбцаcolumn_dimensions["A"].widthсимволы стандартного шрифта
Высота строкиrow_dimensions[1].heightпункты, как размер шрифта
Скрытие столбцаcolumn_dimensions["B"].hiddenTrue / False
столбец можно и спрятать
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws["A1"] = "виден"
ws["B1"] = "скрыт"
ws.column_dimensions["B"].hidden = True    # столбец исчезнет из вида

print("Скрыт B:", ws.column_dimensions["B"].hidden)
print("Скрыт A:", ws.column_dimensions["A"].hidden)
Вывод
Скрыт B: True
Скрыт A: False

У столбца в том же справочнике есть и другие переключатели: hidden прячет служебные колонки — техпаспорта, внутренние артикулы, — не удаляя их из файла. Работает это в паре с шириной: спрятанный столбец сохраняет свою настройку и вернётся, когда hidden сбросят в False.

Высота строки: row_dimensions

Строки адресуются в ws.row_dimensions номерами — без букв. Высота меряется в пунктах, как размер шрифта: стандартная строка Excel для кегля 11 — около 15 пунктов, шапке с крупным шрифтом дают 22–30.

Зачем вообще трогать высоту, если Excel подбирает её сам? Две причины. Первая — дизайн: шапке с жирным шрифтом 12 пунктов нужен воздух, иначе текст упирается в границы, нарисованные в прошлом уроке. Вторая — контроль: высота, заданная явно, не изменится, когда файл откроют в другой версии Excel или LibreOffice, а автоподбор там может сработать иначе. Управляешь высотой — управляешь тем, как файл выглядит у всех.

высокая строка шапки
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws["A1"] = "Шапка"
ws.row_dimensions[1].height = 30       # высота строки в пунктах

print("Высота 1:", ws.row_dimensions[1].height)
print("Высота 2:", ws.row_dimensions[2].height)
Вывод
Высота 1: 30.0
Высота 2: None

Строке, которой высоту не назначали, соответствует None: настройка не записана, и Excel рисует строку стандартной. Та же логика, что у ширин: присвоил — значение записалось в файл, не присвоил — работает умолчание табличного редактора.

высота под перенос текста
from openpyxl import Workbook
from openpyxl.styles import Alignment

wb = Workbook()
ws = wb.active

ws["A2"] = "Длинное описание, которое занимает несколько строк"
ws["A2"].alignment = Alignment(wrap_text=True, vertical="top")
ws.row_dimensions[2].height = 45      # высоту под перенос задаём сами

print("Перенос:", ws["A2"].alignment.wrap_text)
print("Высота 2:", ws.row_dimensions[2].height)
Вывод
Перенос: True
Высота 2: 45.0

Высота и перенос работают в паре: wrap_text из урока 6 переносит текст по словам, а height отводит под него место — без явной высоты Excel сделает это сам, но в сгенерированных файлах неплохо контролировать результат самим, чтобы строки не сжались при открытии в старых версиях.

Автоширина: считаем по самой длинной строке

Задавать каждую ширину руками — та же ручная работа, от которой мы уходим. Генераторы отчётов считают ширины сами: обходят столбцы, находят самое длинное значение и назначают ширину с запасом. Свойство ws.columns отдаёт столбцы готовыми порциями — кортежами ячеек, а у ячейки есть column_letter — буква её столбца.

автоподбор ширин циклом
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws.append(["Товар", "Цена"])
ws.append(["Кофе зерновой, 1 кг", 690])
ws.append(["Чай чёрный", 120])
ws.append(["Сироп топинамбура", 340])

for column_cells in ws.columns:
    longest = max(len(str(cell.value or "")) for cell in column_cells)
    letter = column_cells[0].column_letter
    ws.column_dimensions[letter].width = longest + 3

for letter in ("A", "B"):
    print(letter, "-", ws.column_dimensions[letter].width)
Вывод
A - 22.0
B - 7.0

Сердце приёма — одна строка: max(len(str(cell.value or "")) for cell in column_cells). Разбираем её по кускам: cell.value or "" подставляет пустую строку вместо None — иначе len(None) упадёт с TypeError; str(...) превращает числа в строки, чтобы их длина тоже считалась; max выбирает длиннейшее. К нему добавляем запас в три символа — и ни одно название не обрежется. Для столбца A победила строка из 19 символов «Кофе зерновой, 1 кг», плюс три — двадцать два.

Всё это опирается на два свойства листа: ws.columns отдаёт столбцы кортежами ячеек, ws.rows — строки. Размеры листа считаются простым len по спискам — пригодится и для проверок «а там вообще есть данные?».

сколько строк и столбцов
from openpyxl import Workbook

wb = Workbook()
ws = wb.active
ws.append(["a", "b", "c"])
ws.append(["d", "e", "f"])

print(len(list(ws.rows)), len(list(ws.columns)))
Вывод
2 3

Две строки по три ячейки: строк две, столбцов три. Числа совпадают с max_row и max_column из урока 4, но через rows и columns ты получаешь сами ячейки — со стилями, которые пригодятся, когда размеры и оформление нужно считать одновременно.

Столбцы — буквами, строки — числами

Автоподбор — не единственный способ считать ширины. Если у таблицы фиксированная структура, ширины удобно держать в словаре-конфигурации: колонка — ширина. Такой словарь живёт в начале скрипта, правится в одном месте и применяется циклом.

ширины из словаря
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws.append(["Итог", "Комментарий"])
widths = {"A": 10, "B": 40}
for letter, width in widths.items():
    ws.column_dimensions[letter].width = width

print(ws.column_dimensions["A"].width, ws.column_dimensions["B"].width)
Вывод
10.0 40.0

Словарь можно отдать параметром командной строки или прочитать из настроек — и один и тот же скрипт начнёт генерировать прайсы под разные шаблоны. Между «считать по содержимому» и «задать руками» есть и гибрид: автоширина с потолком — min(longest + 3, 60), чтобы описание на абзац не растянуло столбец на весь экран.

Самая коварная опечатка темы: справочники похожи, а ключи у них разные. Столбец — буква в кавычках, строка — число без кавычек. Перепутаешь — никакой ошибки не будет.

тихая опечатка
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws.column_dimensions["1"].width = 20   # опечатка: цифра вместо буквы A
ws.row_dimensions["2"].height = 25     # и тут: строка вместо числа

print("Столбец A настроен:", "A" in ws.column_dimensions)
print("Столбец '1' настроен:", "1" in ws.column_dimensions)
print("Строка 1 настроена:", 1 in ws.row_dimensions)
print("Строка '2' настроена:", "2" in ws.row_dimensions)
Вывод
Столбец A настроен: False
Столбец '1' настроен: True
Строка 1 настроена: False
Строка '2' настроена: True

Отсюда же — совет для функций-обёрток: если ширина приходит параметром, приводи ключ к букве на входе. В openpyxl нет отдельного исключения «нет такого столбца»: справочник column_dimensions принимает любой ключ как приказ создать настройку. Хорошая обёртка валидирует буквы столбцов заранее — например, проверкой, что ключ состоит из латинских букв и входит в диапазон от A до XFD.

Ширины и высоты живут в файле

Настройки размеров — часть xlsx, как стили и значения: сохранил — они переживают закрытие, открыл через load_workbook — они на месте. Это удобно для скриптов, которые дочитывают и дочищают готовые файлы.

Из этого следует и рабочая привычка: размеры задавай до сохранения, одним куском с данными. Скрипт, который создаёт файл, знает про него всё — и длины текстов, и число строк; откладывать настройку ширин «на потом» в другом скрипте значит снова собирать эти знания по крохам. Генератор, который отдаёт файл сразу готовым к показу, — признак зрелого кода.

размеры переживают сохранение
from openpyxl import Workbook, load_workbook
import os

wb = Workbook()
ws = wb.active
ws["A1"] = "Отчёт"
ws.column_dimensions["A"].width = 30
ws.row_dimensions[1].height = 24
wb.save("report-l7.xlsx")

book = load_workbook("report-l7.xlsx")   # ширины и высоты сохраняются в файле
sheet = book.active
print("Ширина A:", sheet.column_dimensions["A"].width)
print("Высота 1:", sheet.row_dimensions[1].height)

os.remove("report-l7.xlsx")
Вывод
Ширина A: 30.0
Высота 1: 24.0

Первая программа: прайс с автошириной

прайс, который не обрезается
from openpyxl import Workbook
import os

wb = Workbook()
ws = wb.active

ws.append(["Товар", "Цена, руб.", "Остаток"])
for row in [
    ["Кофе зерновой, 1 кг", 690, 14],
    ["Чай чёрный", 120, 40],
    ["Сироп топинамбура", 340, 9],
]:
    ws.append(row)

ws.row_dimensions[1].height = 22     # шапке - чуть больше воздуха

# автоширина: по самой длинной ячейке каждого столбца
for column_cells in ws.columns:
    longest = max(len(str(cell.value or "")) for cell in column_cells)
    ws.column_dimensions[column_cells[0].column_letter].width = longest + 3

for letter in ("A", "B", "C"):
    print(letter, ws.column_dimensions[letter].width)

wb.save("price-l7.xlsx")
os.remove("price-l7.xlsx")
Вывод
A 22.0
B 13.0
C 10.0

Обрати внимание на столбец B: самое длинное значение — три символа «690», но победила шапка «Цена, руб.» из десяти символов, плюс запас — тринадцать. Автоподбор считает и заголовки тоже, и это правильно: шапка обрезается ничуть не лучше, чем данные. Внешний вид прайса теперь закрыт целиком: стили из пятого урока, объединение и выравнивание из шестого, размеры отсюда. Дальше по курсу — числовые форматы: рубли, проценты и разделители разрядов, о которых Excel мечтает, когда видит голые числа.

  • запас два-три символа — для цифр и коротких слов;
  • запас четыре — для кириллицы с заглавными и длинных названий;
  • объединённые ячейки и переносы в расчёт не включай — считай только строки данных;
  • проверяй результат глазами в Excel: ширина в символах — приближение, а не пиксельная точность.

Что дальше

Ты умеешь задавать размеры вручную и считать их сам: column_dimensions для столбцов, row_dimensions для строк, цикл с max(len(...)) для автоширины. Это последний урок «внешнего вида» — со следующего openpyxl начинает разговаривать с Excel на языке чисел: форматы рублей и процентов, а затем даты. Сохрани свой скрипт прайса — в десятке уроков он станет основой финального проекта с диаграммой.

И финальный штрих дисциплины: размеры, как и стили, — часть контракта генератора. Файл, который после запуска не нужно дорабатывать мышкой, — это и есть автоматизация; всё, что требует ручной доводки, рано или поздно доедет до того, кто забудет выровнять колонки.

Кнопки «Автоподбор ширины» в openpyxl нет — её заменяют три строки: найти самое длинное значение столбца и назначить width с запасом.

Что выведет код?

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

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws.column_dimensions["A"].width = 20
ws.row_dimensions[2].height = 15

print(ws.column_dimensions["A"].width, ws.row_dimensions[2].height)
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws.append(["SKU", "Название"])
ws.append(["k1", "Молоко"])

for column_cells in ws.columns:
    longest = max(len(str(c.value or "")) for c in column_cells)
    ws.column_dimensions[column_cells[0].column_letter].width = longest + 2

print(int(ws.column_dimensions["A"].width), int(ws.column_dimensions["B"].width))
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

ws["B1"] = "x"
ws.row_dimensions[1].height = 40

print(ws.row_dimensions[1].height, ws.row_dimensions[2].height)
Проверь себя
0 / 5

1. В каких единицах измеряется ширина столбца в openpyxl?

2. Как задать высоту второй строки равной 30?

3. Как в openpyxl реализовать автоподбор ширины столбца?

4. Что будет после ws.column_dimensions["1"].width = 20?

5. Сохраняются ли заданные ширины столбцов в xlsx-файле?

Карточки терминов
Запомнено: 0 / 6
Практика

Собери таблицу курсов: шапка ["Валюта", "Курс"] и две строки — Доллар 93, Евро 100. Задай высоте шапки 26 пунктов, затем посчитай автоширину обоих столбцов: len самой длинной ячейки плюс 2. Выведи ширины столбцов A и B как целые числа, сохрани файл rate-ex-l7.xlsx и удали его.

practice.py
Вопросы и ответы по уроку

Как изменить ширину столбца в Excel через openpyxl?

ws.column_dimensions["A"].width = 24 — по букве столбца. Единица измерения — символ стандартного шрифта, а не пиксель, поэтому значение подбирают с запасом в два-три символа. Автоподбор считается циклом: max(len(str(cell.value or "")) for cell in ws["A"]) плюс запас.

Как задать высоту строки в openpyxl?

ws.row_dimensions[1].height = 30 — по номеру строки, без кавычек. Высота меряется в пунктах, как размер шрифта: стандартная строка — около 15, шапкам с крупным текстом дают 22–30. Не заданной строке соответствует None — Excel рисует её стандартной.

Почему ширина столбца не соответствует заданному числу пикселей?

Потому что width в openpyxl и Excel измеряется в символах стандартного шрифта книги, а не в пикселях: одно и то же число вмещает разное количество текста разными гарнитурами. Пиксели зависят от шрифта и масштаба экрана, поэтому от них и абстрагировались. Подбирай значения по длине содержимого с запасом.

Как сделать автоподбор ширины всех столбцов сразу?

Циклом по ws.columns: для каждого столбца найди max(len(str(cell.value or "")) for cell in column_cells) и назначь width с прибавкой 2–3. Обходить удобно со второй строки, если в шапке сидит объединённый заголовок — иначе его длина раздует первый столбец.

Понравился урок? Сошлитесь на него

«Единица ширины столбца — не пиксель, а символ стандартного шрифта: одно и то же число 20 по-разному вмещает текст узким шрифтом и широким.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.