Hatena::ブログ(Diary)

yanolabの日記

2012-01-09

map_between をやってみる -slice使ったっていいじゃない編-

| 10:46 | map_between をやってみる -slice使ったっていいじゃない編-を含むブックマーク

[1,2,3,4,5]を与えられたら[3,5,7,9]を返すようなプログラムを書く。

元の記事は以下。

map_between をやってみる - Study08.net 対シンバシ殲滅用人型機動兵器

リストの隣接要素を次々に処理する - 今川館

#! /usr/bin/env python
# -*- coding: utf-8 -*-     

from itertools import islice, imap

def mapbtw(func, it):
    return imap(func, it, islice(it, 1, None))

if __name__ == '__main__':
    import operator

    print list(mapbtw(operator.add, range(1,6)))
    print list(mapbtw(operator.add, xrange(1,6)))

意外と知られていないitertoolsの関数群。

追記

イテレータは前に突き進むよりトラックバックいただきました。

id:imagawa_yakataさんどうもです。

で、本題ですが、上記のmapbtwだとイテレータに対応していないとのこと。

確かにおっしゃる通りです。手抜きですw

一応改良版書いときます。完全にitertoolsの紹介になってますが。。。

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from itertools import islice, imap, tee

def mapbtw(func, it):
    iter1, iter2 = tee(it)
    return imap(func, iter1, islice(iter2, 1, None))

if __name__ == '__main__':
    import operator

    def listlike():
        yield 1
        yield 2
        yield 3
        yield 4
        yield 5

    print list(mapbtw(operator.add, range(1,6)))
    print list(mapbtw(operator.add, xrange(1,6)))
    print list(mapbtw(operator.add, listlike()))

本来はitの型見て動作変えるのがいいのかしらね。ま、気にしない。

teeイテレータをコピーしちゃう関数tee(it,n)で好きなだけコピーできる。

ただし、注意点は、ittee戻り値の1個目は同じイテレータを指していること。(意外とハマる)

まぁ〜、あくまでも別解ってことで。

2011-12-19

RPythonで正規表現を使えるようにする。 PyPy Advent Calendar 19日目

| 18:56 | RPythonで正規表現を使えるようにする。 PyPy Advent Calendar 19日目を含むブックマーク

PyPy Advent Calendar 19日目の担当として、ピンチヒッター@行きます!本来2週目は24日に担当ということでのんびりしてたら前の方々が忙しいらしく急遽回って参りました。精一杯がんばるので、どうかいじめないでください。。。 > pypyjaな方々。

今回のテーマ

RPythonではrsreという正規表現インタプリタに提供するための実装はありますが、RPython自身で使用するための正規表現実装がありません。そこで、今回はタイトルにもあるようにRPythonで正規表現を使えるようにするところまでを書きたいと思います。

ことの発端

PyPy Advent Calendar 15日目 - 低レベルっぽいことをやってみるで@さんがRPython Toolchain側の低レベルを紹介していることでした。

ちょっとだけ記事を引用してみます。

ffi とは、Foreign Function Interface と呼ばれるもので、日本語に訳すと他言語関数インタフェイスというらしいです。
要は別の言語の関数を呼び出すための仕組みです。
clibffi の場合は Python から C の関数を呼ぶものです。
そもそも C の関数を呼べないことにはソケット通信もできませんし、スレッドも立てられません。
この clibffi を使うことで ctypes やスレッド、ソケットなどのライブラリ実装したりしているんですね。多分。

そーなんですよね、Cの関数が呼べないと何もできないはず。これと、前に自分もツイッターで呟いたんだけども、

PyPyをビルドするときはlibffi.aを静的リンクしたりしているし、他のライブラリを使って正規表現を実装できないなんてことはないはず!この仮説が正しいことを証明しちゃる!ってことで書きます。

アプローチ

上述しているように、低レベルなAPIを提供するC言語ライブラリをリンクしffiを使ってラップし、それを使ってRPythonに正規表現の機能を提供します。

使用ライブラリについて

上記のツイッターのつぶやきには鬼車を使用するとありますが、筆者の独断と偏見により、PCREというライブラリを選ばせていただきました。ライブラリ選定の際には最近googleからリリースされた?re2というライブライと鬼車とPCREを比較しましたが、ubuntuのパッケージになっており、C言語用のインターフェースがあるということでPCREを使うことにしました。PCREとはC言語においてPerlと互換な正規表現ライブラリレベルで提供するものらしいです。詳しくは本家サイトをご覧ください。http://www.pcre.org/

準備

前置きが長くなりましたが、ライブラリの準備はubuntuであればlibpcre3-devパッケージをインストールするだけです!楽ちん!

sudo aptitude install libpcre3-dev

次にこれは飛ばしてもよいですが、やっておくと楽な設定です。

vi ~/.bashrc
alias rpython='PYTHONPATH=/pypy-src-path/ python'
alias translate='rpython /pypy-src-path/translator/goal/translate.py'

これをやっておくと、いちいちPYTHONPATHを設定したりしなくていいので何回も実行するときに楽です。

次に筆者作のpypy用正規表現ライブラリクローンします。

hg clone https://bitbucket.org/yanolab/pypypcre

このレポジトリにはライブラリ本体(pypypcre.py)とsample.pyの2点だけが含まれています。(適当ライブラリですいません。。。モジュールの構造にすらなってなくてすいません。。。)

確認ができたら準備は終了です。

実行

translate sample.py

としてみてください。sample-cができるはずです。usage出力も実装しておいたので、sample-cと実行して試してみてください。

解説

sample.pyの解説はいいですよね?pythonのとほぼ同じですから。ということで、ライブラリ本体の解説をします。

追記:すいません、Gistの行出てないですね・・・。gist右下のpypyprce.pyを開いて見てもらえればと思います。



  • line:17 PC環境の中からlibpcre.aまたはlibpcre.soを探します。完全にlinux決め打ちです。macやその他のディストリビューションでは適宜ライブラリの検索先を変更するといいと思います。libpcre.aが見つかればトランスレートしたときに静的リンクし、見つからない場合は、libpcre.soを動的リンクします。どちらも見つからないときはpypypcreを利用することはできません。ここはPyPyで使っているlibffiと同じです。
  • line:43 - 92 C言語ライブラリ用にインターフェースを定義しています。ctypesと同じような感じです。おもしろいのは70-71行目のループです。CConfigの値を実際にC言語ソースをはき出して、コンパイル+実行(ダンプ)し、PCRE_ERROR_NOMATCHの値を取得します。PCRE_ERROR_NOMATCHはリンクするライブラリのヘッダに書かれている定数です。./configureを実行しているような感じですね。
  • line:94pcre_externalでC言語インターフェースをRPythonレベルまで昇華させています。実際にPythonで実行するとここはctypesが使われ、translateするとインタフェース使用部分がC言語に落とされます。
  • line:113 - Python正規表現クラスに合わせるための実装です。現在はmatch,compileの2つのみサポートです。もうちょっと完成度あげたかったけど時間がないのでしかたありませんw

もし低レベルなライブラリを作成しようと思ったら

基本Pythonみたいなので、読みやすそうですが、気をつけなければならない点があります。まず、変換後のC言語ソースを想像しながらかかないと間違いなくtype missmatchになります。また、ポインタの扱いがrffiの場合はひじょーーーに難しいです。nullを渡したいところでNoneをしたりするとだめですし、参照渡しも書けません(知らないだけかも)。また、意識しなければならない型が、C言語の型、rffiの型、RPythonの型と3種類(PyPyはさらにそれをラップしてるので4種類)を意識しなければなりません。どれか一つでもずれていると、rpythonでは動くけどtranslateはできないといった自体になります。また、rffiの層で確保したメモリ等は自分で解放しないといけません。

感想

慣れないと正直きついです。つらいです。でもだんだん楽しくなってきます。きっとwしかし、このエントリを読んでうれしい人っているのかどうか・・・たぶんいても日本に2〜3人w

まー誰かの知識の糧となれれば幸いです。

それでは、enjoy your pypy and python life!

2011-12-11

オリジナルのPyPyを手に入れよう。 ~~PyPy Advent Calendar 11日目~~

| 13:04 | オリジナルのPyPyを手に入れよう。 ~~PyPy Advent Calendar 11日目~~を含むブックマーク

PyPy Advent Calendar 11日目の担当として@が書きます。

PyPyとは

PyPyにはややこしいことに、以下の2つの意味があります。公式に別々の名前で呼ぶように呼びかけているみたいです。

1番目をPyPyと呼んで、2番目をRPython Toolchainなんて呼ぶみたいです。

PyPyとRPython Toolchainについての基本的な情報については、@ さんがPyPy Advent Calendar 6日目としてFAQを翻訳されたので、そちらを参照されるのがよいかと思います。

本記事のテーマ

みなさん、PyPyはビルドしたことありますか?おそらくほとんどの人がNoと答えると思います。なぜなら・・・・PyPyのビルドにはものすごーーーく時間がかかります。さらに、ビルドには多量(4GB以上を推奨)のメモリも必要です。ノートパソコンでは絶望的です。以前、2GBのCore2Duoのviaoでビルドを試みたところ、6時間近くかかったあげく、エラーで失敗しました。バキバキと、ものすごい勢いで心が折れます。粉砕されます。ですので、PyPyのビルドには覚悟が必要です(ぉぃ

しかし、プログラマたるもの自分で使う道具(プログラミング言語)にはお気に入りも存在するはずですし、厳選して使っているはずです。職人ともなれば自分で自分の道具をカスタマイズし、自分仕様にして使うなんてことはざらのはずです。

そこで、今回はPyPyをカスタマイズして、自分独自のPyPy(Python)を作ろうじゃないかというテーマで記事を書きます。

準備

まずはレポジトリをローカルに持ってきましょう。

hg clone https://bitbucket.org/pypyja/pypy

上記のアドレスは日本のPyPy使いが利用しているPyPyのレポジトリです。翻訳したドキュメント等をコミットしています。

本題

今回はPythonrubyでおなじみのunless文を追加してみます。

unless文とは、if文の条件が偽の時のみ実行される構文です。要は"if not 条件"と同意です。

unless False:
  print "False"

unless True:
  print "True"
else:
  print "False"

val = 1 unless True else 0
print val

の様に使います。他にもunless elif elseも使えたりします。

RPython ToolchainによるPythonの実装はpypy/interpreter以下に存在します。ですので、unless文を追加する場合はここを編集します。

Pythonの文法はpypy/interpreter/pyparser/data/Grammer2.7に存在します。ここにunless文を追加すれば、字句解析は既存のフレームワークがやってくれるので、pypy/interpreter/astcompiler/astbuilder.pyの構文木を生成する処理に手を加えれば見事完成です。

と、これが正攻法なのですが、今回はちょっとしたチートをおこないますw

(め、めんどくさいからってわけじゃないんだから!シ、シンプルな方法を選んだんだよ!)

上にも書いたようにunless文はif notと同意なので、トークンを切り出すと時にunlessをif notに置き換えてしまいます。字句解析はpypy/interpreter/pyparser/pytokenizer.pyで行っているので、ここに処理を追加します。追加する処理は下記の通りです。

たったこれだけです。もしくは下記のレポジトリクローンしてもOKです。

hg clone https://bitbucket.org/yanolab/pypy

やっていることは、字句解析処理でトークンに切り出したときに、unlessを見つけたらトークン一覧に追加する前に、解析行のunlessをif notに置き換えてから、もう一度if notのところの処理をやり直させているだけです。これでunlessがif notに置き換わります。if not自体はPythonで元から使えるので他に処理はいりません!なんと楽なことでしょう。

あとはPyPyをビルドするだけでunless文を追加した独自のPython処理系が手に入ります。では早速ビルドしてみましょう!と言いたいところですが、絶対にやめましょうw何時間もかけてビルドして失敗したらたまりません。

PyPyではtestコードを書くことを激しく推奨していますので、pypy/interpreter/test以下にテストコードを書いて実装するのが一番です。

また、以外と便利なのがpy.pyです。PyPyにはPythonで動くPyPy実装があります。それがpy.pyです。実行は至って簡単で、

python pypy/bin/py.py

と実行するだけです。最初にC言語ファイルのビルドが走りますが、PyPyのビルドに比べたら圧倒的に短時間で済みます。このインタプリタで動作を確認したらいよいよビルドです。(testは残念ながらはしょりますw)

PyPyのビルド方法に関しては公式ドキュメントがあるのでそこを参照するといいでしょう。

ubuntuであれば下記のパッケージをインストールしておけばOKです。

sudo apt-get install libffi-dev libssl-dev libncurses-dev libexpat-dev libbz2-dev zlib1g-dev

準備ができたら下記のコマンドを実行します。

cd pypy/translator/goal
python translate.py -Ojit targetpypystandalone.py

後は延々とマンデルブロが表示されるので終わるのを待ちます。ビルド中はひたすら他の作業に打ち込むといいでしょう。

ちなみにRPythonの解析はシングルスレッドで動くのでコアは1個しか使いません。なので、デュアルコアとかクアッドコアよりもシングルで速いCPUの方がPyPyのビルドは速く終わると思います。解析が終わったあとのC言語ファイルのビルドはコア数で動くのでコア数が多い方がお得です。解析だけCPUの速いマシンで行って、C言語ファイルのビルド別マシンでとかいうのもありかもしれませんね。

以上で今回のエントリは終わりです。

(本当はあと、独自ビルトインモジュールの作り方と独自ビルトイン関数の作り方、基底クラスのいじり方と書こうと思っていましたが、長くなりすぎるのでまたいつかの機会に。)

次は@さんの担当です!よろしくお願いします。

enjoy your pypy and python life!

2011-07-29

gist.githubを使ってみた。

12:56 | gist.githubを使ってみた。を含むブックマーク

gist.githubはコードの断片を共有するとかなんとかで、

ブログにコードを書くより良さそうなので使ってみた。

こんな感じ。いい感じ?

2011-02-11

pythonをソースからコンパイルするときのメモ

| 14:37 | pythonをソースからコンパイルするときのメモを含むブックマーク

コンパイル環境はUbuntu10.10

pythonコンパイル時にzlibなどの開発ライブラリがないとモジュール作ってくれない。

なので、以下のコマンドを実行して必要そうなライブラリインストールしておく。

sudo aptitude install libzip-dev libssl-dev libreadline-dev libncurses-dev libsqlite3-dev libexpat-dev libbz2-dev libsqlite-dev tcl-dev libgdbm-dev libbsd-dev

他にもあるかもしれない。。。