俺言語。

自分にしか理解できない言語で書かれた備忘録

【Python】Pyinstaller specファイル

Pyinstaller Specファイルのメモ

# -*- mode: python -*-

block_cipher = None
a = Analysis(
             [],  # 実行する.pyファイル
             pathex=[''],  # フォルダのパス
             binaries=[],  # 依存するdllファイルがあれば
             datas=[],  # 使用する画像ファイルやPDF
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)

pyz = PYZ(
           a.pure,
           a.zipped_data,
           cipher=block_cipher)

exe = EXE(
          pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False   # 実行時のコンソール表示/非表示
 )

coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='')

Pyinstallerは実行時に
(例:%USERPROFILE%/AppData/Local/Temp/_MEIxxxxxx)
に展開されて実行される。
そのため、埋め込んだ画像ファイル等のリソースがこれを参照して実行するように
変更する必要あり。

【Python】文字列とバイト列と16進数文字列

テキストファイルの文字化けをバイナリ(バイト列)で置換する流れ

℃はutf-8で開くとUnicodeEncodeErrorが発生。
どうやらANSI文字らしい。

utf-8で無理やり扱うためにバイナリで開いて文字列を置換した時の覚え書き

バイナリでテキストをread

ファイルストリームをオープンする際のmode='b'で指定可能。

f = open(file, 'rb')
b = f.readline()  #℃

バイト列 -> 16進数文字列

byte列のメソッド、.hex()で16進数文字列に出力可能。
ここで気を付けるべきは文字列strだということ。

s_hex = b.hex() # => 'b043'

特定文字コードを置換

ここで特定文字コードを置換する。
大文字小文字は区別されるので注意。

s_hex_rep = s_hex.replace('b043', '818b43')

16進数文字列 -> バイト列 -> 文字列

この後コードで文字列を加工する必要があったためいったんutf-8でデコード。
その際はバイト列に戻してから文字列にデコード。
バイト列へはbinasciiモジュールで変換可能。

import binascii
s_rep = _binascii.unhexlify(s_hex_rep).decode('utf-8')

文字列 -> バイト列

ファイルをバイナリで書き込むためにバイト列へエンコード

b_rep = binascii.unhexlify(s_rep)

バイナリでファイル書き込み

w = open(new_file, 'wb')
w.write(b_rep)

【Python】Pyinstallerでnumpyを使ったコードをexe化する際のMKL関連エラー

numpyを使用したコードのexe化トラブル覚え書き

1."Cannot load mkl_intel_thread.dll"

使用しているnumpyのバージョンや仕様によって出てくるエラーが違うようだけど

要はMKLライブラリが見つからないとのこと。

2. 非mklのnumpyでexe化

できればexe化後のファイル容量を小さくしたかったのでmklを使用しない方向でトライ

virtualenvで普通のnumpy(pipを使用)をインストール。

しかし同じエラー、"Cannot load mkl_intel_thread.dll"が発生

次にGohlkeさんのサイトの+vanila仕様をインストールしトライ。…でも変わらず。

[Update] Virtualenvで新しく作った環境の方にPyinstallerが入っていなかったことが上手く行かなかった原因。

Pyinstallerが入っていないことで既存の環境のライブラリを読み込みに行ってしまってた模様。

3. エラーが出ない最小のdll構成を調査

今回のコードでは下記があれば動作することが判明

  • mkl_mc.dll
  • mkl_rt.dll
  • mkl_avx2.dll
  • mkl_core.dll

これでも合計で200Mbyte...。mklとついたdll全部入れると500Mbyteもあるからかなり少なったがけど。。。

【Python】例外処理のひな型

Pythonのエラー処理、毎度どうすればいいのか忘れてしまうので
よく使う形の覚え書き。

import warning
try:
    # エラーが起きそうな処理

Exception PermissionError as e:
    # warningを使うと標準出力に警告として出力できる.
    # e.argsにエラー内容が格納されている
    warning(e.args) 
    raise  # 呼び出し元に例外を返す

Exception Exception as e:
    # ほかのエラーはここで全部拾う
    raise  # 呼び出し元に例外を返す

【Python】配列から値と一致するインデックスを取り出す方法

ListとNumpyで使用感が違う。

Listはインスタンスのメソッドなのに対してnumpyはnumpyクラスのメソッド。 紛らわしい。。

Listの場合

list.index()を使用

a = [1, 2, 3, 4, 5]
b = a.index(3)  # 引数は1つのみ、listで渡せない

> 2

ndarrayの場合

np.where()を使用、引数はndarrayであることと、戻り値がタプルな点に注意

a = [1, 2, 3, 4, 5]  
a = np.array(a)  # 引数がndarrayでないと正しく動かない!?
c = np.where(a==3)

> (array([2], dtype=int64),)  # 戻り値はタプルなので注意!

【Python】配列同士の AND や OR, NOT を取る方法

Boolの配列同士でAND, OR, NOTを取る方法。

listとnumpyで方法が違うので覚え書き (こうゆう操作感の違いは何とかしてほしい...)

配列からTrueの部分だけ抽出するときなんかに便利。
oregengo.hatenablog.com

list の場合

戻り値はlist

a = [True, True, False, False]
b = [True, False, True, False]

# AND
c = a and b
> [True, False, True, False]

# OR
c = a or b
> [True, True, False, False]

# Not
c = not a
> False # 反転にはならない。配列全体が評価されてしまうので注意

numpy の場合

戻り値はndarray. 引数はlistも可

a = [True, True, False, False]
b = [True, False, True, False]

# AND
c = np.logical_and(a, b)
> array([ True, False, False, False])

# OR
c = np.logical_or(a, b)
> array([ True,  True,  True, False])

# Not
c = np.logical_not(a)
> array([False, False,  True,  True]) # ちゃんと反転できる

【Python】0次元のndarrayを1次元に変換

そもそも0次元が存在しているのが意味不明なんだけど、

a = np.array(0)

で作成したndarrayはshape=0のゼロ次元になってしまう。

これでは例えばconcatenateでほかのndarrayと結合しようとすると

b = np.zeros(10)
c = np.concatenate((a, b))
ValueError: zero-dimensional arrays cannot be concatenated

と出てエラーになる。

その時は

b = np.atleast_1d(b)

として1次元に変換してあげると結合可能になる。