скопировать стиль ячейки openpyxl

Я пытаюсь скопировать лист default_sheet на новый лист new_sheet в той же книге.

Мне удалось создать новый лист и скопировать значения из листа по умолчанию. Как я могу также скопировать стиль каждой ячейки в ячейки new_sheet?

new_sheet = workbook.create_sheet()
new_sheet.title = sheetName
default_sheet = workbook.get_sheet_by_name('default')
new_sheet = workbook.get_sheet_by_name(sheetName)
for row in default_sheet.rows:
    col_idx = float(default_sheet.get_highest_column())
starting_col = chr(65 + int(col_idx))
for row in default_sheet.rows:
    for cell in row:
        new_sheet[cell.get_coordinate()] = cell.value
        <copy also style of each cell>

В настоящее время я использую openpyxl 1.8.2, но я имею в виду перейти на 1.8.5.

Одно решение с копией:

from copy import copy, deepcopy

new_sheet._styles[cell.get_coordinate()] = copy(
        default_sheet._styles[cell.get_coordinate()])

person FotisK    schedule 28.04.2014    source источник
comment
Я нашел способ с копированием, но я не уверен, что это лучший способ, и он не копирует все, например ширину/высоту ячейки!   -  person FotisK    schedule 28.04.2014
comment
Да, вам нужно использовать копию. Каждый рабочий лист содержит словарь стилей ячеек, который можно копировать. Но на самом деле вы хотите попробовать использовать ветку 1.9, которая имеет гораздо более чистый интерфейс для такого рода вещей.   -  person Charlie Clark    schedule 28.04.2014


Ответы (3)


Начиная с openpyxl 2.5.4, python 3.4: (незначительные изменения по сравнению со старой версией ниже)

new_sheet = workbook.create_sheet(sheetName)
default_sheet = workbook['default']

from copy import copy

for row in default_sheet.rows:
    for cell in row:
        new_cell = new_sheet.cell(row=cell.row, column=cell.col_idx,
                value= cell.value)
        if cell.has_style:
            new_cell.font = copy(cell.font)
            new_cell.border = copy(cell.border)
            new_cell.fill = copy(cell.fill)
            new_cell.number_format = copy(cell.number_format)
            new_cell.protection = copy(cell.protection)
            new_cell.alignment = copy(cell.alignment)

Для openpyxl 2.1

new_sheet = workbook.create_sheet(sheetName)
default_sheet = workbook['default']

for row in default_sheet.rows:
    for cell in row:
        new_cell = new_sheet.cell(row=cell.row_idx,
                   col=cell.col_idx, value= cell.value)
        if cell.has_style:
            new_cell.font = cell.font
            new_cell.border = cell.border
            new_cell.fill = cell.fill
            new_cell.number_format = cell.number_format
            new_cell.protection = cell.protection
            new_cell.alignment = cell.alignment
person Charlie Clark    schedule 17.01.2016
comment
Я использую openpyxl 2.4.1, cell.font или cell.border является экземпляром StyleProxy, если сохранить книгу с этим типом, вы получите исключение. Вы должны скопировать его в новую ячейку, например: new_cell.font = copy(cell.font) - person dawncold; 21.01.2017
comment
СПАСИБО, рассвет, мне было интересно, почему я получаю ошибку нехешируемого типа. - person otocan; 18.08.2017
comment
В 2.5.3, fill, protection и alignment также необходимо скопировать. - person Jorge Leitao; 13.05.2018
comment
Отредактировано, чтобы добавить небольшие изменения, необходимые для недавнего openpyxl, включая изменения, упомянутые всеми. Некоторые изменения в атрибутах ячеек также. Большое спасибо Чарли Кларку, который лег в основу того, что мне нужно для объединить файлы xlsx. - person pbarill; 19.06.2018
comment
Стоит отметить, что у рабочих книг уже некоторое время есть метод copy_worksheet, и этот стиль копирования для вас. - person Charlie Clark; 02.07.2018
comment
@CharlieClark Я не думаю, что здесь можно использовать copy_worksheet, см. это предупреждение. - person Stef; 02.10.2019
comment
Этот вопрос касается копирования рабочих листов в одной книге, поэтому проблем не возникнет. - person Charlie Clark; 04.10.2019
comment
Это не работает для объединенных ячеек, и размеры ячеек не сохраняются. - person wbzy00; 07.04.2021

Реализация StyleableObject хранит стили в одном списке, _style и свойства стиля в ячейке фактически являются геттерами и сеттерами для этого массива. Вы можете реализовать копию для каждого стиля отдельно, но это будет медленно, особенно если вы делаете это в загруженном внутреннем цикле, как я.

Если вы хотите копаться в атрибутах частного класса, есть гораздо более быстрый способ клонирования стилей:

if cell.has_style:
    new_cell._style = copy(cell._style)

FWIW вот как оптимизированный класс WorksheetCopy делает это в методе _copy_cells.

person ldrg    schedule 11.07.2018
comment
NamedStyles имеет гораздо больше смысла, если вы хотите использовать один и тот же стиль в нескольких ячейках. - person Charlie Clark; 12.07.2018
comment
Хороший код. Именно то, что мне нужно на данный момент. Но действительно, в некоторых случаях NamedStyles может быть лучшим подходом. - person Jean-Francois T.; 28.02.2019
comment
Спасибо за однострочный ответ - person Vineesh TP; 10.09.2019

Может быть, это удобный способ для большинства.

    from openpyxl import load_workbook
    from openpyxl import Workbook
    read_from = load_workbook('path/to/file.xlsx')
    read_sheet = read_from.active
    write_to = Workbook()
    write_sheet = write_to.active
    write_sheet['A1'] = read_sheet['A1'].value
    write_sheet['A1'].style = read_sheet['A1'].style
    write_to.save('save/to/file.xlsx')
person Avik Samaddar    schedule 22.02.2016
comment
Это не все стили, этот ответ лучше, но необходимо использовать copy. - person dawncold; 21.01.2017