コンバーターおよびオプション¶
コンバーターはv0.7.0で導入された機能で、Excelのセル範囲やその値の 読み込み 、書き込み 時の変換方法を定義するものです。この機能は、xlwings.Range オブジェクトと User Defined Functions (UDF)の両方で同じように利用できます。
コンバーターを使うには、 Range
オブジェクトの場合は options
メソッドで、UDFの場合は @xw.arg
と @xw.ret
デコレーターで、明示的に指定します。コンバーターの指定が無ければ、読み込み時にはデフォルト コンバーターが適用されます。書き込み時には、Excelに書きこまれるオブジェクトの型に応じて、xlwingsは(可能であれば)適切なコンバーターを自動的に適用します。型に合うコンバーターが無ければ、デフォルト コンバーターにフォール バックします。
以下、全てのサンプル コードは次のインポートを前提としています:
>>> import xlwings as xw
シンタックス:
xw.Range |
UDFs |
|
---|---|---|
読み込み |
|
|
書き込み |
|
|
注釈
キーワード引数(kwargs
)は、特定のコンバーターやデフォルト コンバーターで使用されます。例えば、デフォルトコンバーターの numbers
オプションやDataFrame コンバーターの index
オプションの設定方法は以下のとおりです:
xw.Range('A1:C3').options(pd.DataFrame, index=False, numbers=int).value
デフォルト コンバーター¶
オプションが設定されていない場合の変換は次のとおりです:
単独セルは、Excelセルの値が数字であれば
float
、テキストであればunicode
、日付であればdatetime
、空白であればNone
として読み込まれます。行/列は、リストとして読み込まれます、e.g.
[None, 1.0, 'a string']
2次元のセル範囲は、リストのリストとして読み込まれます、e.g.
[[None, 1.0, 'a string'], [None, 2.0, 'another string']]
以下のオプションを設定できます:
ndim
セル範囲の形に関わらず、強制的に値の次元を1か2にします:
>>> import xlwings as xw >>> sht = xw.Book().sheets[0] >>> sht.range('A1').value = [[1, 2], [3, 4]] >>> sht.range('A1').value 1.0 >>> sht.range('A1').options(ndim=1).value [1.0] >>> sht.range('A1').options(ndim=2).value [[1.0]] >>> sht.range('A1:A2').value [1.0 3.0] >>> sht.range('A1:A2').options(ndim=2).value [[1.0], [3.0]]
numbers
デフォルトでは数字のセルは
float
として読み込まれますが、int
に変更できます:>>> sht.range('A1').value = 1 >>> sht.range('A1').value 1.0 >>> sht.range('A1').options(numbers=int).value 1
それ以外にも、1つのfloat引数を受け取る関数や型を設定することもできます。
UDFでの使用例を以下に示します:
@xw.func @xw.arg('x', numbers=int) def myfunction(x): # all numbers in x arrive as int return x
Note: 内部的にはExcelは常に数字をfloatとして保持しています。そのため、
int
コンバーターは、最初に数字を丸めてから、int
に変換しています。そうしなければ、例えば、5が5よりも僅かに小さい数字として表されている場合には、5は4として返されるためです。Pythonのオリジナルの int が必要であれば、代わりに raw int を使用します。dates
デフォルトでは、日付のセルは
datetime.datetime
として読み込まれますが、datetime.date
に変更することもできます。Range:
>>> import datetime as dt >>> sht.range('A1').options(dates=dt.date).value
UDFs:
@xw.arg('x', dates=dt.date)
それ以外にも、
datetime.datetime
と同じキーワード引数を受け取る任意の関数や型を指定できます。例:>>> my_date_handler = lambda year, month, day, **kwargs: "%04i-%02i-%02i" % (year, month, day) >>> sht.range('A1').options(dates=my_date_handler).value '2017-02-20'
empty
空白のセルはデフォルトでは
None
に変換されますが、次のように変更できます:Range:
>>> sht.range('A1').options(empty='NA').value
UDFs:
@xw.arg('x', empty='NA')
transpose
transposeは読み込み/書き込み時に機能し、例えばリストを列方向に書き込めます:
Range:
sht.range('A1').options(transpose=True).value = [1, 2, 3]
UDFs:
@xw.arg('x', transpose=True) @xw.ret(transpose=True) def myfunction(x): # x will be returned unchanged as transposed both when reading and writing return x
expand
これはRangeの
table
,vertical
,horizontal
プロパティと同じように機能しますが、Rangeの値を取得するときのみ評価されます:>>> import xlwings as xw >>> sht = xw.Book().sheets[0] >>> sht.range('A1').value = [[1,2], [3,4]] >>> rng1 = sht.range('A1').expand() >>> rng2 = sht.range('A1').options(expand='table') >>> rng1.value [[1.0, 2.0], [3.0, 4.0]] >>> rng2.value [[1.0, 2.0], [3.0, 4.0]] >>> sht.range('A3').value = [5, 6] >>> rng1.value [[1.0, 2.0], [3.0, 4.0]] >>> rng2.value [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
注釈
expand
メソッドが使えるのは、Range
オブジェクトのみです。UDFは呼び出し元のセルの操作のみしかできないため、UDFではexpand
メソッドを使えません。chunksize
When you read and write from or to big ranges, you may have to chunk them or you will hit a timeout or a memory error. The ideal
chunksize
will depend on your system and size of the array, so you will have to try out a few different chunksizes to find one that works well:import pandas as pd import numpy as np sheet = xw.Book().sheets[0] data = np.arange(75_000 * 20).reshape(75_000, 20) df = pd.DataFrame(data=data) sheet['A1'].options(chunksize=10_000).value = df
And the same for reading:
# As DataFrame df = sheet['A1'].expand().options(pd.DataFrame, chunksize=10_000).value # As list of list df = sheet['A1'].expand().options(chunksize=10_000).value
ビルトイン コンバーター¶
xlwingsはビルトイン コンバーターを提供しており、これらは、辞書、Numpy arrays, Pandas Series, DataFrame への型変換に対応しています。これらはデフォルト コンバーターを基にしているため、多くのケースで上記のオプションも利用できます(例えば辞書の場合の ndim
のように意味がないこともありますが)。
これら以外の型に対応するカスタム コンバーターの作成や登録もできます(後述)。
以下のサンプルは xlwings.Range
オブジェクトとUDFの両方で使えますが、いずれかで説明します。
辞書コンバーター¶
辞書コンバーターはExcelの2つの列を辞書に変換します。もしデータが行方向なら、 transpose
を使ってください:

>>> sht = xw.sheets.active
>>> sht.range('A1:B2').options(dict).value
{'a': 1.0, 'b': 2.0}
>>> sht.range('A4:B5').options(dict, transpose=True).value
{'a': 1.0, 'b': 2.0}
Note: dict
の代わりに、 collections
の OrderedDict
も使えます。
Numpy array コンバーター¶
options: dtype=None, copy=True, order=None, ndim=None
最初の3つのオプションは、直接 np.array()
を使うときと同じように機能します。また、 ndim
は先述のリスト(デフォルト コンバーター)と同様に機能し、numpyのスカラーや1次元配列、2次元配列を返します。
例:
>>> import numpy as np
>>> sht = xw.Book().sheets[0]
>>> sht.range('A1').options(transpose=True).value = np.array([1, 2, 3])
>>> sht.range('A1:A3').options(np.array, ndim=2).value
array([[ 1.],
[ 2.],
[ 3.]])
Pandas Series コンバーター¶
options: dtype=None, copy=False, index=1, header=True
最初の2つのオプションは、直接 pd.Series
を使うときと同じように機能します。Pandas Seriesは常に列方向への入出力を前提としているため、 ndim
は機能しません。
index
: int or Boolean- 読み込み時、Excel上のデータからインデックスとする列の数を設定します。書き込み時、 インデックスの有無を
True
かFalse
かで設定します。 header
: Boolean- 読み込み時、ExcelにインデックスまたはSeriesの名前がなければ、
False
を設定します。書き込み時、インデックスやシリーズの名前の有無を、True
かFalse
かで設定します。
index
と header
には、1
と True
の両方を使えます。
例

>>> sht = xw.Book().sheets[0]
>>> s = sht.range('A1').options(pd.Series, expand='table').value
>>> s
date
2001-01-01 1
2001-01-02 2
2001-01-03 3
2001-01-04 4
2001-01-05 5
2001-01-06 6
Name: series name, dtype: float64
>>> sht.range('D1', header=False).value = s
Pandas DataFrame コンバーター¶
options: dtype=None, copy=False, index=1, header=1
最初の2つのオプションは、直接 pd.DataFrame()
を使ったときと同じように機能します。Pandas DataFrameは自動的に ndim=2
として読み込むため、ndim
は機能しません。
index
: int or Boolean- 読み込み時、Excel上のデータからインデックスとする列の数を設定します。書き込み時、 インデックスの有無を
True
かFalse
かで設定します。 header
: int or Boolean- 読み込み時、Excel上のデータから列ヘッダーの数を設定します。書き込み時、インデックスやシリーズの名前の有無を、
True
かFalse
かで設定します。
index
と header
には、1
と True
の両方を使えます。
例

>>> sht = xw.Book().sheets[0]
>>> df = sht.range('A1:D5').options(pd.DataFrame, header=2).value
>>> df
a b
c d e
ix
10 1 2 3
20 4 5 6
30 7 8 9
# Writing back using the defaults:
>>> sht.range('A1').value = df
# Writing back and changing some of the options, e.g. getting rid of the index:
>>> sht.range('B7').options(index=False).value = df
同じ例(スクリーンショットで Range('A13')
から始まるもの)は UDF では以下のようになります:
@xw.func
@xw.arg('x', pd.DataFrame, header=2)
@xw.ret(index=False)
def myfunction(x):
# x is a DataFrame, do something with it
return x
xw.Range コンバーターおよび 'raw' コンバーター¶
技術的には、これらは "コンバーターではありません"。
xlwings.Range
オブジェクトに直接アクセスする必要がある場合、次のようにします:@xw.func @xw.arg('x', 'range') def myfunction(x): return x.formula
これはxを
xlwings.Range
オブジェクト、つまり、コンバーターやオプションを何も適用せずに返します。raw
コンバーターは、基礎となるライブラリー(Windowsではpywin32
、Macではappscript
)に変換ぜずに値を渡します。つまり、不要なものの除去やクロスプラットフォーム用の調整がされていない値が作られます。効率化が必要な場合には、この方法が役に立つことがあるかもしれません。例:>>> sht.range('A1:B2').value [[1.0, 'text'], [datetime.datetime(2016, 2, 1, 0, 0), None]] >>> sht.range('A1:B2').options('raw').value # or sht.range('A1:B2').raw_value ((1.0, 'text'), (pywintypes.datetime(2016, 2, 1, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), None))
カスタム コンバーター¶
自身で作成したコンバーターを実装する手順は以下のとおりです:
xlwings.conversion.Converter
を継承します。read_value
メソッドとwrite_value
メソッドをスタティックメソッドまたはクラスメソッドで実装します:read_value
では、value
はbase コンバーターの戻り値です: したがって、base
が特定されなければ、デフォルト コンバーターのものになります。write_value
では、value
はExcelに書き込まれるオリジナルのオブジェクトです。戻り値は、base コンバーターが受け取れる形式でなければなりません。base
が特定されていなければ、デフォルト コンバーターの形式になります。
options
辞書は、xw.Range.options
メソッド(例えば、xw.Range('A1').options(myoption='some value')
)や、UDF使用時の@arg
デコレーターや@ret
デコレーターで指定した、全てのキーワード引数を含みます。 基本的な構造は次のとおりです:from xlwings.conversion import Converter class MyConverter(Converter): @staticmethod def read_value(value, options): myoption = options.get('myoption', default_value) return_value = value # Implement your conversion here return return_value @staticmethod def write_value(value, options): myoption = options.get('myoption', default_value) return_value = value # Implement your conversion here return return_value
Optional: 既存のコンバーターを基にコンバーターを作るには、
base
コンバーター(base
はクラスの名前)をセットします。既存のコンバーターの例はビルトインコンバーターです:DictCoverter
、NumpyArrayConverter
、PandasDataFrameConverter
、PandasSeriesConverter
Optional: コンバーターを登録します: (a) 型を登録すれば、その型を書き込む際ののデフォルト コンバーターになります。そして/または (b) エイリアスを登録すれば、正確なクラス名ではなく、名前でコンバーターを指定できるようになります。
以下の例は理解の助けになるでしょう。ビルトイン DataFrame コンバーターを基に、nanを除去する機能を追加したDataFrame コンバーターを定義しています:
from xlwings.conversion import Converter, PandasDataFrameConverter
class DataFrameDropna(Converter):
base = PandasDataFrameConverter
@staticmethod
def read_value(builtin_df, options):
dropna = options.get('dropna', False) # set default to False
if dropna:
converted_df = builtin_df.dropna()
else:
converted_df = builtin_df
# This will arrive in Python when using the DataFrameDropna converter for reading
return converted_df
@staticmethod
def write_value(df, options):
dropna = options.get('dropna', False)
if dropna:
converted_df = df.dropna()
else:
converted_df = df
# This will be passed to the built-in PandasDataFrameConverter when writing
return converted_df
これらコンバーターの動作の違いを見てみましょう:
# Fire up a Workbook and create a sample DataFrame
sht = xw.Book().sheets[0]
df = pd.DataFrame([[1.,10.],[2.,np.nan], [3., 30.]])
デフォルトのDataFrame コンバーター:
# Write sht.range('A1').value = df # Read sht.range('A1:C4').options(pd.DataFrame).value
DataFrameDropna コンバーター:
# Write sht.range('A7').options(DataFrameDropna, dropna=True).value = df # Read sht.range('A1:C4').options(DataFrameDropna, dropna=True).value
エイリアスの登録(optional):
DataFrameDropna.register('df_dropna') # Write sht.range('A12').options('df_dropna', dropna=True).value = df # Read sht.range('A1:C4').options('df_dropna', dropna=True).value
DataFrameDropnaを、DataFrameに対するデフォルトのコンバーターとして登録(optional):
DataFrameDropna.register(pd.DataFrame) # Write sht.range('A13').options(dropna=True).value = df # Read sht.range('A1:C4').options(pd.DataFrame, dropna=True).value
これらのサンプルはUDFでも同様に機能します。例:
@xw.func
@arg('x', DataFrameDropna, dropna=True)
@ret(DataFrameDropna, dropna=True)
def myfunction(x):
# ...
return x
注釈
Pythonオブジェクトは、複数の変換パイプラインのステージを経て、Excelに書き出されます。反対方向、つまり、Excel/COM オブジェクトがPythonに読み込まれる際も同様です。
内部的には、パイプラインは複数の Accessor
クラスで定義されています。コンバーターは特別なAccessorで、デフォルトAccessorのパイプラインに特別なステージを追加することで、特定の型への/からの変換を行います。例えば、 PandasDataFrameConverter
は、(デフォルトのAccessorが渡す)リストのリストからPandas DataFrameに変換する方法を定めています。
Converter
クラスは、新しいコンバーターを簡単に作るための基本的な枠組みを提供します。もっと細かい操作が必要なら、直接 Accessor
クラスを継承することもできますが、作業が大変になることに加え、現在のところドキュメント化もされていません。