pythonプログラムのexe化

Pythonで作ったMakeCaptionWithLogo.pyをPythonに不案内なユーザにも使えるようにexe化することにした。

  • exe化にはpyinstallerを使った。pyinstallerをインストール後にコマンドプロンプトで以下のようなコマンドを入力する:
@echo off 
pyinstaller --onefile --exclude-module numpy \
 --exclude-module ..... --exclude-module ..... \
--exclude-module ..... --exclude-module .....  \
 --noconsole --icon=TOMATO.ico MakeCaptionWithLogo.py

ここで–exclude-moduleオプションはexe化で排除しても無害なモジュールを書く。numpyは大きなモジュールでプログラムでnumpyを使っていないときには積極的に排除する。その他のオプションの説明はここにある。

これでdistフォルダにMakeCaptionWithLogo.exeができる。これがこのファイル1つで配布可能なexeファイルである。サイズは約10MB。排除オプションを外すとサイズは約30MB。排除オプションは有効であることがわかる。

  • この手の配布用のexeファイルを作成するときには仮想環境を使うのが普通らしい。そこでPythonの仮想環境で使う開発環境で述べた仕方で仮想環境を作りこの環境下でexe化を行った。インストールしたモジュールはプログラムに必要なものだけした。できるexeファイルのサイズは10MBを切るだろうと期待したが、この仮想環境下でできたexeファイルのサイズは期待に反して約15MBであった。

 

 

Pythonの仮想環境で使う開発環境

ごつい表題であるが、いつも使っているPythonのプログラミング開発環境を仮想環境でもそのまま使いたということである。

  • Python3.10.4がインストールされているwindows10にそれと同じヴァージョンのPythonの仮想環境を作る:

win10のコマンド・プロンプト(CMD)の窓で

python -m venv [環境を作成したいパス]

ここの[環境を作成したいパス]はユーザ領域で構わない。このpathの中にあるScriptsフォルダにあるactivate.batというバッチファイルをCMDの中で実行すると仮想環境が実現する。詳しくはここを参照。

  • いつもはPythonパッケージに付随して配布されているIDLEをプログラミング開発環境として使っている。この環境を仮想環境の下でも使う。インストールされたそのままではリンクが全て実環境を向いているので、それらのリンクを全て(と言っても2つ)を仮想環境に向ける。

そのために実環境を向いたIDELと別に仮想環境を向いたIDELを作る。まずインストールしたIDELのショートカットを新規につくりそれが仮想環境を向いていることを示す任意の名前する。そのプロパティを開き[リンク先]のpath2つを変更する。
変更前

"C:\.....\Python310\pythonw.exe" \ 
"C:\.....\Python310\Lib\idlelib\idle.pyw"

変更後

"C:.....\PythonEnv\MyEnv\Scripts\pythonw.exe" \
"C:.....\PythonEnv\MyEnv\Scripts\sample.pyw"

ここでsample.pywは以下を中身とするファイルでフォルダScriptsに保存したものでありIDLEが起動される時に実行される:

from idlelib.pyshell import main
main()

詳しくはここを参照のこと。

このIDELを使うことによって実環境の時とほぼ完全に同じ開発環境で仮想環境下でのPythonプログラミングができる。

iphoneでPythonプログラミング(続)

前の投稿でiphoneでPythonプログラミングの基本的な環境を作る話をした。

ところでpc(win10)を使って多くのPythonプログラムを作ってきた。これらがiphoneのPythonで正常に動くか確かめたい。

まずpcにあるプログラムをiphoneに転送する。これには様々な方法があるが今回使ったものはFTPManagerである。win10ではSSHサーヴァを簡単に起動できるのでiphoneではSSHクライアントを起動してsFTPプロトコールによるファイル転送を使う。

FTPManagerをインストールして起動する。「+」アイコンで新規接続を設定する。

サーヴァーのipアドレス
サーヴァーの利用者名
そのパスワード
利用者のホームディレクトリのパス名
これで接続をするとpcのホームディレクトリ下のホルダー・ファイルの一覧が現れる。
それらのホルダーやファイルにはFTPManagerd独自のタグ(3つの点)が付いているので転送したいもののタグをタップするとメニューが出てくる。「にコピー」を選択し、iphone内でFTPManagerが用意した「私のファイル」などを選択「保存」をタップすると転送が始まる。
転送が終わり「私のファイル」をタップすると転送したホルダーやファイルを確認できる。「私のファイル」は他のアプリからは見えないのでホルダーやファイルを移動する。今の目的からa-Shellアプリのディレクトリpythonに移動する。
これにはiphoneの選択・コピー機能を使う。「私のファイル」内にある転送したいファイルをiphoneの選択機能(丸ボタンのタグ)を使い、画面の右下にあるメニューを開き「共有」のタップ、新な画面で「”ファイル”へコピー」の選択。ファイルアプリの画面でコピー先、今の目的ではa-Shellエントリーのpythonホルダーを
選択、保存する。
a-Shellの画面でこのホルダーやファイルがあることを確認する。
Pythonプログラムファイルの実行は以下のよう:
$python ******.py
で実行する。
因みに以下のようなプログラムを実行してみた:

#coding: utf-8
class Garden:
  def __init__(self, plants):
    self.plants = plants
  def __str__(self):
    t = [ object.__str__(self) + '咲いている草花は' ]
    for obj in self.plants:
      s = ' ' + object.__str__(obj)
      t.append(s)
    return '\n'.join(t)

mygarden=Garden(['なずな','はこべら','ほどけのざ'])
print(mygarden)

正常な結果が得られることを確認した。

iphoneでPythonプログラミング

久しぶりのPythonの話題である。

古いiphoneが手元にあったので、これを使ってPythonプログラミングができないか調べてみた。

いろいろなやり方があるが、iOSが持っているPythonを使うのが簡単。そのためにターミナルアプリをインストールした。使ったアプリはa-Shell

a-Shellを起動するとshellの画面が現れる。

$cd
$pwd

を入力するとホームディレクトリが~/Documentsであることがわかる。ここにファイルを作ってよいが他のアプリでアクセスできないのでこのDocuments下にホルダーを作る。

iphoneのファイルアプリを開き「このiphone内」を選ぶとa-Shellのエントリーが見えるのでそれをタップする。ここでホルダーの新規作成をする。ホルダー名を例えば「python」とする。

a-Shellの画面に戻るとDocuments下にpythonというディレクトリができていることがわかる。そこに移動する。このディレクトリをpythonプログラミングの作業場にする。a-Shellではvimエディターが使えるのでプログラム作成にはこれを使う。

尚最新のiOS5.6では既存のPythonのヴァージョン3.11である。

 

 

opencv-pythonのtempファイルへのアクセス

opencv-pythonはPythonで動画を扱うためのモジュールである。このモジュールを使ってlifegameを高速に描画するプログラムを以前に作った。これをwin10で実行しようとするとエラーがでた。エラーはtmpファイルにアクセスできないことから来てることが分かった。実はwin10ではユーザアカウントのユーザ名に日本語を使っていた。それでtempファイルへのpathに日本語が入ってくる。opencv-pythonは非ascii文字に対応していないことからエラーがででる。ここまでわかった。

対応策(ユーザ名を’花子’とする)

  • 管理者としてコマンドプロンプトを開き、ホルダー’花子’が見えるところまで行き以下のコマンドでsymbolic linkを作る:
mklink /D hanako 花子

これで’花子’の内部のファイルに対してascii文字だけの別名’hanako’経由でアクセスできる。通常tempファイルはこの内部にある。

  • opencv-pytonはtempファイルのある場所を環境変数TEMPまたはTMPに記載されているpathで探す(このpath名に日本語が入っているとエラーがででる)。そこでpath名を変更する)。

ユーザ名’花子’でログインしてコマンドプロンプトの窓を開き以下のコマンドを入力する。

C:\Users\花子>set T
TEMP=C:\Users\花子\AppData\Local\Temp
TMP=C:\Users\花子\AppData\Local\Temp

環境変数TEMP及びTMPのpathに日本語が入っていることがわかる。これを以下のコマンドで変更する。

setx TEMP C:\Users\hanako\AppData\Local\Temp
setx TMP C:\Users\hanako\AppData\Local\Temp

これで環境変数TEMPおよびTMPのpathをascii文字だけで定義できる。

この二つの処理でopencv-pythonは正常に動く。

中古ノートPC:dynabook Satellite B554/L

ひょんなことから表記のような中古ノートPC:dynabook Satellite B554/Lを入手した。中古とはいえ我が家で使っている現役のデスクトップと同等かそれ以上のスペックを持っている。

OSはwindows10が入っていたのでそのまま使うことにした。

追加したことと注記しておきたいことを列記する:

  • メモリーを4GBから8GBに増設した。
  • パスワードなしの管理者ユーザが登録されていたのでパスワードを付けた。コマンド:netplwizを使う。
  • 追加したアプリケーション:

Rawtherapeeーデジタルカメラで撮ったRAWデータを閲覧・加工する。

gimp, Inkscapeー画像のレタゥチ及び描画のオープンソフトウエア。

LibreofficeーOffice系のオープンソフトウエア。

Pythonー最新のPython3.10.4を入れた。パッケージで対応していないもの(wxPython)があり、snapshot-buildsから入手した。またPython本体を多数で使う設定でwindowsのpathの記述のテキスト長に問題が起きた。windowsのレジストリー・キーを変更し解決。

Live Texー今まで使っていたwinshellに代わりに新規にLive Texを入手した。

 

Pythonのタートル・グラフィックス(10):canvasに木を描く

Pythonのタートル・グラフィックスはTkinterを基礎に作られているのでTkinterのcanvasウィジェット上にタートル・グラフィックスで描画を行うことは容易である。しかもTkinterのメニューなどの他のウィジェットも画面構成に使える。ここでは本物らしく木を描くタートル・グラフィックスをcanvas上で実行し、入力パラメタをentryウィジェットを使って入力するようにする。サンプル画像を以下に示す:

canvas上の木

左側がcanvasで、右側がentryを含むメニューである。「Turbo Graphics」(安齋利洋・伊吹龍著;1987年)では二種類(単子葉植物、双子葉植物)の木の描画アルゴリズムが載っているがここではメニューで種類を選べるようにしてある。

Pythonのプログラムはここにある。

Pythonのタートル・グラフィックス(9):ヒルベルト(Hirbert)曲線を描く

ヒルベルト曲線

中華どんぶりに描かれているような「一筆書き」である。このような描画はPythonのタートル・グラフィックスが得意とするものである。「Turbo Graphics」(安齋利洋・伊吹龍著;1987年)に載っているPascal風のプログラムをなぞって作ったのが以下のものだ(元のプログラムにあったkameの大域変数は関数の引数とするようにした)。


#coding: utf-8

import myturtle

depth = 7 #再帰の深さ
atom = 3 #最小の長さ

def deko(kame, level):

    if(level == 0):
        return

    else:
        kame.reverse()
        kame.rt(90)
        deko(kame, level-1)
        kame.reverse()
        kame.fd(atom)
        kame.rt(90)
        deko(kame, level-1)
        kame.fd(atom)
        deko(kame, level-1)
        kame.rt(90)
        kame.fd(atom)
        kame.reverse()
        deko(kame,level-1)
        kame.rt(90)
        kame.reverse()
         

if __name__ == '__main__':
      
    kame = myturtle.MyTurtle()
    kame.ht()
    kame.setposition(-300,-300)
    kame.clear()
    deko(kame, depth)

このプログラムでは二つの定数(depth, atom)が定義されているが、atomは描画が画面内に納まるようにするためのものである。定数depthは再帰の深さを示すものでこの曲線にとっては本質的なものである。

定数depthを大きくしたときの描画は実に奇妙である。以下depth=8の例を示す:

ヒルベルト曲線

一本の線分(両端がある)にも拘わらず平面を埋め尽くすような描画ができる。再帰の深さ(depth)を無限大にする極限でこの線分は平面を文字通り埋め尽くして平面を作ることが知られている。

Pythonのタートル・グラフィックス(8):コッホ(Koch)曲線を描く

有名なコッホ(Koch)曲線を描く。「Turbo Graphics」(安齋利洋・伊吹龍著;1987年)に載っているPascal風のプログラムをなぞって作ったのが以下のものだ:


#coding: utf-8

import myturtle

depth = 5 #再帰の深さ

def koch(length, level):
    global kame

    if(level > 0):
        len1 = length /3
        koch(len1, level-1)
        kame.lt(60)
        koch(len1, level-1)
        kame.rt(120)
        koch(len1, level-1)
        kame.lt(60)
        koch(len1, level-1)

    else:
        kame.fd(length)

         

if __name__ == '__main__':
    
        
    kame = myturtle.MyTurtle()
    kame.ht()
    kame.setposition(-320,-0)
    kame.clear()
    koch(640, depth)

【描画】

コッホ(Koch)曲線

複雑であるが折れ線による「一筆描き」である。このような「一筆描き」ではあるセグメントの折れ線ではこれまで描かれた折れ線の先端を起点として一つの折れ線を描き、その折れ線の先端は次の折れ線の起点となるような処理が必要となる。上のプログラムではこれをkameを大域変数(global)とすることで行っている。こうすることでkameが折れ線を描く毎にkameの属性(位置)が更新される。

このような事情を考慮して直接Pythonで書くと以下のようになる:


#coding: utf-8

import myturtle

depth = 5 #再帰の深さ

def koch(kame, length, level):

    if(level > 0):
        len1 = length /3
        koch(kame, len1, level-1)
        kame.lt(60)
        koch(kame, len1, level-1)
        kame.rt(120)
        koch(kame, len1, level-1)
        kame.lt(60)
        koch(kame, len1, level-1)

    else:
        kame.fd(length)

         

if __name__ == '__main__':
    
        
    kame = myturtle.MyTurtle()
    kame.ht()
    kame.setposition(-320,-0)
    kame.clear()
    koch(kame, 640, depth)

このプログラムではkameは関数kochの引数の一つとして関数kochに渡されるようになっている。このプログラムはPascal風の処理系では期待通りの結果は得られないが、Pythonでは上の描画と同じものが得られる。Pythonでは関数に渡されたオブジェクトkameは関数内の変更を受けて実引数のkameの属性も変更されるからだ。

Pythonではkameを大域変数とするプログラムも、kameを関数の引数として渡すプログラムも作れる。後者は少しトリッキーな気もするが。

Pythonのタートル・グラフィックス(7):本物らしく木を描く

「Turbo Graphics」(安齋利洋・伊吹龍著;1987年)には本物らしく木を描画するプログラムが紹介されている。オリジナルのアルゴリズムは本田久夫氏(「樹木の分枝」別冊『数理科学』形・フラクタル、p78)との注がある。

プログラムは描画のためのパラメターをファイルから読み込むなど凝ったものになっているがここでは描画のエッセンスだけを抜き出しPythonで書いてみた:


#coding: utf-8

import myturtle

#パラメター
xP=0
yP=-300
angleMiki=15
ratioMiki = 0.80
angleEda=45
ratioEda=0.70
length=150
ratioFutosa=0.7200
generation=10


class Seed:
    """木の表現のためのパラメター類"""

def ki(tane):

    def edawakare(mikiT, length, thickness, depth):
        if(depth ==0 or length < 2 or thickness < 0.1):
            return
        miki=mikiT.clone()
        miki.reverse()
        miki.fd(length)
        eda=miki.clone()
        miki.lt(tane.angleMiki)
        edawakare(miki, length*tane.ratioMiki, thickness, depth-1)
        eda.rt(tane.angleEda)
        edawakare(eda, length*tane.ratioEda, thickness*tane.ratioFutosa, \
                  depth-1)
        
    miki=myturtle.MyTurtle()
    miki.ht()
    miki.lt(90)
    miki.setposition(tane.xP, tane.yP)
    miki.clear()
    edawakare(miki, tane.length, 1, tane.generation)

if __name__ == '__main__':

    tane=Seed()
    tane.xP=xP
    tane.yP=yP
    tane.angleMiki=angleMiki
    tane.ratioMiki=ratioMiki
    tane.angleEda=angleEda
    tane.ratioEda=ratioEda
    tane.length=length
    tane.ratioFutosa=ratioFutosa
    tane.generation=generation
    
        
    ki( tane)

ここでは関数内ではクローンturtleを使っている。

【実行結果の描画】

タートル・グラフィックスによる木