Pythonマニア

Pythonを楽しむ!

Author: tettun

OpenPyXLでセルの書式設定を変更

OpenPyXLはPythonからExcelを操作するパッケージですが、今回はOpenPyXLでセルの書式設定を変更する方法を紹介します。 例えばExcelで「01」という値をセルに入力すると、デフォルトのセルの書式設定では数値として認識され「1」となってしまいます。 これをそのまま「01」と入力したければ、セルの書式設定を文字列にしておく必要があります。 このほか数値の小数点以下の桁数を指定したり、パーセンテージの書式に変更したい場合もあるでしょう。 このようにデフォルトの書式設定以外を使いたいければ明示的にセルに書式設定が必要です。これはPythonのOpenPyXLを使った場合も同じです。 セルの書式を文字列に設定する OpenPyXLからセルに書式設定するのは簡単です。次のようにOpenPyXLのCellオブジェクトのnumber_formatプロパティに表示形式を表す文字列を代入するだけです。 <Cellオブジェクト>.number_format = <表示形式文字列> セルの書式を文字列に設定する例でこれをみてみましょう。次のコードを実行すると、A1セルの書式が文字列に設定されます。 import openpyxl wb =openpyxl.Workbook() ws = wb.active cell = ws["A1"] cell.number_format = openpyxl.styles.numbers.FORMAT_TEXT wb.save('セルの書式を文字列に設定.xlsx') コードを実行した後にA1セルの書式設定を確認すると、文字列に設定されていることがわかります。 この例でセルに書式設定を変更しているコードは次の行です。 cell.number_format = openpyxl.styles.numbers.FORMAT_TEXT このようにCellオブジェクトのnumber_formatプロパティに表示形式を表す文字列を代入するだけです。 ここではopenpyxl.styles.numbersモジュールにあらかじめ定義された定数FORMAT_TEXTを代入しています。この定数の値は単なる「'@'」という文字列です。 代入できる値はあらかじめ定義された定数に限られません。number_formatプロパティにはExcelの表示形式を表す文字列を自由に設定できます。 表示形式を表す文字列とは、Excelの「表示形式」の「ユーザー定義」などに設定する文字列のことです。以下の図を参照してください。 例えば次のようにnumber_formatプロパティに設定すると、数値を小数点1桁まで表示します。 import openpyxl wb =openpyxl.Workbook() ws = wb.active cell = ws["A1"] cell.number_format = "0.0" cell.value = 123.456 wb.save('セルの書式を数値に設定.xlsx') 上記のコードを実行するとA1セルは「123.5」と表示されます。 Excelの書式記号の意味 Cellオブジェクトのnumber_formatプロパティに設定するときの、Excelの書式記号が使えることは前述しましたが、その書式記号のいくつかをここでて簡単に説明します。 […]

Pythonの関数が「値渡し」か「参照渡し」かについて決着をつける!

この記事でPythonの関数が「値渡し」か「参照渡し」について決着をつけたいと思います。 さて、いきなり結論を書きますが、Pythonの関数は「値渡し」です。 そしてPythonではすべてがオブジェクトなので、変数(や引数)は値としてオブジェクト参照を持ちます。つまりは関数へ引数を渡すとき、オブジェクト参照が「値渡し」されるので、これを表現する言葉は「参照の値渡し」です。 結論:Pythonの関数は「参照の値渡し」 この記事の残りでは、Pythonの関数の「参照の値渡し」について詳しく解説していきます。 Python公式ドキュメントの見解 関数への引数の渡し方が「値渡し」であることは、Pythonの公式ドキュメント「Python チュートリアル」にも書かれています。その部分を抜粋すると、 関数を呼び出す際の実際の引数(実引数)は、関数が呼び出されるときに関数のローカルなシンボルテーブル内に取り込まれます。そうすることで、実引数は値渡し(call by value)で関数に渡されることになります(ここでの値(value)とは常にオブジェクトへの参照(reference)をいい、オブジェクトの値そのものではありません) はっきりと「値渡し」と書いてあります。 そしてこの文章には脚注が付いていて、次のように記載されています。 実際には、オブジェクトへの参照渡し(call by object reference)と書けばよいのかもしれません。というのは、変更可能なオブジェクトが渡されると、関数の呼び出し側は、呼び出された側の関数がオブジェクトに行ったどんな変更(例えばリストに挿入された要素)にも出くわすことになるからです。 ここには「参照渡しって書いちゃえばいいのかもしれないが、実際は値渡しなのでそうは書けない」と言う迷いがみて取れます。 Pythonの「参照の値渡し」とは Pythonの関数への引数の渡し方は「参照の値渡し」と冒頭で述べました。これは実引数のオブジェクト参照の値が仮引数へ「値渡し」されることを意味します。つまりオブジェクト参照のコピーが仮引数に渡されます。 「参照の値渡し」を説明するために、まずは次のような関数を定義します。この関数は引数としてリストを受け取ります。 >>> def change_element(x): ... print(id(x)) ... x[0] = 10 ... x = "str" ... この関数は最初に仮引数xが参照するオブジェクトの識別値(id()関数が返す値)を表示します。それからリストの1番目の要素を変更し、最後に仮引数xの値を文字列オブジェクト("str")へのオブジェクト参照へ変更しています。 この関数を使う次のコードを実行します。 >>> a = [1, 2, 3] >>> id(a) 4429915968 >>> a [1, 2, 3] >>> change_element(a) 4429915968 >>> […]

Pythonオブジェクトの同一性と同値性(==とisの比較の違い)

「2つのオブジェクトが等しいか」を比べるとき、オブジェクトの「同一性(identity)」と「同値性(equivalence)」の2つの比較があります。 同一性と同値性(等価性)とは ある参照が指しているオブジェクトと別の参照が指しているオブジェクトが「同一」であるというのは、2つの参照が同じオブジェクトを指している場合です。つまりオブジェクトの「同一性(identity)」とは、2つの参照が同じオブジェクトを指しているかどうか、言い換えれば2つの参照の値が同じかどうかを判定することです。 一方、2つのオブジェクトが同じ値(内容)であれば2つのオブジェクトは「同値」であるといいます。これは「同値性(equivalence)」の判定です。 実際にこれらの意味をコードで確認してみましょう。 >>> x = [1, 2, 3] >>> y = x >>> z = [1, 2, 3] >>> id(x) 4559016832 >>> id(y) 4559016832 >>> id(z) 4559016576 >>> x [1, 2, 3] >>> y [1, 2, 3] >>> z [1, 2, 3] Pythonのオブジェクトは、オブジェクトごとにユニークな整数値(識別値)を持っています。組み込みのid()関数はこの識別値を返します。 つまり識別値が同じであればオブジェクトは同一です。一方、異なるオブジェクトでは必ず識別値が異なります。 これを踏まえて先程の出力結果を見てみましょう。変数xと変数yが指すオブジェクトの識別値は同じです。つまりこれらの参照はどちらも同じオブジェクを指しています。言い換えれば2つの参照が指すオブジェクトは「同一」です。 一方、変数zが参照するオブジェクトの識別値は変数xや変数yが指すオブジェクトの識別値とは異なります。これは変数zが指すオブジェクトと変数xや変数yが指すオブジェクトは「同一ではない」ということになります。 しかし、いずれの変数が指すオブジェクトも同じ値(内容)を持っています。これらのオブジェクトはどれもリストで要素として整数1、2、3を同じ順番で保持しています。 「同値性」に関していうと、変数x、変数y、変数zが指すオブジェクトはいずれも「同値」であるといえます。 同一性の判定には演算子isを使う Pythonで同一性を判定するには演算子isを使います。isはid()関数を使って同一かどうかを判定します。つまり、さっきオブジェクトの識別値を目で見て比較していた方法と同じです。 >>> x […]

Pythonのos.walkでディレクトリツリーを再帰的に辿る

あるディレクトリに含まれるすべてのディレクトリやファイルを処理する場合、osモジュールのos.walk()関数を使うのが簡単です。 Pythonのos.walk()関数は指定されたディレクトリを起点(ルート)として、そこに含まれるディレクトリツリーを再帰的に辿ります。 サンプルとして次のようなディレクトリツリーを例に見ていきましょう。 test_dir/ ├── dir1 │ ├── file1-1 │ └── file1-2 ├── dir2 │ ├── file2-1 │ ├── file2-2 │ └── subdir │ └── subfile └── tmp -> /var/tmp(ディレクトリへのリンク) ツリーのすべてのディレクトリを辿る まずは、os.walk()関数の基本的な動作を見ていきましょう os.walk()関数を呼び出すとジェネレータオブジェクトを返します。 このジェネレータはイテレートされるたびに、辿っているディレクトリの情報を含むタプル(dirpath, dirnames, filenames)を返します。タプルのそれぞれの要素は次の通りです。 dirpath ディレクトリのパス(文字列) dirnames ディレクトリに含まれるディレクトリのリスト(文字列のリスト) filenames ディレクトリに含まれるファイルのリスト(文字列のリスト) 実際に例を見た方が理解が早いでしょう次の例はforでイテレートするごと、ジェネレータから返されるタプルを表示します。 >>> import os >>> for root, dirs, files in os.walk('test_dir'): ... print('root […]

Pythonでgzipを解凍・圧縮する方法をサンプルコードで説明する

Pythonでgzipファイルを圧縮・解凍するにはgzipモジュールを使います。 gzipファイルを圧縮・解凍するのは、Pythonで通常のファイルを読み書きする方法とほとんど同じです。通常のファイル入出力が理解できていればgzipモジュールも簡単に使えます。 Pythonの通常のファイル入出力については「Python3入門 - ファイル入出力」に詳しく書いていますので、必要であれば参照してください。 まずは基本的な概要を説明し、そのあとはサンプルコードを使って実際に動作を見ていきましょう。 gzipファイルを圧縮・解凍する手順 gzipファイルを圧縮や解凍する手順はPythonのファイル入出力の手順と同じです。 with文でgzipファイルをオープンする。これにはgzip.open()関数を使う gzip.open()関数が返すファイルオブジェクトでgzipファイルを読み書きする ファイルを開く時にはwith文を使いましょう。そうすればファイルを自動的にクローズしてくれます。 with文の使用を推奨するのはgzipモジュールのドキュメントに次のような記載があるためです。 圧縮したデータの後ろにさらに何か追加したい場合もあるので、GzipFile オブジェクトの close() メソッド呼び出しは fileobj を閉じません。 このため、書き込みのためにオープンした io.BytesIO オブジェクトを fileobj として渡し、(GzipFile を close() した後に) io.BytesIO オブジェクトの getvalue() メソッドを使って書き込んだデータの入っているメモリバッファを取得することができます。 このようにgzip.open()関数が返すファイルオブジェクトのclose()関数を呼び出しても、下層のファイルオブジェクトが閉じられないかもしれません。 gzipファイルをオープンする gzipファイルをオープンするにはgzip.open()関数を使います。この関数の完全な構文は次の通りです。 gzip.open(filename, mode='rb', compresslevel=9, encoding=None, errors=None, newline=None) 引数modeのデフォルト値は、組み込みのopen()関数と異なっていますので注意してください。gzip.open()関数はデフォルトでバイナリモード(b)でファイルをオープンします。 このように組み込みのopen()関数とデフォルトのmodeが異なるりますので、バイナリモード(b)で開くか、テキストモード(t)で開くか明示的に指定した方がわかりやすいでしょう。つまり「rb」、「ab」、「xb」、「rt」、「at」、「wt」のいずれかを指定します。 引数compresslevelには0から9の整数を指定できます。デフォルトの9は最大限の圧縮(しかし最も低速)を行います。 そのほかの引数は組み込みのopen()関数と同じですので、open()関数のドキュメントを参照してください。 gzipファイルを読み書きする gzip.open()関数が返すファイルオブジェクトは、組み込みのopen()関数が返すファイルオブジェクトと同様の読み込み関数と書き込み関数をサポートしています。 つまり書き込みにはwrite()関数、読み込みにはread()関数、readline()関数、readlines()関数などが使用できます。 ファイルオブジェクトをfor文で使うこともできます。 データからgzip圧縮ファイルを作成する ますは、Pythonのデータからgzip圧縮ファイルを作成する方法から見ていきます。 ここでの例でテキストデータとして次の文字列を使います。 >>> str = '''海が光る ... […]

Python3入門 – ファイル入出力

Pythonプログラムで使用していたデータを永続的に保存するにはファイルが最もよく使われます。 いったんファイルへ保存すれば、後でそれを読み込んでデータを再利用することができます。またファイルからデータを読み込んでPythonに処理させることもよく行われます。 プログラムを書くうえで、ファイル入出力はなくてはならないものです。ここではPythonのファイル入出力の方法を説明します。 ファイル入出力の概要 Pythonでファイルの入出力を行うには、まずファイルを開く必要があります。 ファイルを開くには組み込みのopen()関数を使います。 open()関数の完全な引数とデフォルト値は次の通りです。 open(file, mode='r', buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None) ただし、重要な引数は次の4つだけです。ほとんどの場合、これさえ理解していれば十分です。 open(file, mode='r', encoding=None, newline=None) 引数fileにはファイル名(絶対パスか相対パス)を文字列で指定します。 引数modeは、どのモードでファイルを開くかを指示する文字列を渡します。 一般には次の2つの文字を組み合わせて指定します。 1つは次の文字のいずれかです。 文字意味 r読み込み用に開く(デフォルト) w 書き込み用に開く。ファイルが存在しない場合は作成される。既存ファイルを開くと、まずファイルを空にする x 書き込み用に開く。ファイルが存在しない場合は作成される。ファイルが存在する場合はFileExistsErrorが発生する a 書き込み用に開く。ファイルが存在しない場合は作成される。ファイルが存在する場合は末尾に追記する もう1つには次の文字のいずれかを使います。 文字意味 tテキストモード(デフォルト) bバイナリモード デフォルトの文字は省略することができますが、ここでの例ではすべて明示的に記載します。 open()関数の呼び出しが成功すると、ファイルオブジェクトが返されます。ファイルへの読み書きは、このファイルオブジェクトの関数を使って行います。 最後にファイルは閉じる必要があります。それにはファイルオブジェクトのclose()関数を使います。 書き込み関数でファイルへ書き込んでも、それがすぐにディスクへ書き込まれると考えてはいけません。close()関数を呼び出すと、書き込んだ内容がディスクへも書き込まれることが保証されます。 また、ファイルを開くとOSの限りあるリソースを使います。そのため必要なくなったらすぐにファイルを閉じるのがベストプラクティスです。 残りの引数encodingと引数newlineは後ほど説明します。 テキストファイルの入出力 テキストファイルは文字で構成されます。テキストには行があり、各行は改行コードで区切られます。そして文字列をテキストに保存するにはエンコードする必要があります。これらはバイナリファイルにはないテキストファイルの特徴です。 テキストファイルの入出力では、テキストモード(t)でファイルを開きます。 テキストファイルへの出力 テキストをファイルへ書き込む方法から見ていきましょう。テキストファイルへ書き込むにはモード「wt」、「xt」、「at」のいずれかでファイルを開きます。 いずれも存在しないファイルを開くと、新しくファイルが作成されます。これらの違いは既存のファイルを開くときです。「wt」なら既存のファイルをまず空にしてから書き込みます。「xt」なら例外FileExistsErrorが発生してオープンに失敗します。「at」ば既存のファイルの末尾から書き込みを始めます。 write()によるテキストファイルへの書き込み ファイルへ書き込むテキストとして次の文字列を使います。 >>> text = '''海が光る […]

Python3のipaddressモジュールの使い方

ipaddressモジュールは、IPアドレスやIPアドレスのネットワークを表すクラスを提供しています。 これらのオブジェクトを使うと、IPアドレスがネットワークに含まれるかを確認したり、ネットワークに含まれるIPアドレスを一覧するなど、IPアドレスに関する様々な処理を簡単に行うことができます。 このモジュールには、IPv4用とIPv6用の次のクラスが定義されています。 ipaddress.IPv4Address ipaddress.IPv6Address ipaddress.IPv4Network ipaddress.IPv6Network ipaddress.IPv4Interface ipaddress.IPv6Interface これらのオブジェクトは次の3つのに分類できます。 アドレスオブジェクト IPアドレスを表すオブジェクト(IPv4Address、IPv6Addressオブジェクト)。 「192.168.10.5」のような単一のIPアドレスを表します。 ネットワークオブジェクト ネットワークアドレスを表すオブジェクト(IPv4Network、IPv6Networkのオブジェクト)。 「192.168.10.0/24」のようにネットワークを表します。 インターフェイスオブジェクト インターフェイスを表すオブジェクト(IPv4Interface、IPv6Interfaceのオブジェクト) 「192.168.10.5/24」のようなネットワーク内のIPアドレスを表します。 ipaddressモジュールは、これらのオブジェクトを生成するファクトリー関数も提供しています。ファクトリー関数はオブジェクトの生成には便利ですが詳細を隠してしまうため、先ほど分類したオブジェクトから順に説明していきます。 ファクトリー関数については最後に説明します。 なお、この記事ではIPv4用のクラスについてのみ説明します。IPv6用のクラスについては機会があれば書きたいと思います。 アドレスオブジェクト アドレスオブジェクトはIPアドレスを表すオブジェクトです。IPv4用のIPv4AddressオブジェクトとIPv6用のIP64Addressオブジェクトがあります。 ここではIPv4用のIPv4Addressクラスのみに絞って説明します。 ipaddress.IPv4Addressクラス IPv4AddressクラスはIPv4のIPアドレスを表すクラスです。 IPv4Addressオブジェクトの生成 まずはIPv4Addressオブジェクトの作り方から説明します。このクラスのオブジェクトを生成するには次の関数を使います。 ipaddress.IPv4Address(address) addressには次のいずれかを渡します。 10進数のドット区切り形式。つまり0~255の範囲の4つの10進数をドッド(.)で区切ったもの (例:192.168.0.1) 32ビットに収まる整数 長さ4のbytesオブジェクト(最上位オクテットが先頭) 次の例は、どれも同じIPアドレスを表すIPv4Addressオブジェクトを生成します。 >>> ipaddress.IPv4Address('192.168.100.1') IPv4Address('192.168.100.1') >>> ipaddress.IPv4Address(3232261121) IPv4Address('192.168.100.1') >>> ipaddress.IPv4Address(bytes([192, 168, 100, 1])) IPv4Address('192.168.100.1') bytesオブジェクトの4つの要素は、IPアドレスのそれぞれのオクテットに対応します。 addressがIPv4アドレスとして不正ならAddressValueErrorが発生します。 >>> ipaddress.IPv4Address('192.168.100.256') Traceback (most recent […]

テキストファイルの最後の行は改行コードで終わっているべきか?

テキストの設定ファイルなどで、最後の行を改行コードで終わらすべきか、改行コード無しで終わらすべきかで迷ったことはありませんか? 仕事で使っているアプリケーションの中には、読み込むテキストデータの最後の行に改行を入れてはダメなものがいくつもありました。 その作りはどうなのかと思いますが、このアプリケーション、動作の結果から推測すると最後の改行コードの後、空文字列のデータ行があるように処理をしているように見えました。 Pythonでプログラムを作っているとき、ふと「Pythonで行を読み込んだときはどうなる?」か気になりましたので試してみました。 改行コードで終わっているテキストと終わっていないテキストを読み込む 実際に改行コードで終わっているテキストと終わっていないテキストをPythonで読み込んでみましょう。 最初に読み込むテキストを用意します。str1は改行コード(LF)で終わっている文字列、str2は終わっていない文字列です。これをファイルに書き込みます。 >>> str1 = 'First\nSecond\n' >>> str2 = 'First\nSecond' >>> open('nl_included', 'wt', newline='').write(str1) 13 >>> open('nl_included', 'wt', newline='').write(str2) 12 これをテキストエディタで見ると次のようになります。カーソルがあるところがファイルの末尾です。 さて、これを読み込むとどうなるか見てみましょう。 まずは、改行コードで終わっているファイルです。Pythonに改行コードをいじってほしくないので、open関数に「newline=''」を指定しています。 >>> f = open('nl_included', newline='') >>> included = f.readlines() >>> included ['First\n', 'Second\n'] readlines()は1行ずつ読み出して、1行分の文字列を要素に持つリストを返します。返されたリストを見てみると、2行分の要素があります。 期待していた通りです。最後の改行コードの後に余計なものは付いていません。 改行コードで終わっていないファイルも読み込んでみましょう。 >>> f = open('nl_not_included', newline='') >>> not_included = f.readlines() >>> not_included […]

Python3でファイルを読み書きするとき、改行コードはどうなるの?

Python3でテキストファイルをプログラムに読み込む、あるいはプログラムからテキストをファイルに書き込むときに、改行コードはどうなるんだろう?と思ったことはありませんか。 この記事ではPython3のopen()関数でテキストファイルを読み込むとき改行コードはどうなるの?プログラムがテキストをファイルに書き込むとき改行コードは何になるの?と言った疑問にお答えします。 改行コードとは プログラムを書く方はご存知だろうが、OSによって使用される改行コードは異なります。現在使われている改行コードには次の3つがあります。 LF Line Feed(ラインフィード)と呼ばれる制御文字。Unix、Linux、Macで改行コードとして使われている。エスケープシーケンスで表すと「\n」。 CR Carrige Return(キャリッジリターン)と呼ばれる制御文字。古いMacで改行コードとして使われていた。エスケープシーケンスで表すと「\r」。最近のMacではLFが使われているので、もはやこの改行コードのテキストに出会うことはないかも。 CR+LF(CRLF) 上記の2つの制御文字が連続したもの。Windowsがこれを改行コードとして使っている。 改行コードの違いを意識してプログラミングしないとトラブルになることがあります。 例えばCRLFを期待しているプログラムがLFのみのテキストファイルを読み込むと、CRLFが一つも見つからないので、テキスト全体を1行として読み込んでしまいます。 一方、LFのみの改行コードを期待しているプログラムがCRLFのテキストファイルを読み込むと、行に分割したとき(つまりLFで分割)に、行末にCR文字が残ってしまいます。Windowsで編集したファイルをLinuxなどに持っていく場合、よくこのミスで問題が起きます。 なお改行コードCRは、現在あまり使われていませんので、この記事では詳しく扱いません。 open()関数のnewline引数 open()関数には改行コードを制御するnewlineという引数があります。ファイルの読み書き時に改行コードがどうなるかは、実はこのnewline引数に渡す値によって決まります。 なお、改行コードはテキストファイル特有のものですので、ファイルをテキストモード以外で開いた場合は改行コードを気にする必要はありません(改行コードは制御文字なのでそもそも改行コードは存在しない)。 この後はにファイルを読み込むときと書き込むときに分けて順に説明します。 open()関数でテキストファイルを読み込むときの改行コード まずはopen()関数でテキストファイルを読み込んだときの改行コードについて説明します。 newline引数に渡す値と、そのときの動作を次の表にまとめました。 newline引数の値動作の説明 None universal newlinesモードが有効になる。従って、読み込むとき「\n」、「\r」、「\r\n」を改行コードと認識する。認識された改行コードは呼び出し元へ返す前に「\n」に変換される。 '' universal newlinesモードが有効になる。従って「\n」、「\r」、「\r\n」を改行コードと認識する。改行コードは変換されないでそのまま呼び出し元へ返される。 '\n', '\r', '\r\n' newline引数に指定された文字列を改行コードと認識する。改行コードは変換されず、そのまま呼び出し元へ返される。 newline引数のデフォル値はNoneです。つまりnewline引数を省略するとNoneを渡すのと同じです。 universal newlinesモードとは「\n」、「\r」、「\r\n」のいずれでも柔軟に改行コードとして認識するモードです。例えばCRLFのファイルを読み込むと「\r\n」が改行コードと認識され、 LFのファイルなら「\n」が改行コードと認識されます。 つまり、universal newlinesモードが有効であれば、プログラムではテキストファイルにどんな改行コードが使われているかを意識せずに、行の処理ができるようになります。 newline数にそれぞれの値を渡したときの実際の動作例は、後ほど説明します。 open()関数でテキストファイルに書き込むときの改行コード open()関数でテキストファイルにテキストを書き込むとき、newline引数に渡す値にどのような動作になるかは、次の表のようになります。 newline引数動作の説明 None 書き出すテキストの「\n」を、システムデフォルトの改行コード os.linesep に変換する。 '' または '\n' テキストは何も変更されず、そのまま書き出される。 '\r' または '\r\n' […]