0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【随時更新】プログラム初心者に伝えたい、これだけはやっておいてくれというポイント [#Python 編]

Posted at

前提

データサイエンス・機械学習にあこがれてプログラミングを始めた人に、これだけはやっておいて欲しいという計算研究者からの願いを書いておきます。前職のラボ後輩たちが研究成果を外部公開できる形にまとめられていないのがもったいないなと思ったことがあるので、私の思いつくTipsをまとめます。

開発時から実践しておくと開発時間が短縮されるものもあるので試してください。なおVisual Studio Codeの利用は網羅できていません。

logging を最初から使ってログを出しておく

デバッグ作業をするときにログは重要です。
どこまでの処理が走っていて、どこの処理で躓いているのかを明らかにできます。pythonでは少なくともバージョン3.7以降標準ライブラリとしてloggingがあり、import loggingでいつでもログ出力のライブラリが利用できます。関数やクラスを書いたらloggingを仕込んで置くのが無難です。loggingのログレベルをいじれば、出力したいログの種類を制限できます。これにより開発環境と本番環境でloglevelを変えれば見せたいログを制御できます。logging.basicConfiglevel引数に指定するだけですのでドキュメントも読みつつ実装しましょう。

以下はサクッと書いたサンプルコードです。

$ 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__':ブロック内が読み取られることになります。これは慣習ですが、そうすることで記述が楽になったりします。

main.py

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に与えた入力全てが配列として与えられるのでスクリプト実行する場合はスクリプト名自体も与えられます。以下のように使います。

feed.py
$ 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.argvargparse.ArgumentParserで書き直していきます。sys.argvでは配列で与えていたので変数を辞書のキーで指定することができませんでした。これは可読性に影響します。

そこで、argparse.ArgumentParserを使うと柔軟にスクリプトへの入力を指定することができます。以下のスクリプトfeed.pyではprint文をloggingへ差し替えました。それっぽいですね。

feed.py
$ 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)

まとめ

利用シーンにもよりますが、他人に使われなかったら効率が悪いことも多々あります。生産性高く生きていきましょう。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?