LWP::UserAgent::WithCache

ごくたまに、思いつきでLWPを使ったコードを書くことがある。そんな時は、wgetとかcurlで、対象のファイルをローカルに落として、ゴソゴソとテストを繰り返し、最後にLWPをくっつけるというちょっと無駄が多いやりかたをしていた。最近さすがに嫌になってきて、なんとなく気になっていたLWP::UserAgent::WithCacheというモジュールを使ってみた。

なんも考えなくてもキャッシュされるので便利!

キャッシュがある限りそれを読めばいいし~~
って、キャッシュの読み込みどうすればいいんじゃろか?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/perl

use strict;
use warnings;
use LWP::UserAgent::WithCache;

my %cache_opt = (
                'namespace' => 'lwp-cache',
                'cache_root' => "/tmp",
                'default_expires_in' => 60 * 60 * 24 * 7 );
my $ua = LWP::UserAgent::WithCache->new(\%cache_opt);
my $response = ua->get('http://www.potschi.de/svmtut/svmtut.html');

if ($response->is_success) {
    print $response->content;  # or whatever
} else {
    print $ua->{cache}->get('http://www.potschi.de/svmtut/svmtut.html')->{content};
}

$uaでできたcache::fileのオブジェクトを引っ張り出してきてgetしたのを出力させてみた。あんまりいい方法とは言えない気がするけどこんな感じでいいのか。

CDK使ったモジュールを書いてみた

Inline::JavaでCDKのニ次元構造立ち上げをperlでやれるようになったんだけど、やっぱuseして使いたいのでモジュール化してみた。

最初、Inlineでモジュールを書く方法の通りに書いてみたらエラーを吐いて動かないので、どうしたもんかと。
で、少し探してみたら、あまり深く考えなくて、普通にコンストラクタだけ用意してやればOKということらしい。

use 5.008008;
use strict;
use warnings;

our $VERSION = '0.01';

use Inline Java => "DATA";

sub new {
    my $class    = shift;
    return CDK::Simple::smi2mol->new();
}

1;

__DATA__
__Java__
import java.io.StringWriter;
import java.io.IOException;
後はjavaコードがジャヴァジャヴァと。

で、使ってみる。

my $parser = CDK::Simple->new;    
my $smiles_string = "C(=O)O";
print $parser->convert($smiles_string);

お~、モジュールだ。実行すると無駄にタメがあるのはjavaだから~。ところで、newでblessする必要はないのかな?とか気になる。

実際に作ってみて、Inline::Java使ったモジュールは意外に簡単だった。

pydocって-pオプションでWebサーバーになるのね

pydoc って

pydoc -p 8020

で、ドキュメントのウェブーサーバーとして動くということを知った。あとは

from pydoc import writedoc
import os, sys
import os.path

sys.path.append("../lib")

writedoc('PyModule')

とかやるとドキュメントがhtmlで書き出されるのね。pythonはここらへんが標準なので使い勝手がよい。perlだと pod2htmlでよいが、サーバーはPod::Webserverをインストールして

podwebserver

で動かせるらしい。

これはperl hacksで知った。

ProductName Perl Hacks: Tips & Tools for Programming, Debugging, And Surviving
Damian Conway
Oreilly & Associates Inc / 2163円 ( 2006-05-30 )


最初、を~便利かもとか思ったけど、ブラウザ使わないでperldoc とかperldoc -m で端末から眺めるほうが一番な気がしてる。

FANNとperlバインディング

ちょっと遊んでみたくなってFast Artificial Neural Network LibraryPerl wrapperを入れてみた。

perlで割と簡単に書けるので、手軽にニューラルネットで何かをしたいときには重宝しそう。

他にもAI::NeuralNet::Simple(POEのヒトが作者っぽい)とかAI::LibNeuralとかAI::NNFlexとか探してみると結構ある。

perl5.8で日本語を扱うこと

昨日の続き

  • フォームが文字化け
  • 正規表現の部分がよくわからなかった。

丸ごとperlで紹介されていたDevel::Peekを使ってみた。MFPMによるとやっぱ、UTF-8フラグ探知モジュール的な使い方が多いのか。こういうのはプリントデバッグ的で好き。#の行が無駄に増えるけど。

ProductName まるごとPerl! Vol.1
小飼 弾
インプレスコミュニケーションズ / ?円 ( 2006-08-24 )


で後者の正規表現のマッチがよくわからんという部分は、mecabのパース$m->parseToNode($word)でutf8フラグがたたないことが原因だった。わかってみればそりゃそうだと思えるが。

my $n = $m->parseToNode($word);

while ($n = $n->{next}) {
    my $devword = decode("utf8",$n->{feature});
    #   if ($devword =~ /^\345\220\215\350\251\236/) { # 名詞
    #    if ($devword =~ /^\x{540d}\x{8a5e}/) { # 名詞
    if ($devword =~ /^名詞/) { # 名詞

        my $w = $n->{surface};
        print $w,"\n";
    }
}

use utf8しとけばx{540d}x{8a5e}でも名詞でもマッチした。なんとなく体で理解したっぽい。以下参考にしたページ。

で、前者のフォームが文字化けの部分はさっぱりわからん。どうも、HTML::Template通るときに文字化けしてるっぽい。うーん。

perlで関数型のプログラミングをするモジュールとか

List::UtilとかList::MoreUtilsというものを教えてもらったので、少し読んでみた(というか自分用のメモ的な意味合いが強いかも)

あと、リスト操作の動作確認するために、対話型のperlshを使ってるが便利だ。

List::Util

リストの最大、最小の要素を返したりとか。reduceで同じことができるのでreduce覚えておけばよい感じ。日本語訳

perlmolのChemistry::InternalCoords ::Builderだとこんな感じで使ってる。

$ref = ${
    reduce { $a->[0] < $b->[0] ? $a : $b }
    map { [$atom->distance($_)] }
    grep { $_ ne $atom } @$atoms;
}[1];

grep,mapでリストを操作した後、reduceを使ってお望みの要素を取り出すと。
というわけで、これといった例が思い浮かばないが、シュワルツ変換っぽく使えばリストでなくて要素が返ってくると。

List::MoreUtils

anyとかallとかのリストに対する真偽判断用の関数はこっち。日本語訳

pairwise、each_array、zipはfor文を入れ子にしなくてよくなるので、コードの見通しがよくなる感じ。

あと、QSAR記述子選択用のコード書くのに便利そうなのが、minmax(min==maxの記述子はこれでさくっと落とせる)。さらに、uniq組み合わせて、さらに数値のバリエーションのない記述子も落としていけるし、any使えばnullデータの入ってる記述子も排除できるので、今度preparation用のコードをList::MoreUtils使って書いてみよう。

fp::functionals

リスト操作用だけでなく、関数操作用のモジュールもあるだろうと探したら、やっぱありました

もうちょいhaskellまともに書けるようになったら使ってみたい(かな?)が、今のところはperlで関数型っぽくかけるのはリスト操作で十分かもという気がしてる。

BiopythonはbioperlよりもPDBファイルの処理が速かった

みんなのpythonも読んだし、フレームワークでも試してみるかと、djangoとかTurbogearsに手をだしたら、火傷した。

djangoは一通りサンプル動作をさせることができたけど、Turbogearsはコントローラのあたりからさっぱりわからん。
いきなりフレームワークは無謀すぎたかなということで、Biopythonでも入れて、もう少しpython慣れすることに。

easy_install numpy

wget http://www.egenix.com/files/python/egenix-mx-base-2.0.6.tar.gz
python setup.py install

svn co http://www.reportlab.co.uk/svn/public/reportlab/trunk
python setup.py install

wget http://biopython.org/DIST/biopython-1.42.tar.gz
python setup.py install

easy_installはperlでいうところのcpanコマンドみたいで楽チンです(ちゃんと動けば)。動かないのは地味にダウンロード、展開、setup.pyを行なった。

さて、インストールも無事に終了したところで、bioperlと比べてみた。比較したのはpdbファイルの処理。というのは、FMO用のインプット作るときに使っているPDBパーザーつまりBio::Structure::IOがやたらと遅く、不満だったからというありがちな理由。

コードはこんな感じで、1fatっていうpdbファイル読み込んでCalphaを出力してみた。

python

from Bio.PDB.PDBParser import PDBParser

parser=PDBParser(PERMISSIVE=1)
structure=parser.get_structure("1fat", "1fat.pdb")
for model in structure.get_list():
    for chain in model.get_list():
        for residue in chain.get_list():
            if residue.has_id("CA"):
                ca_atom=residue["CA"]
                print ca_atom.get_coord()

perl

use strict;
use Bio::Structure::IO;

my $pdb_file = "1fat.pdb";
my $structio =  Bio::Structure::IO->new(-file => "$pdb_file",
                            -format => 'PDB');

my $struc = $structio->next_structure;
for my $chain ($struc->get_chains) {
    for my $res ($struc->get_residues($chain)) {
        for my $atom ($struc->get_atoms($res)) {
            print join " ",$atom->xyz,"\n" if $atom->pdb_atomname eq " CA ";        
        }
    }
}

で、ベンチマーク

$ time python test.py
real    0m1.161s
user    0m0.996s
sys     0m0.116s

$ time perl pdbtest.pl
real    0m3.183s
user    0m3.056s
sys     0m0.044s

平均とってないけど、何回か実行してみてもpythonのほうがbioperlよりも3倍くらい速かった。bioperlのコードってなんだかなと思うことがままある。pdb_atomnameなんかも4文字で前後にスペース入ってるし。というわけで、SBDD周りのプログラミングはbiopythonのほうが扱いやすい感じがしてる。

ProductName みんなのPython
柴田 淳
ソフトバンククリエイティブ / ?円 ( 2006-08-22 )


余談だが、Turbogears普通に触れる程度までpython覚えてやる(意地でも)とか思ったので、Dive Into Pythonも読み中。

eijiro.pl

plaggereijiro.plのソース眺めててFindBinとFile::Specの使い方を学んだ。

use FindBin;
use File::Spec;
use lib File::Spec->catdir($FindBin::Bin, '..', 'lib');

$FindBin::Binで実行されたスクリプトのpathを取得しておいて、File::SpecでOSに依存しないようにパスの組み立てをする。

確かに、use libと組み合わせて使うとスマートだ。

ちなみに、このスペックのマシンで、eijiro.pl用の内部データを作成するのに8時間ほどかかったが、コマンドラインでも辞書引けると何かと便利。

perlでパイプつきopen文

今まであんまパイプ付きopen使わずに、system()とかbackticsばかりだったので、ちゃんと理解しておくことにした。

perlipc - Perl のプロセス間通信

open()関数は "-|" や "|-" といったファイル引数を非常におも しろいことを行うために受け付けます: これはあなたがオープンしたフ ァイルハンドのための子プロセスをfork()するのです。その子プロセス は親プロセスと同じプログラムを実行します。

if ($pid) {  # parent
    print KID_TO_WRITE @some_data;
    close(KID_TO_WRITE) || warn "kid exited $?";
} else {     # child
    ($EUID, $EGID) = ($UID, $GID); # suid プログラムのみ
    open (FILE, "> /safe/file")
        || die "can't open /safe/file: $!";
    while (<STDIN>) {
        print FILE; # 子プロセスの STDIN は親プロセスの KID
    }
    exit;  # これを忘れてはいけません
}

確かに、openした後は親子な処理になってます、waitって勝手にするんだろうか?おそらくするんだろうなと思うが、waitしてるかってどうやって確かめればよいんだろう?

また、ここまで理解すれば、次のサンプルもなかなかすっきりしてると思えるようになる。

日本語 perl texinfo - open

コマンド -' を用いてパイプを open する場合、 すなわち|-' または`-|' の場合、 暗黙の内に fork がなされ、 open の返り値は親プロセスでは子プロセスの pid、 子プロセスでは 0 になる。

||がif ($pid) {} else {}と同じだということはわかる。

open(FOO, "|-") || exec 'tr', '[a-z]', '[A-Z]';

ということはこの式も実はforkしているのか。

open(FOO, "|tr '[a-z]' '[A-Z]'");

あと、Higher-order Perlのp.152の例だとtacの出力を"|-"でつないでるんだよな。おかしいなぁと思ったらやっぱ間違ってた。ちなみにいま6章読んでる。

File::Remoteのファイルハンドルを動的生成したかった

rshが必要な古いマシンで動くプログラムって、引数にファイルをとることが多い。つまり、インプットファイルをリモートに書き込む必要があるわけだ。nfsマウントでもいいかもしれないが、fstabが無駄にごちゃごちゃしてくるので好きではない。潔くNet::FTPでもよかったのだけど、この際File::Remoteを使ってみた。

で、このモジュールはなぜか

use FileHandle ();
my $fh = FileHandle->new();
open($fh, "test.txt");
close($fh);

みたいな書き方ができないし、じゃぁこれでどうだと

        $rh->open(RH, ">remote:/tmp/$rfile") or die $!;

これはuse Strictしてると

Bareword "RH" not allowed

とか怒られる。で結局、下の感じでフニュケたコードになってしまった。

{ # Bareword "RH" "LH" allowed
    no strict 'subs';

    my $lh = File::Remote->new();
    $lh->open(LH, "$file") or die $!;

    my $rh = File::Remote->new();
    $rh->open(RH, ">remote:/tmp/$rfile") or die $!;
    local $/;
    my $f = <LH>;
    print RH $f;
    $rh->close(RH);

    $lh->close(LH);

}

どう使うのが賢いやり方なんだろう。

$rh->open(*RH, ">remote:/tmp/$rfile") or die $!;

とでもするのがいいのか?