yuuho.wiki

カオスの欠片を集めて知恵の泉を作る

ユーザ用ツール

サイト用ツール


tips:python:start

Python

Pythonは numpyやPyTorchなどC++やCUDAで実装されたライブラリに 素早くアクセスできる優れたスクリプト言語.

配下ページ

保存関係

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() : インスタンス化されているもの.

Pythonのビルトインオブジェクト

Pythonに最初から組み込まれていて既に使用されている変数名などが builtinsを見ればわかる. listdictmapなど最初から使える関数がビルトイン.

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<len(target)%num_split) for i in range(num_split)]
splits = [ (slice(l[0],l[0]+n),l.append(l.pop()+n))[0] for l in [[0]] for n in nums ]
splitted = [target[sl] for sl in splits]
 
num_split = 3
nums = [ len(target)//num_split+int(i<len(target)%num_split) for i in range(num_split)]
splitted = [ (target[l[0]:l[0]+n], l.append(l.pop()+n))[0] for l in [[0]] for n in nums ]

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)<size*-~i or l[size*i:size*-~i]!=indent else loop.append(i+1) )][-1]
  1. 内包表記のケツの filter-if に常にlistのメソッド戻り値を入れてやる.
  2. listのclear()append()は何も返さないので常にFalse
  3. if not False であるから常に filter されずに残せる.
  4. 計算したときの i を保存しておいてやる.
    1. 保存された最後が0なら0で止まった == 一つもないよ
    2. 保存された最後が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で作成

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などについて

ファイルハッシュの計算

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)) # <class 'str'>

コメントブロック

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'

デバッグテクニック

tips/python/start.txt · 最終更新: 2025/03/19 21:56 by yuuho