質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.55%

pythonスクリプトから別のpythonスクリプトを実行したい。

受付中

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 227

teityura

score 57

a.pyからb.pyを利用する際、
a.pyにて
import bして、
b.method()のように利用するのが一般的だと思いますが、
b.main()を利用したいです。

しかし、b.pyを単体で利用することもあるため、
b.py arg-a arg-b arg-c のように呼び出したいです。
argparseを利用しており、引数を解析もしたいです。
どういう風に分割するのが一般的なのでしょうか。

具体的には、
enter_excelというファイルが下記のようにあり、
execやsubprocess を使って、
exec('enter_excel 山田太郎 シート名 11:00 16:30')
とした場合、結果や値の受け渡しが面倒になりそうなので、
import enter_excel
enter_excel.main()
としたいのですが、enter_excel単体で利用する場合もあり、
main()で引数を取るのも少し抵抗があります。

今は、仕方ないので、
eman = enter_excel.ExcelManager()
eman.edit_book(FPATH_XLSX, 'シート名', enter_excel.WRITER_DICT[dic["sender"]],
dic["start"], dic["end"], dic["name_kanj"], dic["name_kana"], dic["company"], dic["tel"], )
としていますが、ExcelManagerに渡す前に、
dic["start"], dic["end"]を
ArgsManager.valid_dateでチェックしておきたいのです。

a.py b.py があり、
a.pyからb.pyを利用する際、
どういう風に分割するのが一般的なのでしょうか。
分かりづらい質問ですみませんが、よろしくお願いします。

# enter_excel.py
import argparse
from datetime import datetime
import openpyxl

FILE_PATH = r'C:\hoge\piyo\enter.xlsx'

WRITER_DICT = {
    '山田 太郎': ['田中株式会社', '山田 太郎', '03-1111-0001', 'yamada@hoge.com'],
    '山田 次郎': ['田中株式会社', '山田 次郎', '03-2222-0002', 'yamada@hoge.com'],
    '山田 三郎': ['田中株式会社', '山田 三郎', '03-3333-0003', 'yamada@hoge.com'],
    '山田 四朗': ['田中株式会社', '山田 四朗', '03-4444-0004', 'yamada@hoge.com'],
}


# ==============================================================================
# Parse Args
# ==============================================================================
class ArgsManager:
    def __init__(self):
        pass

    def valid_date(self, s):
        try:
            datetime.strptime(s, "%Y/%m/%d %H:%M")
            return s
        except ValueError:
            msg = f"Not a valid date: '{s}'"
            raise argparse.ArgumentTypeError(msg)

    def getargs(self):
        parser = argparse.ArgumentParser(
            prog='enter_excel.py',
            usage=r'''
            ex:
                enter_excel.py '2019/07/01 11:00' '2019/07/07 13:00'
            ''',
            add_help=True,
        )
        parser.add_argument('sender', type=str, help='start')
        parser.add_argument('start', type=self.valid_date, help='start')
        parser.add_argument('end', type=self.valid_date, help='end')
        parser.add_argument('name_kanj', type=str, help='name_kanj')
        parser.add_argument('name_kana', type=str, help='name_kana')
        parser.add_argument('company', type=str, help='company')
        parser.add_argument('tel', type=str, help='tel')
        args = parser.parse_args()

        # return vars(args)  # 辞書で返す
        return args


# ==============================================================================
# Edit Excel
# ==============================================================================
class ExcelManager:
    def __init__(self):
        pass

    def edit_book(self, file_path, sheet_name, sender, start, end, name_kanj, name_kana, company, tel):
        wkbook = openpyxl.load_workbook(file_path)  # ブックを取得
        wksheet = wkbook[sheet_name]  # シートを取得
        self.write_sender(wksheet, sender[0], sender[1], sender[2], sender[3])  # シート編集(記入者)
        self.write_date(wksheet, start, end)  # シート編集(入場予定時刻)
        self.write_human(wksheet, name_kanj, name_kana, company, tel)  # シート編集(入場予定者)
        wkbook.save(file_path)  # 保存する

    def write_sender(self, sheet, company, name_kanj, tel, mail):
        # E15(山田株式会社) O15(山田太郎) E16(050-5555-5555) O16(yamada@yamada.com)
        sheet['E15'] = company
        sheet['O15'] = name_kanj
        sheet['E16'] = tel
        sheet['O16'] = mail

    def write_date(self, sheet, start="1999/01/01 00:00", end="2211/11/11 22:22"):
        start = datetime.strptime(start, '%Y/%m/%d %H:%M')
        end = datetime.strptime(end, '%Y/%m/%d %H:%M')
        # E(2019)年 H(6)月 J(1)日 M(13)時 O(30)分 ~ R(17)時 T(30)分
        sheet['E19'] = str(start.year)
        sheet['H19'] = str(start.month)
        sheet['J19'] = str(start.day)
        sheet['M19'] = str(start.hour)
        sheet['O19'] = str(start.minute)
        sheet['R19'] = str(end.hour)
        sheet['T19'] = str(end.minute)

    def write_human(self, sheet, name_kanj='山田 太郎', name_kana='やまだ たろう', company='山田株式会社', tel='050-5555-5555'):
        # C(山田 太郎) G(やまだ たろう) K(山田株式会社) R(050-5555-5555)
        sheet['C23'] = name_kanj
        sheet['G23'] = name_kana
        sheet['K23'] = company
        sheet['R23'] = tel


# ==============================================================================
# main
# ==============================================================================
def main():
    # 引数解析
    aman = ArgsManager()
    args = aman.getargs()

    # Excel編集
    eman = ExcelManager()
    eman.edit_book(FILE_PATH, '入場申請書', WRITER_DICT[args.sender],
                   args.start, args.end, args.name_kanj, args.name_kana, args.company, args.tel)


if __name__ == "__main__":
    main()
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+1

単体実行用のmain(コマンドライン引数の解析などを行う)と、内部的に使うmain(必要な情報は関数の引数として取る前提。単体実行用のmainからも、bをimportしたスクリプトからも呼び出される可能性がある)を分けてあげてください。
(それぞれ適切な関数名にして)

# b.py
# ...

def 単体実行用main():
    コマンドライン引数の解釈とかいろいろ
    内部用main(解釈した情報とかを引数で渡す)

def 内部使用するmain(引数いろいろ):
    ほげほげ

if __name__ == "__main__":
    単体実行用main()
# a.py
import b

# ...
b.内部使用するmain(必要な情報)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

b.py が直接実行されるときは以下の if の内容が実行されます。

if __name__ == "__main__":
    main()

a.py から import した場合は呼び出されません。
これを使って処理を切り分けてみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

(前の方が回答されているのに加え)
他の手段としては、

Pythonからコマンドを実行するためのモジュールである、
subprocessモジュールが、使いやすいのでないでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.55%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る