[an error occurred while processing this directive]
[an error occurred while processing this directive]
応用編
.py って拡張子がついてないファイルを import する
Python の import では ".py" って拡張子が付いたファイルしか読み込めませんが、
imp.load_source() を使うと、どんなファイル名でも python として読み込めます。
import os
import imp
base = os.path.dirname(os.path.abspath( __file__ ))
my_path = os.path.join(base, "my_python_filename");
my_module = imp.load_source("my_name", my_path);
my_module.hoge()
普通は相対パスで読み込むと思うけど、単に load_source() するだけだと、
ユーザが実行する際のカレントディレクトリからのパスになってしまい、意味がない。
そこで、ファイルが置かれている場所のパス名を取得して、つなげている。
ディレクトリ内のファイルをまとめて、文字コード変換する
はじめ手作業でやってたら、サブディレクトリが大量にあることがわかったため、
python の os.walk を使うことに。
import os
for base,dirs,files in os.walk("."):
for f in files:
target = os.path.join(base, f);
if target.endswith(".pm") or target.endswith(".cgi"):
print 'mv %(x)s %(x)s.temp; nkf -e %(x)s.temp > %(x)s'%{"x":target}
os.system('mv %(x)s %(x)s.temp; nkf -e %(x)s.temp > %(x)s'%{"x":target})
1024 みたいに、2 の n 乗が 10 の m 乗に近いことってあるのか?
調べてみるために、ざっと書いてみた。
t = 1
for i in range(1000):
t *= 2
d = t * 1.0
while d > 1:
d *= 0.1
if d < 0.1025: print t
結果、始めに 10 と続く数でさえ、10141204801825835211973625643008 まで待たないといけない。
1024 が 1000 にすごく近いのは偶然なんだなー。
INT_MAXとかFLOAT_MAXとか、整数の最大値や浮動小数点数の最大値を取得
numpyという数値処理モジュールの中だけど、多分普通の型でも同じ。
from numpy import finfo, float_
finfo(float_).max
サイズを指定してリストを作る
大きさを明示的に指定して配列を作る方法はいくつか考えられるが、
[0] * 100000みたいなのが一番速いと思う。
(mmapオブジェクトを使う方法も考えられるけど)
試しにrange()を使う方法、ひとつずつappendする方法と時間をtimeコマンドで比較してみた。
# A = [0] * 1000000
0.028us (マイクロ秒)
# A = range(1000000)
0.068us (マイクロ秒)
# A=[]; for i in range(1000000): A.append(0)
0.248us (マイクロ秒)
ひとつずつappendに比べて、このサイズだと10倍速いですね。
ついでにCとも比べてみた。
# (Cで)
A = (int *)malloc(sizeof(int) * 1000000);
for(i = 0; i < SIZE; i++) A[i] = 0;
0.008us (マイクロ秒)
さすがにCには余裕で負ける...
日時フォーマットを指定
t = time.time()
t_str = time.strftime("%Y-%m-%d_%H-%M-%S", t)
新しいファイルをサイズを指定して作る
mmapしてランダムにファイルに書き込むのに、まっさらなファイルをopenして適当なサイズを指定してmmap()したらおこられてしまった。
あらかじめ領域を確保したいだけだから、例えば0をサイズ分だけ書き込むのはためらわれる。
(ディスクアクセスが発生していまうから。ほんとはinodeだけ書き換えればいいはず)
ちょっと考えたら、open()したあとseek()すればいいみたい。
fp = open(filename, "w")
fp.seek(size)
でもこれだけだとサイズは変わらないみたい。そこで、seek()した先に1バイトだけ書き込んでみる。
def create_empty_file(filename, size):
fp = open(filename, "w")
fp.seek(size-1)
fp.write('\0')
fp.close()
これで、任意のサイズのファイルを簡単に作る関数ができた。
Pythonでmmap()
あらかじめ/tmp/hogehogeに20バイト以上なんか書いておきましょう。
import mmap, os
def mmap_file(fn):
fd = open(fn, "r")
size = os.path.getsize(fn)
data = mmap.mmap(fd.fileno(), size, access=mmap.ACCESS_READ)
print data[10:20] # ファイルの10-19バイト目を表示する
mmap_file("/tmp/hogehoge")
変数が定義されているか調べる
vars()は今使える変数のリストを返してくれる。
(dir()でもほぼ同じ結果が返る)
だから、ある変数aが定義されているかどうか知りたかったら、
a in vars()
とすればよい。
また、
del a
とすると、aという変数を消すことが出来る。
エラーをtry...excepでキャッチした後で表示
Thanks to kennyくん
def getStackTrace(e):
'''
get the stacktrace of an immediately
previous exception as a string
'''
err_str = cStringIO.StringIO()
traceback.print_exception(e.__class__, e, sys.exc_info()[2], None, err_str)
return err_str.getvalue()
Pylint
import pylint
で、
Pythonでoption explicitみたく文法チェックしてくれる。
文字列をリストに変換
文字列を一文字ごとのリストに変換するには、list()で囲むだけ。
s = "abcdef"
print list(s)
結果
['a', 'b', 'c', 'd', 'e', 'f']
16進数と10進数
16進数(の文字列)から10進数への変換。
例えば"1a"→26みたいな。
int()とかを調べたけどかっこいい方法が見つからなかったので、遅そうだけどevalを使いました。
str = "1a"
i = eval("0X" + str)
print i
enumerateを使おう!
Pythonのfor文を使うと、リストに関する処理がとてもしやすいが、ループ変数(iみたいなの)に相当するものが無いので
ちょっと不便な場合もある。例えば、
A = ["apple", "banana", "carrot"]
for a in A:
print a
とすると順番にapple, banana, carrotが表示されるが、その前に1, 2, 3と番号が振りたい(1 apple, 2 banana, 3 carrotみたいに)とき、普通に考えると順番に増える変数を作る
A = ["apple", "banana", "carrot"]
i = 0
for a in A:
print i, a
i += 1
か、ループ変数自体を変える
A = ["apple", "banana", "carrot"]
for i in range(len(A)):
print i, A[i]
だけど、どちらもいまいちすっきりしない。
そこでenumerateという関数を使うと、すっきり片付く。
A = ["apple", "banana", "carrot"]
for i,a in enumerate(A):
print i, a
元々ループ変数が複数あるときは、パターンマッチ的な記述をするとうまくいく。
A = [(1,2), (3,4)]
for i,(x,y) in enumerate(A):
print i, x, y
浅いコピーと深いコピー。
copy.copyでjavaのcloneみたいにオブジェクトのコピーが出来るけど、
普通にオブジェクトをコピーしても、メンバ変数に入っているオブジェクトや配列(これもオブジェクト)はコピーされない。
copy.deepcopyを使うと、変数に入っているオブジェクトも「可能な限り」コピーしてくれる。
import copy
class A:
def __init__(self):
self.array = [1,2,3]
self.string = "abc"
def __str__(self):
ret ="{array : ["
for a in self.array:
ret += "%d "%(a)
ret += "], string:%s}"%self.string
return ret
a = A()
copied_a = copy.copy(a)
deepcopied_a = copy.deepcopy(a)
a.array[2] = 5
a.string = "hello"
print "a = ", a
print "copied_a = ", copied_a
print "deepcopied_a = ", deepcopied_a
実行結果。
a = {array : [1 2 5 ], string:hello}
copied_a = {array : [1 2 5 ], string:abc}
deepcopied_a = {array : [1 2 3 ], string:abc}
a.arrayやa.stringを書き換えるとcopied_a.arrayやcopied_a.stringも書き換わってしまいますが、deepcopied_a.arrayや
deepcopied_a.stringは別なものになっているので書き換わりません。
文字と文字コードの変換
バイトからasciiコード(int)を返す ... ord()
asciiコード(int)から文字を返す ... chr()
glob (ファイルの列挙)
ある条件にあうファイルを全て列挙する。
ディレクトリを開く(opendir)代わりにも使える。
import glob
for f in glob.glob('/etc/*.conf'):
print f
こうすると、条件にマッチするファイルへのフルパスがfに順次入ります。
/etc/pam.conf
/etc/ypserv.conf
/etc/host.conf
/etc/cvs-cron.conf
...
popenを使って、子プロセスのpidを取得
import popen2
import os
p = popen2.Popen3("command_hoge", True)
# Trueを付けると、エラー出力と標準出力を分けて使える
print p.pid
# p.pidに"command_hoge"を実行しているプロセスIDが入っている
p.tochild.write("moi")
# command_hogeの標準入力にmoiと書く
p.fromchild.read(100)
# command_hogeの標準出力を100バイト読む
p.childerr.read(100)
# command_hogeのエラー出力を100バイト読む
os.kill(p.pid, 9)
# popenしているプロセスをkillする
popenしたプロセスは、正しくpcloseしなければいけません。
…といっても、Pythonにpcloseはありません。かわりに全てのファイルディスクリプタを閉じて、wait()を呼びます。
import popen2
p = popen2.Popen3("bash", True)
# 相手(popenされたプログラム)にとってのstdinを閉じる (EOFを送る)
p.tochild.close()
# 相手(popenされたプログラム)が何も出力していなければ、
# 閉じなくてもブロックしないかもしれないけど、
# 一応礼儀として閉じましょう。
p.fromchild.close()
# こっちも。
p.childerr.close()
# これでdefunctになった子プロセスを回収する
p.wait()
リストのランダムな置換(0,1,2,3)から(2,0,3,1)など)を作る。
import random
def getOrdering(n):
A = []
B = range(n)
for i in range(n):
index = int(random.random() * (n-i))
A.append(B.pop(index))
return A
getOrdering(10)
リストからランダムに重なり無くn個取り出す。
(リストの方が短いときにはリストをランダムに置換したのを返す)
import random
def pickSome(list, n):
retlist = []
picklist = list[:]
imax = min(n,len(picklist))
for i in range(imax):
index = int(random.random() * len(picklist))
retlist.append(picklist.pop(index))
return retlist
使い方。
A = range(7)
print pickSome(A, 10)
ソート
リスト(配列)のソート。昇順(小さい順)になります。
>>> A=[3, 4, 2, 0, 5]
>>> A.sort(lambda x,y: cmp(x, y))
>>> A
[0, 2, 3, 4, 5]
mapを使う。
A= ["1", "2", "-1"]というリストを、全て数値に変換する
A= ["1", "2", "-1"]
B = map(string.atoi, A)
これでB = [1, 2, -1]になります。
lambdaだってこわくない。Bの各要素を2乗してみます。
C = map(lambda(x): x*x, B)
C=[1,4,1]となります。
文字列を分割したり、リストを連結して文字列にしたり。
>>> s1 = "1;2;345;"
>>> A=s1.split(";")
['1', '2', '345', '']
>>> "#".join(A)
'1#2#345#'
連結する方ですが、セパレータの文字列のメソッドの引数に配列を入れます。
ちょっと独特。
fork()
Pythonでもfork()。osモジュールの中にあります。
import os,time
child = os.fork()
if child == 0:
print "I'm a child"
time.sleep(3)
else:
print "I'm a parent"
os.wait()
print "Joined"
対話式のシェルで迂闊に
>> os.fork()
って打つと、確率1/2でどちらかのプロセスが反応して意味不明に…
ファイルが存在するかどうか
ファイルが存在するかどうかの判定は、Perlならファイル存在演算子-eが使えるけど、Pythonでは
import os
ret = os.path.exists("/tmp/hoge")
print ret
ファイルが存在すると、retがTrueになる。
exceptionの受け方。
下の例で、check()は2,4,6の場合のみ成功し、それ以外の場合は例外を投げます。
例外が出たらちゃんと受けて(Java的にはcatchして)、次の値を試します。
def check(candidate):
if not candidate in [2,4,6]: raise "Exception"
return "OK"
for i in range(0,8)
ret = ""
try :
ret = check(i)
break
except :
continue
print i, ret
あと、知らなかったんだけど、sys.exit()で返り値を付けると、これがexceptionのようにraiseされてくる。
try:
sys.exit(1)
except Exception,e:
print "Caught %s"%(e)
とすると、'1'を受け取れる。
リスト内包表現
for文を[]の中に書く書き方。例えば、
sum([i**2 for i in A]) ** 0.5
で、ベクトルのノルム(長さ・二乗和のルート)が取れる。
emacs
Emacsのpythonモードで複数行をまとるてインデントするには、C-c >とタイプ
for文中で、対象リストをいじる
for文で回しているリストの中身を、ループの中でいじると変なことが起こる。
A = [1,2,3,4,5]
for a in A:
print a
if a == 2:
A.remove(a)
リストに2が現れたら削除したので、この結果は1,2,3,4,5と期待されるが、
実際には1,2,4,5,になる。(リストがずれたから)
そこで、元のリストをいじらずに、skipリストを作ってみる。素数を求めるプログラムの例。
A = range(2,100)
skips = []
for i, a in enumerate(A):
if i in skips: continue
print a
for j, b in enumerate(A[i:]):
if b % a == 0:
skips.append(j)
リスト内包表現: 例えばリストの足し算。(python2以降限定?)
A = [1,2,3]
B = [4,5,6]
C = [A[i]+B[i] for i in range(3)]
C=[5,7,9]になります。
かなり強力です。
A = ["Hello", "Goodbye"]
B = ["kei", "rei"]
C = [x + ' ' + y for x in A for y in B]
C=["Hello kei", "Hello rei", "Goodbye kei", "Goodbye rei"]ってなります。
in
in ってすごく便利。
s = "hello, world!"
p = "o, w"
if p in s
print "Matched"
てすると、MAtchedが表示されます。
ファイルのパーミッションを調べる
import os
os.access("/tmp", os.W_OK)
これで、/tmpに書けるかどうか調べられる。
ランダムな文字列を生成
import random
def random_str(self, length = 20):
ret = ""
for i in range(length):
ret += random.choice(string.ascii_letters)
return ret
コマンドライン引数を一覧表示。
import sys, os
def E(m):
os.write(2, m)
for i,arg in enumerate(sys.argv):
E("%d : %s \n", i, arg)
fdopen
fdopenで、ファイルディスクリプタ番号を決め打ちして開く。
決まっているファイルディスクリプタは、0:stdin, 1:stdout, 2:stderr。
fd_in = os.fdopen(0, "r")
fd_out = os.fdopen(1, "w")
こうすると、fd_inはsys.stdinと、fd_outはsys.stdoutと等価に使える。
fd_in.readline()
fd_out.write("hello")
長い文字列連結
文字列を改行で区切って書くと連結される。
s = "abc"\
"def"\
"ghi"
は、
s = "abc" +
"def" +
"ghi"
と同じ。
N以下の素数を全て出力。
Bloom filterの勉強をしてたら、素数が欲しくなりました。
N = 10000
A = [True] * N
for i in range(2,N):
if not A[i] : continue
print i
for j in range(i*2,N,i):
A[j] = False
指定したディレクトリ以下の csv を全てグラフ化
import os
def print_plot(typ, f):
csv = os.path.join(typ, f)
png = os.path.join(typ, f[:-3] + "png")
print """set terminal png;
set out "%(png)s";
set datafile separator ",";
plot "%(csv)s" index 0 using 0:1 with lines title "X", "%(csv)s" using 0:2 with lines title "Y", "%(csv)s" using 0:3 with lines title "Z";
#plot "%(csv)s" using 0:1,
"""%locals()
for typ in ["armup", "armdown", "normal"]:
for f in os.listdir(typ):
if f.endswith(".csv"):
print_plot(typ, f)
[an error occurred while processing this directive]