tuneoの日記: Pythonのcontextlibでハマる 5
ロックファイルを使ったスクリプトの排他制御をやろうと思ってcontextlibに手を出してみた。
つまり
with lockfile("/var/lock/test.lock"):
排他的な何か
排他的じゃない何か
みたいな感じで書けると便利だな、と思ったわけである。
お気楽にこの手の処理を実現するためにcontextlibモジュールというモノがあり、そしてそこにはジェネレータでコンテキストマネージャをお気楽に実装するためのデコレータがcontextlib.contextmanagerがある、というところまでは理解した。
import contextmanager from contextlib as cm
import os
import errno
class Locked(Exception):
pass
@cm
def lockfile(filename):
try:
fd = os.open(filename, os.O_CREAT | os.O_EXCL)
yield fd
except OSError as e:
if e.errno == errno.EEXIST:
raise Locked
else:
raise
else:
os.close(fd)
os.remove(filename)
これでイケると思ったんだがいまいち芳しくない。
withブロックの中でsys.exit()とかraise SystemExitしたりKeyboardInterrupt例外が発生すると、コンテキストマネージャお構いなしでプロセスが終了するのか?だとするとあんまりご利益無いなー。
やっぱりatexit? (スコア:1)
異常終了時にも後始末をするためには
とか書かないとダメ?
Re:やっぱりatexit? (スコア:2)
try ... finally を使えばいいのでは?
http://blog.amedama.jp/entry/2015/10/02/234946 [amedama.jp] とか https://qiita.com/QUANON/items/c5868b6c65f8062f5876 [qiita.com] とか見ると、そうしています。
svn-init() {
svnadmin create .svnrepo
svn checkout file://$PWD/.svnrepo .
}
Re:やっぱりatexit? (スコア:1)
ここがちょいと面倒なところなのですが、当然のことながら「別プロセスが作成したロックファイルは触らずにLocked例外をraiseしたい」わけですよ。
だもんでfinallyにos.removeを書くとあまり都合がよくないのです。
逃げる手は思い付かないではないですが、is not NoneとかPythonicじゃないのが好かないんですよね。
Re:やっぱりatexit? (スコア:2)
別途 try するのは?
svn-init() {
svnadmin create .svnrepo
svn checkout file://$PWD/.svnrepo .
}
Re:やっぱりatexit? (スコア:1)
yield Noneが何の例外をraiseするんだ?とか半年後のボクが頭を抱えそうなのでちょっと。
Pythonicなコードにバグを仕込むよりは。Pythonicでなくてもわかりやすいコードを書いた方がいいだろう、と割り切ることにします。