# openpyxl と xlwings の比較

# はじめに

openpyxl と xlwings のどちらかを採用する時の判断とか、一方に慣れている人がもう片方主体のスクリプトを読む手助けとなる為や事務手作りファイルを読み込む処理でよく使う API を纏めました。 自身の書いたスクリプトのメンテナンスは将来のメンテナーに対し後はよろしくって形に持っていく資料で御座います。 にゃーん

使ったのは openpylx 2.5.0, xlwings 0.11.7 辺り

# ライブラリの特徴

| openpyxl https://openpyxl.readthedocs.io/ | xlwings https://www.xlwings.org/ |
|----------------------------------------|---------------------|
| Excel 不要                             | 必要                 |
| 早い                                   | 遅い                 |
| Excel のバグを踏まない                  | バグも互換            |
| 同名ブック処理に問題なし                 | 片側は読み込み専用    | 
| 自己書き換えマクロ化が不能               | 可能                 |
| xlsx/xlsm が扱える                     | Excel が扱えるもの全て |
| ブックを超えたシートのコピーが出来ない    | 制限は Excel に準じる  |
| セル式計算は簡易的                      | 完全                 |
| 結合セルの罫線が崩れる [^結合セルの罫線が崩れる] | 完全                  |
| API が VBA と遠い                      | 近い(実質同じ)        |
| Range が無い、セルのタプルで扱う         | 有る                 |
| PythonからのVBAの実行が不能             | 可能                  |

[^結合セルの罫線が崩れる]: [Styling Merged Cells isn't working](https://bitbucket.org/openpyxl/openpyxl/issues/365/styling-merged-cells-isnt-working)

# 略称の凡例

| 略称  | 名称          | 内容                      |
|-------|--------------|---------------------------|
|       |              |                           |
| px    | openpyxl     |                           |
| xw    | xlwings      |                           |
|       |              |                           |
| apps  | Applications | アプリケーションコレクション |
| app   | Application  | アプリケーション            |
| wbs   | Workbooks    | ワークブックコレクション    |
| wb    | Workbook     | ワークブック               |
| wss   | Worksheets   | ワークシートコレクション    |
| ws    | Worksheet    | ワークシート               |
| rng   | Range        | 範囲                      |
| c     | Range        | 単一セル                   |

<!--
 アプリケーション

[Application オブジェクト (Excel)](https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/application-object-excel)

| openpyxl  | xlwings  | 内容    |
|-----------|----------|---------|
|           | xw.apps              | Application.Windows 相当        |
|           | xw.books.active      | Application.ActiveWorkbook 相当 |
|           | xw.sheets.active     | Application.ActiveSheet    相当 |
|           | app = xw.apps.active | Application                    |
|           | xw.main.App          | Windows 型相当                  |
|           | xw.main.Books        | Workbooks 型相当                |
|           | app.Workbooks        | Application.Workbooks 相当      |

 Workbooks

| openpyxl  | xlwings  | 内容    |
|-----------|----------|---------|
|           |                            |                           |
| 無い      | [xw.main.Books](http://docs.xlwings.org/en/stable/api.html#books) | [Books](https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/workbooks-object-excel) 型相当 |

-->

# API

## Workbook

| openpyxl  | xlwings  | 内容    |
|-----------|----------|---------|
|                                         |                            |                           |
| [px.workbook.workbook.Workbook](http://openpyxl.readthedocs.io/en/default/api/openpyxl.workbook.workbook.html#module-openpyxl.workbook.workbook)           | [xw.main.Book](http://docs.xlwings.org/en/stable/api.html#xlwings.Book)                          | [Workbook](https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/workbook-object-excel) 型相当  |
|                                         |                            |                           |
| wb = px.Workbook()                      | wb = xw.Book()             | 新規ブック                 |
| [wb = px.load_workbook('ブックファイル名')](http://openpyxl.readthedocs.io/en/default/api/openpyxl.reader.excel.html?highlight=load_workbook#module-openpyxl.reader.excel) | wb = xw.Book('ブック名')   | ブックを開く                |
| wb.close()                              | wb.close()                 | 閉じる                     |
|                                         | wb.name                    | ブック名                   |
|                                         | app = wb.app               | Workbook.Application 相当  |
| names = wb.defined_names                | names = wb.names           | Workbook.Names 相当        |
| wss = wb.worksheets                     | wss = wb.sheets            | Workbook.Worksheets 相当   |

## Worksheets

| openpyxl  | xlwings  | 内容    |
|-----------|----------|---------|
| list[[px.worksheet.worksheet.Worksheet](http://openpyxl.readthedocs.io/en/default/api/openpyxl.worksheet.worksheet.html#module-openpyxl.worksheet.worksheet)]  | [xw.main.Sheets](http://docs.xlwings.org/en/stable/api.html#sheets)      | [Worksheets](https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/worksheets-object-excel) 型相当        |
|                                         |                     |                          |
| ws = wb['シート名']                      | ws = wss['シート名'] | シートを返す             |
| ws = [ws for ws in wss if ws.title == 'シート名'][0] |           | シートを返す             |
| ws = wss[0]                             | ws = wss[0]         | 最初のシートを返す        |
|                                         | ws = wss(1)         | 最初のシートを返す        |

## Worksheet

| openpyxl  | xlwings  | 内容    |
|-----------|----------|---------|
|                  |                                     |      |
| [px.worksheet.worksheet.Worksheet](http://openpyxl.readthedocs.io/en/default/api/openpyxl.worksheet.worksheet.html#module-openpyxl.worksheet.worksheet) |  [xw.main.Sheet](http://docs.xlwings.org/en/stable/api.html#sheet) | [Worksheet](https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/worksheet-object-excel) |
|                       |                        |                        |
| ws.title              | ws.name                | シート名               |
|                       | ws.names               | Worksheet.Names 相当   |
|                       |                        |                        |
|                       | [rng = ws.range(...)](http://docs.xlwings.org/en/stable/api.html#xlwings.Sheet.range)         | Worksheet.Range 相当 |
| c = ws.cell(行, 列)   | rng = ws.range((行, 列))    | 単一セル           |
| c = ws['セルアドレス'] | rng = ws['セルアドレス']     | 単一セル           |
| セルの2次元タプル = ws['矩形アドレス'] | rng = ws['矩形アドレス']         | 矩形範囲           |
| [こちら](https://qiita.com/m5knt/items/107896f739c21a41dbcb) を参照 | rng = ws['範囲名']           |            |
| [サンプル](https://qiita.com/m5knt/items/ab56f1d0a783f3422ee3#openpyxl%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB) | rng = ws['テーブル名']       |             |
|                       |                             |             |
| ws.rows [サンプル](https://qiita.com/m5knt/items/ab56f1d0a783f3422ee3#openpyxl%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB)              | [サンプル](https://qiita.com/m5knt/items/ab56f1d0a783f3422ee3#xlwings%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB)               | 有効範囲セルの行処理ジェネレータ |
| ws.values [サンプル](https://qiita.com/m5knt/items/ab56f1d0a783f3422ee3#openpyxl%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB)            | [サンプル](https://qiita.com/m5knt/items/ab56f1d0a783f3422ee3#xlwings%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB)               | 有効範囲セル値の行処理ジェネレータ |

## Range

| openpyxl   | xlwings   | 内容    |
|------------|-----------|---------|
|                      |                   |                 |
| [px.cell.cell.Cell](http://openpyxl.readthedocs.io/en/default/api/openpyxl.cell.cell.html#module-openpyxl.cell.cell) | [xw.main.Range](http://docs.xlwings.org/en/stable/api.html#range) | 単一セルの型 |
| 2次元タプル           | [xw.main.Range](http://docs.xlwings.org/en/stable/api.html#range) | 矩形範囲の型 [Range](https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/range-object-excel) 型相当       |
|                      |                   |         |
| c.value              | rng.value         | 値      |
| c.value              | rng.formula       | 式      |
| c.coordinate         |                   | 相対アドレス |
|                      | rng.address       | 絶対アドレス |
| c.row_idx            | rng.row           | 行      |
| c.col_idx            | rng.column        | 列      |
| c2 = c.offset(行, 列) | rng2 = rng.offset(行, 列) | 相対位置の新インスタンスを返す |

* xlwings は範囲を一度に処理可能であるが openpyxl ではタプルを手繰りセルを操作する必要がある。

## Names Name

名前付き範囲は [こちら](https://qiita.com/m5knt/items/107896f739c21a41dbcb) を参照

# 型

| 表示形式  | 文字列 | 数値     | 通貨             | 会計            |
|----------|-------|-----------|-----------------|-----------------|
| 値       | 1     | 1～       | 1～              | 1～             |
| openpyxl | str   | int/float | int/float       | int/float       |
| xlwings  | str   | float     | decimal.Decimal | decimal.Decimal |

| 表示形式  |  日付             | 日時               | 時刻              |
|----------|-------------------|-------------------|-------------------|
| 値       | 2001/1/1          | 2001/1/1 10:00:00 | 10:00:00          |
| openpyxl | datetime.datetime | datetime.datetime | datetime.time     |
| xlwings  | datetime.datetime | datetime.datetime | datetime.datetime |

# サンプル

## openpyxlサンプル

```python
# ブックを開く
wb = px.load_workbook('book.xlsx', data_only=True) # cell.value が値になる
ws = wb['Sheet1']

# 使用範囲の値(tuple)を取得して出力
print(tuple(ws.values))

# セルを行毎に得て値を出力
for row in ws.rows:
    print([c.value for c in row])

# テーブル情報
tbl = [t for t in ws._tables if t.name == 'テーブル'][0]
cells = ws[tbl.ref]
# テーブルタイトルを取得して出力
print([c.value for c in cells[0]])
# テーブル内容を取得して出力
print([[c.value for c in row] for row in cells[1:]])

# ブックを閉じる
wb.close()
```

## xlwingsサンプル

```python
# 新規Excelインスタンスでブックを開く
app = xw.App()
wb = app.books.open('book.xlsx')

# シートを得る
wss = wb.sheets
ws = wss['Sheet1']

# 使用範囲
u = ws.api.UsedRange
r = u.Row + u.Rows.Count - 1
c = u.Column + u.Columns.Count - 1
rng = ws.range((1, 1), (r, c))

# 使用範囲の値(list)を取得して出力
print(rng.value)

# 行毎の範囲を得て値を出力 (値のみなら rng.value が速い)
for row in rng.rows:
    print([c.value for c in row])

# テーブル内容の範囲
rng = ws['テーブル']
# テーブルタイトルを取得して出力
print(rng.rows[0].offset(-1, 0).value)
#　テーブル内容を取得して出力
print(rng.value)

# ブックを閉じる
wb.close()

# Excelインスタンスを閉じる
app.quit()
```

# 注釈