前提
データサイエンス・機械学習にあこがれてプログラミングを始めた人に、これだけはやっておいて欲しいという計算研究者からの願いを書いておきます。前職のラボ後輩たちが研究成果を外部公開できる形にまとめられていないのがもったいないなと思ったことがあるので、私の思いつくTipsをまとめます。
開発時から実践しておくと開発時間が短縮されるものもあるので試してください。なおVisual Studio Codeの利用は網羅できていません。
logging
を最初から使ってログを出しておく
デバッグ作業をするときにログは重要です。
どこまでの処理が走っていて、どこの処理で躓いているのかを明らかにできます。pythonでは少なくともバージョン3.7以降標準ライブラリとしてlogging
があり、import logging
でいつでもログ出力のライブラリが利用できます。関数やクラスを書いたらlogging
を仕込んで置くのが無難です。logging
のログレベルをいじれば、出力したいログの種類を制限できます。これにより開発環境と本番環境でloglevelを変えれば見せたいログを制御できます。logging.basicConfig
のlevel
引数に指定するだけですのでドキュメントも読みつつ実装しましょう。
以下はサクッと書いたサンプルコードです。
$ cat test.py # ターミナル上で実行
import logging
logging.basicConfig(
format='[%(levelname)s]%(asctime)s: %(message)s',
datefmt='%Y-%m-%dT%H:%M:%S',
level=logging.INFO)
def main():
logger = logging.getLogger(__name__)
logging.info('GUOOOO')
logger.error('WAWAWA')
if __name__ == '__main__':
main()
$ python test.py # ターミナル上で実行
[INFO]2021-09-19T11:42:58: GUOOOO
[ERROR]2021-09-19T11:42:58: WAWAWA
スクリプトではifmain
を使う
Pythonスクリプトを書くときは、変数や関数のスコープに影響されずに処理を書く目的でmain
関数を定義してmain
関数をif __name__=='__main__':
ブロックから呼び出します。if __name__=='__main__':
ブロック内に記述したものだけがファイルをスクリプト実行した際に読み取られます。以下の例では、python main.py
と実行するときだけif __name__=='__main__':
ブロック内が読み取られることになります。これは慣習ですが、そうすることで記述が楽になったりします。
def main():
# 最初に処理の流れを定義して良い
# 冒頭にあることでファイルを開いてすぐに
# ファイル内の関数の使い方の例が示されたことになる。
func_a()
func_b()
# 複数の関数を定義
def func_a():
pass
def func_b():
pass
if __name__ == '__main__':
# スクリプト実行したときだけ以下が読み取られる
main()
C.f. Python Tips: Python で main 関数を定義することのメリット
Jupyterで作った(計算)処理で何度も使用するものがあればスクリプトにして保存しておく
何度も使うJupyter Notebookは、Jupyterで開くのではなくスクリプト実行できるようにしておきましょう。マジで。スクリプト実行とはターミナルやコマンドプロンプトから python script_name.py
と実行することです。入力データがあるときは python script_name.py path/to/data.csv
などとすると入力を与えることができます。
スクリプトに入力を与える一番原始的な方法は、 sys.argv
を用いることです。Pythonに与えた入力全てが配列として与えられるのでスクリプト実行する場合はスクリプト名自体も与えられます。以下のように使います。
$ cat feed.py
import pandas as pd
import sys
def main():
argv = sys.argv
print(argv) # print文でデバッグ
filename = argv[1]
df = pd.read_csv(filename)
print(df.shape)
if __name__ == '__main__':
main()
$ python feed.py data.txt
['feed.py', 'data.txt']
(1, 2)
$ cat data.txt
sample, 10
example, 40
sys.argv
の代わりにargparse.ArgumentParser
を使う
直前で書いたsys.argv
をargparse.ArgumentParser
で書き直していきます。sys.argv
では配列で与えていたので変数を辞書のキーで指定することができませんでした。これは可読性に影響します。
そこで、argparse.ArgumentParser
を使うと柔軟にスクリプトへの入力を指定することができます。以下のスクリプトfeed.py
ではprint文をlogging
へ差し替えました。それっぽいですね。
$ cat feed.py
import pandas as pd
import argparse
import logging
logging.basicConfig(level=logging.INFO)
def main():
parser = argparse.ArgumentParser(description='Description')
parser.add_argument('filename', help='Give csv file name to read with pandas.')
args = parser.parse_args()
logging.info(args) # logging.info文でデバッグ
logging.info(f'args.filename: {args.filename}')
filename = args.filename
df = pd.read_csv(filename)
logging.info(df.shape)
if __name__ == '__main__':
main()
$ python feed.py data.txt
INFO:root:Namespace(filename='data.txt')
INFO:root:args.filename: data.txt
INFO:root:(1, 2)
まとめ
利用シーンにもよりますが、他人に使われなかったら効率が悪いことも多々あります。生産性高く生きていきましょう。