Help us understand the problem. What is going on with this article?

超軽量、超高速な配布用Python「embeddable python」

0.wybf0c7nin9.png

追記:18-10-31 パッケージのインストールエラーに対応する方法を追記

Pythonを独立したExeファイルとして書き出すPyInstallerの記事を以前書きました
しかし、この方法よりも実行がより高速、より軽量な方法がありました。
embeddable pythonと呼ばれるもので、Windows限定ではありますが、ダウンロードしてきた圧縮状態なら 7 MB解凍しても 14 MB程度のPython実行環境です。
もちろんこのままではパッケージを使えませんので、そのパッケージ導入方法も合わせて記載します。

公式
3. Windows で Python を使う — Python 3.6.4 ドキュメント

ダウンロード

Python Releases for Windows | Python.org

上記ページにあるWindows x86-64 embeddable zip fileをダウンロードして解凍。
もしくは、WindowsPowerShellで以下を実行。(wgetが使えるため楽だから)

PowerShell
# 作業用フォルダへ移動(適当なところでOK)
cd (適当なところ)
# PowerShellのwgetでファイルをダウンロード(ウィルス対策ソフトに注意)
wget "https://www.python.org/ftp/python/3.6.4/python-3.6.4-embed-amd64.zip" -O "epython_zip.zip"
# 解凍
Expand-Archive -Path epython_zip.zip -DestinationPath epython

0.igcn5ygx4xs.png

最小構成

pythonNN.dll、pythonNN.zip、vcruntime140.dllがあればPythonは動作します。
python.exeは、pythonNN.dllへ引数を送るだけの実行ファイルですので、独自C++に組み込むときは必要ありません。
(pythonNN.zipは圧縮ファイルですが、このままで機能しますので解凍してはいけません。 フォルダ名さえ気をつけていれば解凍しても使えます。詳しくは下部の「エラー対応」項目を参照)

今回は他の構成ファイルを使うのでそのままにしておいてください。

0.9x3kncj8xjq.PNG

PIP

pythonNN._pthファイルを修正。

そのままではget-pip.pyが使えないので、少し手直しをする必要があります。
ダウンロードしてきたファイルの中にあるpython36._pthというファイルをエディタで開いて、

python36._pth
# import site

を、

python36._pth
import site

とコメント解除する必要があります。
python 3.6 embed cannot get pip · Issue #7 · pypa/get-pip · GitHub

それから、https://bootstrap.pypa.io/get-pip.pyのファイルをダウンロードするか、ダウンロード処理をPowerShellで以下の通りに実行。

PowerShell
# 解凍したepythonの中身へ移動
cd epython
# そのままではwgetでダウンロードできないので、下記を実行(PowerShellではデフォルトでTLS1.2が非対応のため)
# 一時的にTLS1.2を有効にします(PowerShellを閉じると解除される)
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
# Wget
wget "https://bootstrap.pypa.io/get-pip.py" -O "get-pip.py"

コマンドプロンプトで作業

これでget-pip.pyが使えるのでインストール作業をしますが、
ここからはコマンドプロンプトで作業します。(PowerShellではモジュールエラーで実行出来なかった。)

0.0v0n1hrp4rv.PNG

要注意点

get-pipに限らず、ルート環境にpythonがインストールされているときはembeddable pythonなのかルート環境なのかを注意して実行すること。(作業フォルダにembeddable pythonがあるかどうか。もしくはpipインストール後にpython -m pip list等でパッケージの中身を見て確認。)

cmd
cd (embeddable pythonのフォルダ)
# 念の為、python.exeがあるディレクトリか確認。
dir
# リストの中にpython.exeがあれば、get-pipをインストール
python get-pip.py

これでpipが使えるようになりました。
ただし、

cmd
# NG
# pip install numpy
# OK
python -m pip install numpy

のようにpython -m pip install (パッケージ名)の書式でなければなりません。

試しにMatplotlibとWxPython

試しにMatplotlibを使ってグラフを書きつつ、wxPythonで描画してみましょう。

Package

以下のようにパッケージをインストール

cmd
python -m pip install numpy
python -m pip install matplotlib
python -m pip install wxpython

テストスクリプト

テストスクリプトは下記URLから引用。
main.pyという名前でpython.exeと同じ階層に保存してください。

スクリプト引用元
python - Embedding a matplotlib figure inside a WxPython panel - Stack Overflow

main.py
#! env python
# -*- coding: utf-8 -*-

from numpy import arange, sin, pi
import matplotlib
matplotlib.use('WXAgg')

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure

import wx

class CanvasPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self, -1, self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        self.SetSizer(self.sizer)
        self.Fit()

    def draw(self):
        t = arange(0.0, 3.0, 0.01)
        s = sin(2 * pi * t)
        self.axes.plot(t, s)


if __name__ == "__main__":
    app = wx.PySimpleApp()
    fr = wx.Frame(None, title='test')
    panel = CanvasPanel(fr)
    panel.draw()
    fr.Show()
    app.MainLoop()

バッチファイルを保存

同じ階層にバッチファイルをmain.cmdという名前で以下のように記載して保存。

main.cmd
# このファイルの位置を作業ディレクトリに
cd /d %~dp0
# main.pyを実行
python.exe main.py

main.cmdを実行するとグラフが描画される。

0.wyhsc17sc2.png

容量

ディレクトリの容量は 183 M程度になりました。
パッケージを含めると流石に容量が大きいですが、しかし、速度はPyInstallerより高速に動いている感じがします。

エラー対応

pipでエラー

python -m pip install パッケージ名

上記のようにパッケージを追加しようとしたときエラーが表示されることがあります。
このエラーの原因は、zipファイル内のlib2to3というパッケージの中身が展開出来ないことによるもののようです。
対応方法としては、
1.同封の「PythonNN.zip」を失敗した時の為にバックアップ、コピーしておく。
2.「PythonNN.zip」をフォルダとして展開。
3.「PythonNN」というフォルダ名から「PythonNN.zip」に変更。

“python setup.py egg_info” failed with error code 1
https://stackoverflow.com/questions/42962765/embedded-python-3-5-python-setup-py-egg-info-failed-with-error-code-1

ModuleNotFoundError: No module named XXX

同じ階層にpyファイルがあり、それをimportしようとしてエラーが発生した場合、その発生箇所よりも前に、以下のスクリプトを追加する。

sys.path.append(os.path.dirname(os.path.abspath(sys.argv[0])))

公式
1. 他のアプリケーションへの Python の埋め込み — Python 3.6.4 ドキュメント
Python/C API リファレンスマニュアル — Python 3.6.4 ドキュメント

mm_sys
deepoculus
ツカザキ病院眼科のAIチームです。医療AI(特に眼科領域)の開発を行うスタートアップ
https://www.tsukazaki-hp.jp/care/ophthalmology/ai
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした