====== Python ======
Pythonは
numpyやPyTorchなどC++やCUDAで実装されたライブラリに
素早くアクセスできる優れたスクリプト言語.
* [[https://docs.python.org/ja/3/index.html|Pythonドキュメント]]
=== 配下ページ ===
* [[.:env:start|環境構築]]
* [[.:numpy:start|NumPy]]
* [[.:opencv:start|opencv]]
* [[.:pytorch:start|PyTorch]]
* [[.:matplotlib:start|matplotlib]]
* [[.:tensorflow:start|TensorFlow]]
* pillow (''from PIL import Image'')
* [[.:pptx:start|python-pptx]]
* [[.:detectron2:start|detectron2]]
* [[.:autogluon:start|autogluon]]
===== 保存関係 =====
pickle
with Path('hoge.pkl').open('wb') as f:
pickle.dump(save_obj, f)
with Path('hoge.pkl').open('rb') as f:
save_obj = pickle.load(f)
npz
np.savez( Path('hoge.npz'), **{'a':array_a, 'b':array_b} )
with np.load(Path('hoge.npz'), allow_pickle=True) as load_dict:
load_dict = {k:v for k,v in load_dict.items()}
===== Jupyter =====
==== JupyterLab ====
jupyter labで起動.デフォルトでは''8888''ポートで立てられる.
ポート指定して立てたい場合は
jupyter lab --port XXXXX
とすれば良い.
立てると自動でブラウザが起動されるはずだが、できないこともある.
アクセスするには起動時に出てきたtokenでアクセスすれば良い.
http://localhost:8888/?token=xxxxxxxx
ssh経由でアクセスするならssh -L ローカル側ポート:localhost:サーバー側ポート サーバー
=== gitでjupyter notebook管理 ===
python環境下に ''nbstripout'' コマンドを入れておくと,
gitコミットにnotebookの出力が入らないようにできる.
以下を最初にやっておく
pip install --upgrade nbstripout
nbstripout --install --attributes .gitattributes
git add .gitattributes
あとは ''git commit'' 時に自動的にやられる.
==== jupyter ====
=== サブコマンド一覧 ===
jupyter のサブコマンドをリストアップするには、
jupyter- と入力してタブ補完で探すのが良さそう。
jupyter のサブコマンドは jupyter-hoge という実行ファイルの形になっているので。
=== ノートのコマンドライン実行 ===
* 実行結果削除\\ jupyter nbconvert --clear-output --inplace MYNOTEBOOK.ipynb
* ノートの実行(ノート自体の書き換え)\\ jupyter nbconvert --execute MYNOTEBOOK.ipynb --inplace --allow-errors
* ノートの実行(実行済みノートの新規作成)\\ jupyter nbconvert --to notebook --execute MYNOTEBOOK.ipynb \
--output OUTPUT.ipynb --ExecutePreprocessor.timeout=2678400 --allow-errors
===== scikit-image =====
scikit-imageには画像変換などに有用な関数などがある.
=== テスト用画像 ===
''skimage.data'' 配下に画像データ自体が入っているので以下のようにして
ndarray形式の画像を得ることができる.
from skimage.data import astronaut
img = astronaut()
''PIL.Image'' を使ってJupyter上で可視化
from PIL import Image
Image.fromarray(img)
===== pandas =====
=== 関数 ===
DataFrame インスタンスを ''df'' と表すことにする.
| ヘッダのキーリスト | ''df.columns.values.tolist()'' |
===== 現在の名前空間/import可能 =====
* ''globals()'' : インスタンス化されているものとimportされたパッケージ.(ビルトインオブジェクトのコンストラクタは含まれない)
* ''locals()'' : インスタンス化されているもの.
* [[https://gist.github.com/yuuho/252034a942e31a16be64b789dbd1d589|調査用コード (gist.github.com) ]]
==== Pythonのビルトインオブジェクト ====
Pythonに最初から組み込まれていて既に使用されている変数名などが
builtinsを見ればわかる. ''list''や''dict'',''map''など最初から使える関数がビルトイン.
names = __builtins__.__dict__.keys()
print(names)
すべての組み込みオブジェクトは''import builtins''して
''builtins.open()''みたいな感じで正式名称で利用できる.
==== Pythonの標準ライブラリ ====
標準ライブラリディレクトリの中から ''%%_%%_init%%_%%_.py'' のあるディレクトリと ''%%_%%_init%%_%%_.py'' 以外の pythonファイルを列挙.
import distutils.sysconfig
from pathlib import Path
stdlibs = [ item.name.replace('.py','') for item in
sorted( Path(distutils.sysconfig.get_python_lib(standard_lib=True)).glob('*') )
if ( item.is_dir() and (item/'__init__.py').exists() ) or
( item.name[-3:]=='.py' and item.name!='__init__.py' ) ]
print(stdlibs)
import distutils.sysconfig
from pathlib import Path
stdlib_path = Path(distutils.sysconfig.get_python_lib(standard_lib=True))
stdlib_dynamic_load_path = stdlib_path / 'lib-dynload'
std_mods = [ item.name.replace('.py','') for item in sorted( stdlib_path.glob('*.py') )
if item.name!='__init__.py' ]
std_pkgs = [ item.name for item in sorted( stdlib_path.glob('*') )
if item.is_dir() and (item/'__init__.py').exists() ]
std_dynl = [ item.name.split('.')[0] for item in sorted( stdlib_dynamic_load_path.glob('*.so') ) ]
std_libs = list(sorted(std_mods + std_pkgs + std_dynl))
print(std_libs)
print('debug console : ', len(std_mods), '(std_mods) +',
len(std_pkgs), '(std_pkgs) +', len(std_dynl), '(std_dynl) =', len(std_libs), '(std_libs)' )
==== Pythonの読み込み可能なパッケージについて(サード/自作) ====
すでに名前空間に存在するパッケージを表示できる.
以下のように確認するとたとえば''test''というパッケージはすでに標準ライブラリとして存在するので,
自分で''test.py''などというファイルを作るのはあまりよろしくないということがわかる.
import pkgutil
arr = sorted([p.name for p in pkgutil.iter_modules() if p.ispkg ])
for p in arr:
print(p)
''pkgutil.iter_modules()'' は ''sys.path''以下と相対パスの\\
pythonファイル / soファイル / ''%%_%%_init%%_%%_.py'' のあるディレクトリ(パッケージ)
を列挙する.
標準ライブラリも含まれる.
===== デバッグ用途 =====
==== 何のメソッド・プロパティを持つか確認 ====
あるオブジェクトが何のメソッド・プロパティを持っているか調べる.
プロパティとメソッド両方なら
[k for k in dir(obj) if not k.startswith('__')]
メソッド単体なら
obj.__dict__.keys()
=== 確認 ===
''obj'' を確認したい場合.
nr_prop_meth = set(k for k in dir(obj) if not k.startswith('__'))
sp_prop_meth = set(dir(obj)) - nr_prop_meth
nr_meth = set(k for k in obj.__dict__.keys() if not k.startswith('__'))
sp_meth = set(obj.__dict__.keys()) - nr_prop
nr_prop = nr_prop_meth - nr_meth
sp_prop = sp_prop_meth - sp_meth
print('=== normal method ===')
print(list(sorted(list(nr_meth))))
print('=== special method ===')
print(list(sorted(list(sp_meth))))
print('=== normal property ===')
print(list(sorted(list(nr_prop))))
print('=== special property ===')
print(list(sorted(list(sp_prop))))
===== 未整理メモ =====
=== 分け方 ===
* python基礎 型変換,基礎文法
* オブジェクト指向,各種プログラミングパラダイム
* パッケージ作成,import
標準ライブラリ(pipも3.4以降は標準)
==== 切り捨て・切り上げ ====
ceil,floor
mathをimportするのは面倒
ceil = lambda x:-int((-x)//1)
floor = lambda x:int(x//1)
==== 三項演算子 ====
python の三項演算子の書き方.\\
and-or スタイルは最後に評価されたものが返ってくる?
''条件式 and 真戻り値 or 偽戻り値'' だが、真戻り値は ''bool()'' で真になるものじゃないといけない
def func1(x):
return 'fuga' if x=='hoge' else 'piyo'
def func2(x):
return x=='hoge' and 'fuga' or 'piyo'
def f1():
print('eval 1')
return 'bar'
def f2():
print('eval 2')
return 'baz'
def func3(x):
return x=='hoge' and f1() or f2()
def main():
print(func1('hoge'))
print(func1('foo'))
print(func2('hoge'))
print(func2('foo'))
x = 'poon'
z = ( x=='hoge' and 'fuga' or 'piyo' )
y = x=='hoge' and 'fuga' or 'piyo'
print(z)
print(y)
print('------')
print(func3('hoge'))
print('------')
print(func3('foo'))
if __name__ == '__main__': main()
結果
fuga
piyo
fuga
piyo
piyo
piyo
-----
eval 1
bar
-----
eval 2
baz
==== 配列色々 ====
=== 内包表記について ===
* 単純に丸括弧で内包表記するとtuple内包表記ではなくGeneratorオブジェクトになる.
* tupleにしたい場合は''tuple(i for i in range(10))''みたいに最初に''tuple''とつける.
* dict についても内包表記で生成できる
=== listの初期化 ===
* MxN二次元配列は [[0]*N for _ in range(M)]のように初期化する.こうせず''%%[%%[0]*N]*M''とするとidが同じになってしまう.
* >>> N,M = 3,4
>>> x = [[0]*N]*M
>>> x[0][1] = 3
>>> x
[[0, 3, 0], [0, 3, 0], [0, 3, 0], [0, 3, 0]]
* range より短い書き方として strを使うものがある\\ [[0]*N for _ in ' '*M]
=== listを固定個数ずつ取り出し ===
同一オブジェクトとなることを利用して以下のように順番に3つずつの組にするなどのテクニックがある.\\
ただし個数が割り切れない場合は最後のほうのは使われなくなる(zipの仕様による挙動).
>>> zip(*[iter(range(15))]*3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
より読みやすい書き方としては (何個ずつ切り分けるかがわかっているときは)
>>> l = [i for i in range(15)]
>>> zip(l[::3],l[1::3],l[2::3])
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
=== 2次元配列の転置 ===
以下はtupleのlistを作成してしまう.それで問題ない場合はこの書き方が一番短い.
LT = list(zip(*L))
listのlistをとして転置したものを作成したい場合は
LT = [[*l] for l in zip(*L)]
=== 配列から同じ個数ずつ取り出し ===
ここまでは、端数が出たとき最後の配列が少なくなる状況だった。
たとえば ''21=[5,5,5,5,1]'' みたいになる。これを ''21=[5,4,4,4,4]'' としたい。
その場合、
# target : 配列
num_split = 3
nums = [ len(target)//num_split+int(i
=== generatorの展開 ===
# * を使うのが良い。
# 複数の generator から展開してまとめるときは
[*hoge, *fuga, *piyo]
# 無数のgeneratorから展開してまとめるときは
sum([[*g] for g in g_list],[])
==== 内包表記の旅 ====
=== while ===
MAX = 5
hoge = 0
while True:
if fuga() and hoge>MAX:
break
else:
continue
みたいにしたいときの内包表記
depth = [i for loop in [[0]] for i in loop if not \
(loop.clear() if len(l)
- 内包表記のケツの filter-if に常にlistのメソッド戻り値を入れてやる.
- listの''clear()''や''append()''は何も返さないので常にFalse
- if not False であるから常に filter されずに残せる.
- 計算したときの i を保存しておいてやる.
- 保存された最後が0なら0で止まった == 一つもないよ
- 保存された最後がNならNで止まった == 0からN-1までは通った == N個あるよ
==== 相互参照 ====
Mutual recursion
定義前の関数を参照しないと定義できない再帰関数の利用.
even = lambda n: True if n==0 else odd( abs(n)-1)
odd = lambda n: False if n==0 else even(abs(n)-1)
==== 対話モードの表示とprint関数の違い ====
オブジェクトに設定されたどの特殊属性(magic variable)が表示されるか
| 対話モード | ''%%_%%_repr%%_%%_'' |
| print関数 | ''%%_%%_str%%_%%_'' |
==== printでの表示に対する色付け ====
普通のシェルと同じ様にエスケープシーケンスで
標準出力に着色することが可能.
モード変更とモード終了のエスケープを利用する.
^ 操作 ^ 文字列 ^
| 元に戻す | ''\033[0m'' |
| 黒色にする | ''\033[30m'' |
| 赤色にする | ''\033[31m'' |
| 緑色にする | ''\033[32m'' |
| 黄色にする | ''\033[33m'' |
| 青色にする | ''\033[34m'' |
| 紫色にする | ''\033[35m'' |
| 水色にする | ''\033[36m'' |
| 白色にする | ''\033[37m'' |
| 太くする | ''\038[1m'' |
| 下線を付ける | ''\033[4m'' |
| 反転? | ''\033[08m'' |
| 逆? | ''\033[07m'' |
==== オブジェクト指向について ====
プライベート変数は擬似的にしか作れない.''self.%%__%%param'' とすると外からは
アクセスできないが,''_classname%%__%%param'' としてアクセスできる.
==== 自作スクリプトをPythonで作成 ====
- [[https://qiita.com/Tadahiro_Yamamura/items/cecbc27182b76257d18f|コマンドラインスクリプト作成参考]]
- [[https://blog.amedama.jp/entry/2015/09/17/224627|参考]]
- [[https://docs.python.org/ja/3/distutils/examples.html|パッケージ構成の例(disutils)]]
pipで自作コマンドをインストールする方法.
pipとかはリポジトリのルートディレクトリに置かれた''setup.py''を見て実行される.
''setup.py''の中では,''setuptools''という非標準パッケージを利用しているが,
pipが入っているとまず入っているので大丈夫.
setuptoolsのsetup関数にわたす値で色々と設定する.
''entry_points''という引数に以下のようにわたしてやれば良い.
entry_points={
"console_scripts": [
"hoge = fuga.piyo:main"
]
}
この例ではfugaパッケージpiyoモジュールのmain関数がhogeというコマンドで呼び出されることになる.
setuptoolsは内部では''distutils''という標準パッケージを利用している.
==== パッケージのimportなどについて ====
* [[https://qiita.com/ysk24ok/items/2711295d83218c699276|importの躓きどころ]]実行するファイルとimportできるものとの関係性について
==== ファイルハッシュの計算 ====
hashlibという標準ライブラリがある.
import hashlib
with open('hoge.txt','rb') as f:
bindata = f.read()
SHA1 = hashlib.sha1(bindata).hexdigest()
print('SHA1 :',SHA1)
MD5 = hashlib.md5(bindata).hexdigest()
print('MD5 :',MD5)
==== 16進数表現への変換 ====
''bytes''は組み込み型.標準ライブラリ''struct''を使って変換する.
import struct
float_value = 1.234
hex_value = bytes.hex(struct.pack("f",float_value))
print(type(hex_value)) #
==== コメントブロック ====
text = r"""
こうやって
文字列を
好き放題書ける
"""
print(text)
==== ファイルの入出力 ====
テキストファイルを開く場合は
with open('filename.txt',MODE) as f:
# 何らかの処理
とする.\\
openしてcloseする方式でも良いが,\\
なるべくファイルの処理がプログラム中の一部に収まるようにすることが大切.\\
closeされている/されていない の状態管理を適切にするのは常人の脳では不可能.
=== mode ===
^ 指定 ^ 存在しないファイル ^ 存在するファイル ^ 操作 ^
| ''r'' | エラー | 変更なし | 読み込み |
| ''w'' | 新規作成 | 消去 | 書き込み |
| ''x'' | 新規作成 | エラー | 書き込み |
| ''a'' | 新規作成 | 追記 | 書き込み |
その他,\\
バイナリファイル用の''b'',\\
読み書き両用(途中の箇所に追加など)の''+''
=== 操作 ===
* read
* write
==== argparse ====
import argparse
def parse_args():
parser = argparse.ArgumentParser(description='ここにプログラムの説明文')
parser.add_argument('-v','--value_name', type=str, default='hogehoge',
dest='value_name', help='変数の説明')
parser.add_argument('-f','--flag_name', action='store_true',
dest='flag_name', help='boolの変数')
args = parser.parse_args()
==== 無理やりインデントによる可読性向上 ====
何もしないと指定のインデントにしなければいけない
a = 0
x = 1
y = 2
''if'' に恒等真なものを与えるとインデントを強制的に下げられる.
これによりブロックを作りコードの行をグループ分けできる.
''if'' の中身を文字列にするのがコメント替わりにもなって良い.
if 'hoge':
a = 0
if 'fuga':
x = 1
y = 2
''if'' のコメント部分を ''print'' したい場合は次のように工夫する.
if [print('hoge')]:
a = 0
if {print('hoge')}:
b = 0
if (print('fuga'),):
x = 1
y = 2
''print()'' の返り値は ''None'' であるので list や set に変換すれば良い.
''bool(None)'' は ''False'' だが ''bool([None])'' は ''True'' である.
list, set は括弧の2文字だけでできるので楽.tupleの場合は括弧の二文字とカンマが必要となるため最適解ではない.
''print()'' の前に ''1 or'' を付けることで簡単に ''print()'' が評価されずに ''True'' となり,
簡単にprintする/しないを切り替えられる.
if 1 or [print('表示されない')]:
a = 0
if 0 or [print('表示される')]:
x = 1
y = 2
変数名として ''ignore_flag'' としておくことで
一括で簡単に表示非表示を切り替えられる.
ignore_flag = True
if ignore_flag or [print('表示されない')]:
a = 0
if ignore_flag or [print('表示されない')]:
x = 1
y = 2
''with'' で利用できるクラスを作成したら良い.
class MSG:
def __init__(self,step): self.step=step
def __enter__(self): print(self.step,'start...')
def __exit__(self,*arg): print(self.step,'done.')
with MSG('last step'):
print('do something')
class MSG:
def __init__(self,step,flag=True): self.step,self.flag=step,flag
def __enter__(self): not self.flag or print(self.step,'start...')
def __exit__(self,*arg): not self.flag or print(self.step,'done.')
==== デコレータ ====
def hoge(func):
return None
@hoge
def fuga():
hoge
def timelimit(msec):
def _deco(func):
def wrapper(*args, **kwargs):
return func(*args,**kwargs)
return wrapper
return _deco
@timilimit(1000)
def some_func():
return 'hoge'
===== デバッグテクニック =====