search
LoginSignup
45
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

[python] シェルからpythonファイルの関数を実行する

どういったときに使うのか

自作したpythonファイル内に大量の関数があり,それらを個別で使用したいが,そのために大量の実行用ファイルを作りたくない,複雑な引数制御を書きたくない,というとき。

例えば,通信試験を行うとき,大量の通信コマンドを任意のタイミングで動かす必要があるため,手動でコマンドライン操作を行うことになると思いますが,そういったときに,もしかしたら本記事の内容が役に立つかもしれません。

本記事の環境

そこまで気にしなくてもいいと思いますが,一応書いておきます。

  • Windows10
  • Python 3.7.3
  • git-bash 4.4.23

ファイルの準備

解説用に次のpyファイルを作ります。引数のないhello関数と2つの引数があるadd関数が書かれています。これをターミナルから実行してみます。

call_test.py
def hello():
    print('hello qiita')

def add(a, b):
    print(a + b)

方法1: pythonのcmdオプションを使う

典型的な方法として,pythonのcmdオプションを使う方法があります。

python -c <command>

pythonを実行するとき,上記のように-cをつけることで後ろのコマンドを実行できます。コマンド内での改行は;で表現します。

これを使って上記のpyファイルの関数を呼び出してみましょう。

hello関数を実行する
python -c "import call_test; call_test.hello()"
実行結果
hello qiita

hello関数が実行されていることがわかると思います。次に,引数がある関数を実行します。

引数がある関数を実行する
a=1
b=2
python -c "import call_test; call_test.add($a,$b)"
実行結果
3

pyファイルを編集せずに済むので,最もよく使われる方法だと思います。ただし,importを書く必要があるため,コマンドが冗長になりやすいという欠点があります。

方法2 : 汎用的なmain関数を作る

状況によっては,やっぱりmain関数を作ったほうがいい場合もあると思います。例えば,初期化処理がimportだけでは済まず,長大なコマンド文が必要になる場合,関数の戻り値に応じた制御が必要な場合,などです。

このとき大事なことは,関数名をmain関数のソースコード上にべた書きしないということです(そこにミスがあったら何の試験をやっているのかわからなくなる)

説明用にmain関数を作りました。先ほどのcall_test.pyに以下のmain関数を追加してください。標準的な引数(任意個数のfloatstr)には対応するように書いたので,割と使いまわせると思います。

import argparse
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('function_name',
                        type=str,
                        help='set fuction name in this file')
    parser.add_argument('-i', '--func_args',
                        nargs='*',
                        help='args in function',
                        default=[])
    args = parser.parse_args()

    # このファイル内の関数を取得
    func_dict = {k: v for k, v in locals().items() if callable(v)}
    # 引数のうち,数値として解釈できる要素はfloatにcastする
    func_args = [float(x) if x.isnumeric() else x for x in args.func_args]
    # 関数実行
    ret = func_dict[args.function_name](*func_args)

使い方は次のようになっています。ファイル名と関数名を並べて指定し,関数内引数が存在する場合は-iオプションの後に指定します。

python <file.py> <関数名> -i <関数内引数>

例えば,先ほどの-cオプションの解説と同様のことは,次のようにできます。

# call_test.py の hello() を実行
python call_test.py hello
# call_test.py の add(1,2) を実行
python call_test.py add -i 1 2

可読性は,やっぱりこっちのほうがいいかなと思います。

さいごに

実はrunpパッケージといったpythonの関数をターミナルから呼び出すことに特化したpythonパッケージがあります。runpはpipで入れられたのですが,残念なことに,python3系には対応していないようでした。3系に対応したrunpのようなパッケージをどなたかご存じであれば,教えてください(時間があれば自分で作りたいけど…)

参考資料

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
What you can do with signing up
45
Help us understand the problem. What are the problem?