11
11

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ファイルを一つのpythonファイルにする

Last updated at Posted at 2020-12-19

やりたいこと

例えば, main.pyが他のファイルを呼び出すようなプロジェクトを...

- main.py
- sub1.py
- folder
    - sub2.py

↓↓↓ 依存してる関数やクラスなどをちゃーんと...

onefile.py

ぎゅ!!!っとする.

(動機としては, プロジェクト管理しているpythonファイルを楽にgoogle colabで実行できないかな〜と思ったからです.)

解決法

こちら, stickytapeというpythonパッケージを使えばOK.
https://pypi.org/project/stickytape/

stickytape = 粘着テープ

実験

実験したコードは全てGithubに公開してますので, 参考までに.

install

これでstickytapeコマンドが使えるようになる. (コマンド名なげぇ...)

$ pip install stickytape

ファイルを用意

以下のような構成とします.

- main.py
- sub1.py
- folder
    - sub2.py

folder/sub2.py

適当にAppleクラスとか作って, 適当にvalueプロパティとか持たせときます.

class Apple:

    def __init__(self, value):
        self.value = value

sub1.py

適当に平均関数とか作っときます.

sub1.py
def mean(a, b):
    return (a+b)/2

main.py

importしてきて適当に計算させて適当に表示します.

from sub1 import mean
from folder.sub2 import Apple

apple1 = Apple(value=100)
apple2 = Apple(value=200)

result = mean(apple1.value, apple2.value)
print(result)

いざ!一つのファイルに!

以下のコマンドを実行します. (もちろんonefile.pyのところは何でもOK)

$ stickytape main.py > onefile.py

結果

以下のようなonefile.pyが生成されます.

#!/usr/bin/env python


import contextlib as __stickytape_contextlib

@__stickytape_contextlib.contextmanager
def __stickytape_temporary_dir():
    import tempfile
    import shutil
    dir_path = tempfile.mkdtemp()
    try:
        yield dir_path
    finally:
        shutil.rmtree(dir_path)

with __stickytape_temporary_dir() as __stickytape_working_dir:
    def __stickytape_write_module(path, contents):
        import os, os.path

        def make_package(path):
            parts = path.split("/")
            partial_path = __stickytape_working_dir
            for part in parts:
                partial_path = os.path.join(partial_path, part)
                if not os.path.exists(partial_path):
                    os.mkdir(partial_path)
                    open(os.path.join(partial_path, "__init__.py"), "w").write("\n")

        make_package(os.path.dirname(path))

        full_path = os.path.join(__stickytape_working_dir, path)
        with open(full_path, "w") as module_file:
            module_file.write(contents)

    import sys as __stickytape_sys
    __stickytape_sys.path.insert(0, __stickytape_working_dir)

    __stickytape_write_module('sub1.py', 'def mean(a, b):\n    return (a+b)/2')
    __stickytape_write_module('folder/sub2.py', 'class Apple:\n\n    def __init__(self, value):\n        self.value = value')
    from sub1 import mean
    from folder.sub2 import Apple
    
    apple1 = Apple(value=100)
    apple2 = Apple(value=200)
    
    result = mean(apple1.value, apple2.value)
    print(result)

一瞬「何じゃこりゃ!?」となりましたが, これを実行すると...

150.0

無事正しい計算結果が表示されました.

Google Colabで実験

先ほどのコードをGoogle Colabにコピペして実行しました.

下のように, 無事150.0が表示されました.

(虹色の猫が歩いてるのは気にしないでください.)

スクリーンショット 2020-06-25 12.38.44.png

スクリプト化

ここからは余談です.

stickytapeというコマンドは長いですし, いちいち生成ファイルのディレクトリを指定するのとか怠いので, 次のようにスクリプト化しておくといいかと思います.

- main.py
- sub1.py
- folder
    - sub2.py
- scripts
    - tape.sh
- build
    - onefile.py
tape.sh
# 初期値
entry="main.py"
output="onefile.py"

# オプション
while getopts e:o: OPT
do
	case $OPT in 
		"e" ) entry=${OPTARG};;
		"o" ) output=${OPTARG};;
	esac
done

# 実行
stickytape ${entry} > "build/${output}"

以下のコマンドで, main.pyを実行し, buildディレクトリにonefile.pyを生成してくれます.

$ sh scripts/tape.sh

オプションも用意しておきました.

オプション名 説明
-e エントリポイントのファイル名
-o アウトプットするファイル名
$ sh scripts/tape.sh -e <ファイル名> -o <ファイル名>

生成されるディレクトリはbuildで固定にしているので, 嫌なら勝手に変えてください.

自己紹介

冒頭に書くと邪魔になるので最後にひっそりと自己紹介させてください。

名前 綿岡晃輝
学校 神戸大学大学院
学部の研究 機械学習, 音声処理
大学院の研究 機械学習, 公平性, 生成モデル, etc
Twitter @Wataoka_Koki

Twitterフォローしてね!

11
11
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
11
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?