threading.Threadの使い方

よく忘れるので.
docoptは入れて使ってくらはい.他のはanaconda3-4.4.0で入ったと思う.

この記事は次の記事を参考にしている.
実行中のスレッドに対し外から操作をする - Qiita
ただし,私はスクリプトの外から操作をしたかったので,イベントハンドラから呼んでみた.
あと終了処理を入れたかったので無駄に関数を作って呼び出し順などを確認できるようにしてみた.
withは使ってないからenterとexitはいらんかった.

__file__ を test.pid で一括置換した名残が何か残ってるけど気にせんとってください.(abspathとかdirnameとかbasenameとかんとこ)

# スレッドを3つ開始
# 1つはインスタンスで生成
# 2つはサブクラスで生成
# サブクラスの1つは自動的に3秒後に停止
$ python start.py
# SIGUSR1を送信してサブクラスのもう一つを停止
$ kill -USR1 $(cat test.pid)
# 停止スクリプトから停止
$ python stop.py

cygwin に jupyter を入れる

経緯

Ctrl+d で落ちない python コンソールなんてありえない!

方法

python3-pip と python3-zmq を cygwin のインストーラで入れる.
(英語サイトでは bundled zmq とか書かれてるやつ)

pip3 install jupyter

他にも何か pip で入らなさそうなモジュールとかあったら,bundled を探してみるとあるかも.

jupyter notebook tips

色々とtipsを書くエントリ.

ブラウザを起動しない
jupyter notebook --no-browser
他のホストからアクセスさせる
デフォルト設定をファイル出力させる.

jupyter notebook --generate-config

設定ファイルを編集する.

c.NotebookApp.ip = '*'
c.NotebookApp.port = 8888
c.NotebookApp.password = 'sha1:********'

パスワードの生成は

from notebook.auth import passwd; passwd()

2回パスワードを入力すると,ハッシュが返ってくるので,上のpasswordの値として代入する.

python3 で seaborn を使うまで

python3系でvenvを使う想定.

ubuntuとかだとpython3は入っているので,他にいりそうなものを入れる.

$ sudo apt-get install python3-dev python3-venv python3-tk tk-dev

python3-devはnumpyとかのコンパイルに,venvはpipとかをローカルで使うために,tk系はmatplotlibでプロットするウィンドウをコンソールから起こすために使う.

venvで環境を整える.
どこでもいいけど,私は ~/.py3 に環境を作っている.

$ cd
$ pyvenv-3.4 .py3
$ source ~/.py3/bin/activate

source ~/.py3/bin/activateはaliasにしといた方が良いと思う.
以降,source ~/.py3/bin/activateした状態を,(.py3) $と表記する.

必要なパッケージをインストールする
pipでパッケージを入れるが,もしかしたらディストリのパッケージのうち,必要なものが抜けているかも知れない.
build-essentialとかgfortranとか…エラーが出るはずなので,その時に検索すること.
ともかく,以下でpython上の依存関係は入る.

$ pip install seaborn
matplotlibの設定ファイルを変更
(.py3) $ python -c 'import matplotlib;print(matplotlib.matplotlib_fname())'
/home/USERNAME/.py3/lib/python3.4/site-packages/matplotlib/mpl-data/matplotlibrc

で場所を見付けて,backend と書かれた行が agg だったら,tkaggに変更する.

chainer, cuDNN on ubuntu 14.04

cudaは,CUDA 7.5 Downloads | NVIDIA Developerあたりから落として入れる.
私はネットワークインストーラを選択して入れた.入れ方はダウンロードリンクのすぐ下に書かれた通りにやればOK.
なんか,nvidiaドライバもこれで入る.入ったかどうかは

$ lsmod | grep nv
nvidia_uvm             77824  0 
nvidia               8544256  1 nvidia_uvm
drm                   344064  5 i915,drm_kms_helper,nvidia

みたいな感じで入ってればいいんじゃないかしら.
記憶にないけど,なんかnouveauは入ってなかった.
私のマシンはオンボードのIntelグラフィックコントローラとGeForceの両方を搭載しているので,多分最初にubuntu入れる時,グラボを使わなかったんじゃなかろーかと.よく知らんけど.

cuDNNをNVIDIA cuDNN | NVIDIA Developerから落としてきて入れる.
登録は必須っぽいから,仕方なくやる.

cudnnのtar ballを解凍したら,cudaというディレクトリができるので,cudaのインストールパスにコピる.
多分,デフォなら /usr/local/cuda あたりにあるはず.

chainerを入れ直す.
chainerはキャッシュを使うとコンパイルし直してくれないっぽいので,キャッシュを無効化して入れる.

$ pip install chainer --user --no-cache-dir

ローカルに入れない場合は,userオプションを抜いてsu権限でやる.

うまくいけば,pythonから呼び出した時にエラーが出なくなる.

>>> from chainer import cuda
>>> cuda.zeros(1)
array([ 0.], dtype=float32)

python types.MethodType

自作モジュールに問題にチューンした処理を追加しないといけないことがあって,types.MethodTypeでメソッドを追加しようとした話.
自作モジュール内でimportされたモジュールを使う時,どうすればいいのかなー,とか,自作モジュール内のimport時につけた別名と被ったらどうなるのかなー,とか調べてみた.

おおむね予想通り.
自作モジュールを丸ごとimportしてたら参照できるけど,from/importでクラスしか取り込んでなかったら,別途,importしないといけない.
別名が被ったところで,スコープが被るわけじゃないから,人が見て分かりにくいことを除けば問題なくスコープ内のモジュールが呼び出される.

ということを全部は反映してないけど,簡単な使い方メモ.
これは,unbundle版.

import numpy as np
class MyModule:
    def test(self):
        return np.array([1,2,3])
import types
import mymodule

def new_test(self):
    return mymodule.np.array([4])

mymodule.MyModule.additionalMethod = \
    types.MethodType(new_test, None, mymodule.MyModule)
mymod = mymodule.MyModule()
print mymod.test()
print mymod.additionalMethod()

実行結果

$ python mydriver.py
[1 2 3]
[4]

mapと内包表記

リストの全要素へ同じ処理を適用する時に,lambda関数化してmapで適用するのと,内包表記で適用後の値を要素とするリストを生成するのはどっちが早いんだろう?

こんなタイマーを作って,試してみた.

# -*- coding: utf-8 -*-

import timeit
import sys 

'''実行速度を計測する'''

def time_measurement(script, preprocessing, number, recursion):
    '''script is main process, preprocessing includes import statements,
    number means the number of a single trial,
    recursion means the number of trials'''

    timer  = timeit.Timer(script, preprocessing) 
    result = timer.repeat(recursion, number)
    return result

試してみる.

# -*- coding: utf-8 -*-
import tm

# 内包表記
script = '''
o=[' '.join(d) for d in data]
'''
preproc = '''
import numpy;data = [('%d'%(100*numpy.random.uniform()),'%d'%(100*numpy.random.uniform())) for i in range(1000000)]
'''
result=tm.time_measurement(script,preproc,10,2)
print 'make list:',min(result)

# for文
script = '''
o=[]
for d in data:
    o.append(' '.join(d))
'''
result=tm.time_measurement(script,preproc,10,2)
print 'for:',min(result)

# map関数
script = '''
o=map(joint,data)
'''
preproc = '''
import numpy;data = [('%d'%(100*numpy.random.uniform()),'%d'%(100*numpy.random.uniform())) for i in range(1000000)];joint=lambda x:' '.join(x)
'''
result=tm.time_measurement(script,preproc,10,2)
print 'use map:',min(result)

結果

$ python test.py
make list: 1.00997805595
for: 1.52903008461
use map: 1.53125476837

内包表記の勝ち

for文とmap関数は,ほぼ同じ時間だった.同じように実装されているのかなぁ.

numpyを使った複数要素の一括比較演算

まとめて複数要素の比較をし,andを取る

import numpy as np
a=np.array([1,2,3])
b=np.array([1,2,3])
c=np.array([1,2,4])
print a==b,' is ',(a==b).all()
print b==c,' is ',(b==c).all()

出力

[ True  True  True]  is  True
[ True  True False]  is  False

まとめて複数要素の比較をし,その配列でDataFrameをフィルタ

import numpy as np
import pandas
df = pandas.read_csv(open(...))
under50 = df[df['axis1']<50]
between50_100 = df[np.logical_and(df['axis1']>=50,df['axis1']<100)]

httpとhttpsで動作を分ける場合は両方に記述を追加すること(SPDYも注意)

nginx+uwsgiで80番ポートのあるアクセスにpythonスクリプトの出力を流すようにしていたのだが,443ポートでのアクセスは想定していなかったので,特に何も設定していなかった.
そうしたら,httpsでアクセスすると表示されないはずのindex.htmが表示されることに気付いた.
さらに,pythonスクリプトファイル名をダイレクトに指定すると,pythonスクリプトがダウンロードできることも判明した.
そのファイルにこそ,パスワードの類は入れていないものの,インポートしているファイルの一覧が見えてしまうし,これはかなり危険だ.

で,443ポートのserverディレクティブに80番と同じ設定をコピペしたが,動かない…
firefoxやchromeでアクセスしていたため,443ポートとは別に443 spdyが有効になっていたのだ!
二段の罠だった.

ドライブ間/ディレクトリ間のdiff

なんかwebに転がっていそうだけど,ちゃんと探さず実装.
python on cygwinで動作確認.
os.statを使っているので,多分シンボリックリンク辿ってしまう.

なんでこんなもんがいるのかっつーと,truecryptのストレージファイルをdropboxで共有していて,うっかりあるPCでマウントしたまま別のPCでもマウントしてしまうと,ストレージファイルのタイムスタンプが両方とも新しくなって競合が起こって,それぞれのPCでマウントしていたストレージファイルが両方残ってしまうから.
すぐその場で気付けばいいんだが,後で増殖しているのに気付いた場合,差分がどこにあるか把握するのが困難なので,全ファイル,全dirを比較して,どのファイル/dirがどう差分あるのか出力する.
linuxは忘れたけど,windowsでフォルダ配下に新規ファイルを作ったりファイルを消したりすると,ディレクトリのタイムスタンプが更新されてしまうので,無駄に差分が出力されるのを防ぐため,ディレクトリの時刻は比較しないことにした.
どうせ,そのディレクトリ配下で何かいじってたら,ファイルの差分として検出できるし.

import os,sys,stat

if len(sys.argv)<3:
    sys.stderr.write("""Too few arguments!
Usage:
    python diffdrive.py drivepath1 drivepath2
""")
    sys.exit()

if not os.path.isdir(sys.argv[1]) or not os.path.isdir(sys.argv[2]):
    sys.stderr.write("""input path is not found!
""")
    sys.exit()

apath=sys.argv[1]
bpath=sys.argv[2]

def diffdir(apath,bpath,counter):
    if counter>10000: return True
    try:
        alist=os.listdir(apath)
        blist=os.listdir(bpath)
    except OSError,ex:
        if ex.errno == 13:
            alist=[]
            blist=[]
            # permission error
        else:
            raise ex

    tmplist=[]
    nextlist=[]
    for afile in alist:
        # ignore fucking wasted file started by '._' which is created by Mac OS X
        if afile[:2] == '._':
            continue
        if afile not in blist:
            sys.stdout.write("< %s/%s\n"%(apath,afile))
            counter+=1
        else:
            tmplist.append(afile)
    for bfile in blist:
        # ignore fucking wasted file started by '._' which is created by Mac OS X
        if bfile[:2] == '._':
            continue
        if bfile not in alist:
            sys.stdout.write("> %s/%s\n"%(bpath,bfile))
            counter+=1
    for abfile in tmplist:
        astat=os.stat(apath+'/'+abfile)
        bstat=os.stat(bpath+'/'+abfile)
        amode=astat[stat.ST_MODE]
        bmode=bstat[stat.ST_MODE]
        asize=astat[stat.ST_SIZE]
        bsize=bstat[stat.ST_SIZE]
        atime=astat[stat.ST_MTIME]
        btime=bstat[stat.ST_MTIME]
        if stat.S_ISDIR(amode) and stat.S_ISDIR(bmode):
            nextlist.append((apath+'/'+abfile,bpath+'/'+abfile))
        elif stat.S_ISDIR(amode)==stat.S_ISDIR(bmode):
            if asize==bsize and atime==btime: next
            elif atime>btime:
                sys.stdout.write("< %s/%s is newer\n"%(apath,abfile))
                counter+=1
            elif atime %s/%s is newer\n"%(bpath,abfile))
                counter+=1
            elif asize>bsize:
                sys.stdout.write("< %s/%s is larger\n"%(apath,abfile))
                counter+=1
            elif asize %s/%s is larger\n"%(bpath,abfile))
                counter+=1
        else:
            if stat.S_ISDIR(amode):
                afiletype='DIR'
                bfiletype='FILE'
            else:
                afiletype='FILE'
                bfiletype='DIR'
            sys.stdout.write("< %s/%s is %s\n> %s/%s is %s\n"\
                    %(apath,abfile,afiletype,bpath,abfile,bfiletype))
            counter+=1
    for nextpair in nextlist:
        if diffdir(nextpair[0],nextpair[1],counter): return
    return False

diffdir(apath,bpath,0)