2010-12-31

映画「ノルウェイの森」の感想

映画「ノルウェイの森」みました。かなりな勢いで、気に入ったので2回みました。また観るかも。そんなわけで、興奮にまかせて映画の感想を書いてみます。

免責事項を2つ。まず、全力でネタバレです。それから、映画や文学のことはほとんど知らないので、かなり稚拙な内容です。映画評ではなくて、感想です。原作もそんなに読み込めていません。はい。以上、いいわけ。

表層的なストーリーはヤンデレなラブストーリーで、その下のレイヤーは、村上春樹お得意の、こちらとあちらの話です。この映画では、その境目に水があるように思えます。原作になかったのか、読めていないのかは不明です。

たとえば、直子とワタナベが再会するのは、池の前のベンチです。このとき、直子はあちらからこちらにきたのでしょう。そしてセックスをするわけですが、そのあと、あちらに行ってしまいます。このとき雨が降っています(これは原作にもある)。

ワタナベが、あっちとこっちを行ったり来たりし始めるのは、阿美寮に行き始めてから。このあたりでは、阿美寮と早稲田大学を交互にカットが入ります。

緑は一貫して、こちらがわにいるんですが、ワタナベがうろうろしているので、プールが登場したりします。

直子と緑に共通する、雪をどう解釈するかは、自分の中でまとまっていません。

最後のほう、レイコさんとワタナベが寝たあと、直子のシーンが出てくる。水辺の木の枝の上にワタナベが立ってて、木の幹に直子がもたれています。レイコさんが、少し離れたところに座っていて、立ち上がり、そのまま直子の前を通りすぎていってしまう。すぐにシーンは切り替わって、ワタナベのアパートから、レイコさんとワタナベが出て行く。

このシーンは原作にはないのですが、原作で直接語られていない、登場人物の世界の移動というか立ち位置の変化を、映像化しているのだと思います。直子のそばからレイコさんが離れていくけれど、ワタナベはそこにいる。だから最後にワタナベは「今、どこにいるんだろう?」って言うわけですよ、きっと。

小説ではこの表現はできないでしょうね。けど、無粋にならない程度に、トランの解釈が表現されていると思いますし、小説だけでは分かりにくい部分が解説されていると思いました。

あと映画を見て思ったのは、ビリヤードでポケットにボールが落ちるのは、井戸に落ちるメタファーなのかな、と。それは考えすぎですかね。

ちなみに、原作があろうがなかろうが、映画は、その製作者(監督なり、脚本なり、俳優なり、カメラなり)の表現である、という解釈をしています。原作に忠実とかはそれほど気にしないです。あんまり離れてたら気持ちわるいですが、原作から汲み取ったエッセンスを使って表現しているんだなぁってことで。なので、スカイ・クロラも好きだし、頭文字Dの海外版も好きです。それを踏まえて、この映画は、原作をよく表現できているなぁと思いました。

2010-12-23

小室淑恵 / 6時に帰るチーム術

ワークライフバランスって言葉が目に付く本ですが、究極的には生産性向上のしくみの提案です。仕事すんな、とか、そういう話ではないです。

たとえば、その日の予定を立てて共有する朝メールと、実績を報告する夜メール。まだ他者と共有してはいませんが、私はカレンダーに大きなタスクをざっくり書きこんで、それを予定にしています。で、それを実績のとおりに修正すると、それが日記というか活動記録になります。ほんとは、予定と実績を別のカレンダーにしたほうがいいのかもしれません。

まあ自分の予定通りには進まないです。残念ながら。

ただし、就業時間と残業時間の区分はしっかりしておきましょう。残業ではどんな業務が多いのか、なぜ残業にずれ込んでしまうのかを意識させると、次のステップにつなげやすくなります。(p.90)

別に勤務時間外で仕事をしちゃいけないとかいう意味ではなく、予定とどのくらいずれているか、ってことのフィードバックが重要なんですよね。そもそも見積が甘いのか、割り込みがあったのか、云々。


共有と言えば、

一つの業務を一人で担当すると、自分にしかわからないことばかりですから、「休みたくても休めない」という状況に陥ります。(p.117)  

こんな話も。仕事自体の共有です。XP のペアプロを彷彿とさせます。レビューやコードの共有は重要だから、ペアプロしようぜという極端なやりかた。いつも仕事を一緒にやっていれば、日々、少しずつ共有が進んでいくってわけです。じゃあいきなり、ってわけにもいきませんが、なにがしか近いことはできるんじゃないかなと思います。

ワークライフバランスっぽい話でいくと、取引先の時間が夜型のときには、全体的にこちらもそれに引きずられやすいので、そうしない工夫とか、あるいは、始業時間をシフトさせることを言えるようにしたい。いまは、なんとなく自分がバリューだせていないっていう引け目があって言いにくい。

業務上のタスクには締め切りがあるはずですが、締め切りまでの間にさらにいくつか「チェックを入れるタイミング=締め切り」を設定するのです。
マネジャーからメンバーに仕事を依頼するときにも、「何を、いつまで、何時間ぐらいかけて」と指示するとともに、「こことここの段階で見せて」と言っておきます。 (p.177 )

ほんとにダサい話なのですが、私は締め切りの設定が下手で、非常に大きな誤差が発生します。ほとんどの場合、見積もりのほうが楽観的すぎますが、「なぜそんなにかかるのか?」という修辞的質問の圧力に屈してしまいます。そしてまったく根拠のない締め切り設定をしてしまう。だからこそ、チェックポイントを用意して、締め切りごとのごさを小さく、そして修正を早めにできるようにならないとなぁ、と、思いましたとさ。自分にも他人にも。



2010-12-07

Python 3.x 対応のフレームワーク QP

Python Web フレームワークアドベントカレンダー の 7 日目担当の、ふるかわとおるです。よろしくお願いします。

あのですね。Python 3.x みんな使わないんですよねぇ。やっぱり、それなりのことをやりたくなると、サードパーティのライブラリに依存することになるんですが、そのライブラリが 3.x 対応じゃないと、なかなか乗り換えられませんよね。特にウェブの場合は、文字列まわりの変更の影響が大きいですし、WSGI の次期仕様である PEP444 が確定してないこともあったりで、軒並み Python 3.x 対応していません。http://python.org/3kpoll を見ると、Python 3.x 対応してほしいランキング 1位が Django ですね。私も1票投じているわけですが。

さてさて、そんなわけで、ここでは Python 3.x に対応しているウェブフレームワーク QP を紹介します。Mac OS X 10.6.5 でビルドした Python 3.2 を使いました。紹介といいつつも、ドキュメントがほとんどないので、必死でサンプルを読み解いた軌跡です。やべぇ、もう 23:22。

インストール

setuptools では、途中のビルドに失敗するので、Distribute を先にインストールします。

http://pypi.python.org/pypi/distribute からソースをダウンロードして、

$ python3.2 setup.py install

つづいて、

$ easy_install-3.2 durus
$ easy_install-3.2 qpy
$ easy_install-3.2 qp

durus は ZODB っぽいデータストレージ、qpy はテンプレートエンジンです。qp は Quixote の後継フレームワークなんですけど、23:27 になったので次。

Hello world!

qp のプロジェクトは、配置する場所が決まっています。/var/qp_sites とか。あるいは環境変数 QP_SITES に格納されたパスに置いておきます。

ここでは qp_sites/hello ディレクトリをまず作ります。必要なファイルがいくつか必要です。

  • qp_sites/hello/__init__.py ... からっぽで OK
  • qp_sites/hello/var ... 空っぽのディレクトリ。pid ファイルとかが置かれる。
  • qp_sites/hello/slash.py ... ここにコードかく
では、slash.py を見ましょう。

from qp.pub.publish import Publisher
from qp.fill.directory import Directory

class SitePublisher (Publisher):
    configuration = {"http_address":("", 8000)}  

class SiteDirectory (Directory):
    def get_exports(self):
        yield ("", "index", "top page", "Home page of hello")  # パス、メソッド名、名前、タイトルのタプル

    def index(self):
        return "hello, world"


ターミナルから
   qp -u hello
で、起動します。






テンプレートエンジン使う準備

変更するファイルがトリッキーです。まず、slash.py を slash.qpy にリネームして、以下のように編集します。

# qp_sites/hello/slash.qpy 

from qp.pub.common import header, footer
from qp.pub.publish import Publisher
from qp.fill.directory import Directory

class SitePublisher (Publisher):
    configuration = {"http_address":("", 8000)}

class SiteDirectory (Directory):
    def get_exports(self):
        yield ("", "index", "top page", "Home page of hello")

    def index [html] (self):
        header("Hello!")  # <html><head> ... とかを出力してくれる
        "<strong>Hello,</strong> <em>World!</em>"
        footer()  # </body></html>を出力してくれる


つづいて、__init__.py も編集。

#__init__.py 
from qpy.compile import compile_qpy_files
compile_qpy_files(__path__[0])


.qpy は、微妙に Python とはことなってて、def index [html] (self) あたりが拡張されています。テンプレートエンジン qpy はこのファイルをコンパイルしたものを使います。なので、テンプレート書き換えたら、qp を再起動します。

  qp restart

index メソッドがテンプレートになっていて、各行を評価した結果の文字列が、テンプレートの出力になります。
header() の戻り値、"<strong>Hello,</strong> <em>World!</em>"、footer() の戻り値が連結されて、レスポンスになります。




テンプレートと永続化を使う

わたくし、ちょうど1年くらい前にウェブ業界にはいりまして、データベースとか詳しくないんですよねぇ。なので、MySQL とかとつなぐとかめんどくさくって。qp なら durus というオブジェクト永続化の仕組みをつかえるので楽ちんです。ZODB を知ってる人ならなじめるらしいです。

# qp_sites/hello/slash.qpy

from qp.pub.common import header, footer, get_publisher
from qp.pub.publish import DurusPublisher
from qp.fill.directory import Directory
from durus.persistent import PersistentObject

class SitePublisher (DurusPublisher):
    configuration = {"http_address":("", 8000)}

    def count_up(self):
        d = self.get_root()
        d['count'] = d.get('count', 0) + 1
        self.commit()
        return d['count']

class SiteDirectory (Directory):
    def get_exports(self):
        yield ("", "index", "top page", "Home page of hello")

    def index [html] (self):
        header("Hello")
        "<strong>Hello,</strong> <em>World!</em>"
        "<p>"
        get_publisher().count_up()
        "</p>"
        footer()

データは SitePublisher クラスのプロパティとして格納されます。でデータは基本的にツリー構造になっていて、ツリーの根をとるのが、get_root() メソッドで辞書っぽいオブジェクトを返します。これに任意のオブジェクトを追加して、commit() メソッドを実行すると、データが保存できます。上の例では、 count_up() メソッドがそれです。



てな感じですね。

まとまらないまとめ

テンプレートが 似非 Python コードであること、データの保存がオブジェクト永続化であること、あたりが、メジャーどころと大きくことなる QP ですが、ちょっと気になっています。durus はマルチスレッド、マルチプロセスに対応している雰囲気です。そんなわけで、QP と Python 3.x 、これからも気にしていこうと思います。

つぎは、Python 界のイケメン地ビール愛好家 @MiCHiLU さんにお願いしまっす。

2010-11-24

web3ref PEP444 の実装例

PEP444 のリファレンス実装の存在を @aodag さんに教えてもらったので、見てみる、という試み。PEP444 は、PEP333 WSGI の後継仕様の提案です。まだ提案段階なので、WSGI 2.0 ではなく web3 という呼称を使っています。

読んでみたコードは、http://github.com/mcdonc/web3 です。Pyramid フレームワークの開発者だそうで。

サンプルコードとして simple_server.py というのがあります。ここで簡単な web3 アプリが定義されています。

def demo_app(environ):
    result = b'Hello world!'
    headers = [
        (b'Content-Length', to_bytes(len(result))),
        (b'Content-Type', b'text/plain'),
    ]
    return (b'200 OK', headers, [result])

戻り値の各要素は、bytes 型、bytes 型、bytes型の配列になっています。これは PEP444 と PEP333 の違いのひとつで、web3 アプリのレスポンスは bytes 型で返すこと、となっています。ステータスコードも bytes 型です。PEP444 でもいくつか理由があげられていますが、Python 2.x 系列の str 型はそれが文字列なのかバイト列なのかが不定である、サーバにエンコーディングをさせたくない、などの理由でこうなっているとのことです。

この簡単なサンプルだけみると、Content-Type の指定なんかで、わざわざ bytes にするのってどうよ、って思いましたが、多くの場合ここには Django とか Pylons なんかのフレームワークがのっかってくるので、アプリ(web3 アプリではなくて、web サービス的な意味でのアプリケーション)で気にしなくてよいでしょう。

ちなみに、to_bytes() 関数は、

def to_bytes(data):
    str(data).encode('ascii')

です。

サーバとハンドラはまた今度。socketserver モジュールで定義されているテンプレート的な基底クラスを、何段階か継承しているので、ゆっくり見てみようかと。いつになるんだろ。

2010-11-20

(第3回)Python mini Hack-a-thon

Python mini Hack-a-thon に初めて行きました。もともと Plone/Zope の hack-a-thon だったらしいのですが、最近は Plone/Zope に特化していないのということなので、こっそり参加です。何かを作り上げるっていうよりも、Python 3.2 を使うことが目的でした。が、しかし、最初の自己紹介で「Python 3 で何かつくる」って言ってしまった手前、まあなにかやろう、と。

標準ライブラリだけを使って、BaseHTTPRequestHandler を継承してフレームワークを作るというのが、どんなもんか、というのが興味あったのですよね。WSGI とかは無視で。

実は一番困ったのは、BaseHTTPRequestHandler.wfile.write() には文字列ではなくて、bytes や bytearray を渡す必要があったんですね。このへん、Python 3 の話をするときにいつも言ってるのですが、自分がやってしまうとは。

久しぶりに、どうでもいいコードを書いた。たのしぃ。やべぇ。

     
import sys
import http.server
import re

PORT = 8001

# --------------------------------------------------------------
# Request handler
# --------------------------------------------------------------

class Handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        return self.show()

    def show(self):
        view = self._find_view(self.path)
        response = view(Request(self.path, self.command))
        response.render(self)

    def _find_view(self, path):
        for pattern, view in urls:
            if re.match("^"+pattern+"$", path):
                break
        else:
            view = error_404
        return view

class Request(object):
    def __init__(self, path, method):
        self.path = path
        self.method = method

class Response(object):
    def __init__(self, data,
                 headers={"Content-type":"text/html"}):
        self.status = 200
        self.headers = headers
        self.data = data

    def render(self, handler):
        self._render_status(handler)
        self._render_headers(handler)
        self._render_content(handler)

    def _render_status(self, handler):
        handler.send_response(self.status)
   
    def _render_headers(self, handler):
        for k,v in self.headers.items():
            handler.send_header(k, v)
        handler.end_headers()

    def _render_content(self, handler):
        data = self.data
        if data is not None:
            handler.wfile.write(data.encode("utf8"))
   
# --------------------------------------------------------------
# View(s)
# --------------------------------------------------------------

def index(request):
    t = "<html><head><title>Hello</title></head><body><p>Hello</p></body></html>"
    return Response(t)

def error_404(request):
    response = Response("404 Not Found", {})
    response.status = 404
    return response

# --------------------------------------------------------------
# main
# --------------------------------------------------------------
   
urls = [('/hoge.*', index)]

def main():
    print("serving at port", PORT)
    httpd = http.server.HTTPServer(("", PORT), Handler)
    httpd.serve_forever()

if __name__ == "__main__":
    main()


2010-11-14

村上龍「歌うクジラ」の感想






村上龍の「歌うクジラ」を読みました。

群像に連載されていた、未来SFディストピア的ロード小説「歌うクジラ」を読みました。iPad の電子書籍版で1,500円です。「五分後の世界」「コインロッカーベイビーズ」「イビサ」みたいな描写が好きな人は、好きなんじゃないかな、と思います。

これまでの作品で描かれていた、あるいは主張されていたことと、今回新たに書かれたこと、の両方があります。村上龍節++ っぽい感じでしょう。ディテール描写でぐんぐん惹きつけられる感じでした。

プラットフォームとしては未来SFですが、書かれているテーマであろう、格差や断絶はタイムリーだと思います。「日本に移民が増えすぎる」みたいなのは、10年前と今ではリアリティが違うと思います。

epub などとの互換性のない電子書籍版を先行販売したことや、小説のウェブサイトがあることなど、メタな話題については、基本的にポジティブに受け取っています。

注意:以下、物語の核心に関する核心部分が明かされます。






大勢の人が笑顔をつくっている乳製品の宣伝映像を父親のデータベースではじめて見たとき、目まいと吐き気を覚えた。害悪だと子供にもわかった。 (p.207)

村上龍は、この種の笑顔を否定する記述を、小説内でよくやっている。本当に本人が嫌っているのか、そういう立場の人を描きたいだけなのかわからないけど。ただ、あまりに無表情な会話を続けると私は不安になります。この人、いやなのかなぁ、あるいは何か威圧しようとしているのかなぁ、と。


歩いて老人施設まで行くのかとアンジョウに聞いても意味がない。アンジョウに付いていく以外に老人施設を目指す方法はないからだ。 (p.332)

やっても意味のないことはすべきではない、っというのも、村上龍がよく明示的に書いています。個人的にそれはよいプラクティスだと思っていて、それは心がけたいなぁと思う。思考停止と間違わないように、と。



あの小型のドーム内にはガラスのグラスで飲みものを飲んでいる特別な人たちがいる。だが外を眺めるためのものではない。あれは自分たちが特別だと示すための施設なのだ。(p.149) 

「VIP 用なんとか」が目に見える状態になっているのは、今でも見せるために見せていると思います。それが商品としての価値だったりする。そのことに自覚的にならないと、まんまとマーケティングの餌食になってしまうなぁと思いました。


人口の減少および労働力の移民への依存度は幾何級数的に高まり生産性は劇的に下がり幾度となく円は暴落してやがて燃料と職労が欠乏するようになるが一般大衆の政治意識はゼロに等しかった。(p.238)

それ今でもそうだよなぁ。最近、政治がらみで盛り上がってるふうだけど、具体的な活動に移す人は殆どいないし、私もまったく行動をしていません。あまりに何もしていないとか、無関心が続くと、いざとなったときに、どうしていいのか分からないと思います。こわこわ。





2010-11-07

Python 3.2 を調べ始めてみた

Python 3.2 alpha 3 が出ているので、見てみました。前提として、私は仕事では Django を使っている(ので、Python 2.x 系)のと、ちょっとした日々の作業のスクリプトを Python 3.1 で書いています。その視点で気になったことリスト。

@atsuoishimoto に教えてもらったファイル名の取り扱いに変更があります。UTF-8 決め打ちじゃなくて、システムロケール使うぜ、と。os.fsencode() と os.fsdecode() でシステムロケールに合わせた、エンコード/デコードができます。

コンパイル済みコードの置き場が変わります。これまでは、foo.py が foo.pyc になってました。が、これだと複数の Python があったりすると、インタプリタが変わるごとに結局再コンパイルでした。てなわけで、__cahced__/foo.cpython-32.pyc みたいなファイル名で保存されます。

Logging の設定を、API 経由だけじゃなくて、辞書で指定できます。

3.1 では hasattr() があらゆる例外を握りつぶしていたのですが、AttributeError 以外はちゃんと伝搬してくれます。

などなど。あと全体的にパフォーマンスが上がっているようです。

個々の変更が、どういう影響があるかは、Python の使い方によって違うと思います。logging 使ってない人にしてみたらどうでもいいわけです。

個人的な印象としては、ものすごく大きな変更ではないようです。が、見逃していることは多々あるでしょうね。

2010-10-10

東京・江戸前トライアスロン 2010

羽田空港のすぐ近くにある、城南島と大井ふ頭で、スイム 750m、バイク 20km 、ラン 5km のスプリントレース「東京・江戸前トライアスロン 2010」に行ってきました。8月に中島大会に出て以来なので、約2ヶ月ぶりのトライアスロンです。

ウェブサイトに、競技説明やコースが載ってて、今日のレース結果が今日中に載っています。

スイム

城南島海浜公園の人工浜と平行に、1往復750mを泳ぎます。水温は23度、凪でとても泳ぎやすかったです。ええ、東京湾です。泳げるのか?とか聞かれますけどね。泳げますよ。そりゃハワイや宮古島に比べたらひどいもんでしょうけど。普通の海で、ヘドロくさい感じです。余裕で泳げます。神戸の須磨がいけるなら、このレースは大丈夫です。

100人未満のウェーブで、4ウェーブでスタートでした。

バイク

城南島と大井ふ頭を往復する、1周10km のコースを、2周回します。全フラット。橋のところでちょっと起伏があるくらいです。

スタート直後と周回が終わるところは城南島で、コーナーが多いです。道幅も1車線程度のところが数カ所あります。一方、大井ふ頭側はほとんど直線で DH バー握りっぱなしです。ただ、トラックの走行による轍があるので走りにくいところがあります。

エイドステーションはありません。20km なら、べつになくてもいいと思います。

ラン

城南島海浜公園の東側の遊歩道を走る、2.5km x 2周回のコース。軽い起伏がありますが、フラットなコースです。こっちはコースが狭め。交通規制をはらずに公園内で2.5km を稼ぐために、細かく折れ曲がっているコースです。でも道は綺麗ですよん。

タイムを見た感じだと、もしかしたら、このコースレイアウトでは5kmないかも知れません。根拠ゼロ。自分が22分で5km も走れたっけかなぁという単純な疑いによります。

給水が、走り始めと、奥の折り返しにあります。今日は気温も低く、小雨もあったりして、1回しか給水していません。暑くても 、この2箇所で大丈夫ではないでしょうか。

その他

多くのトライアスロンレースと同じく、貴重品預かりなんかはありません。都市型のレースだと自走でくる人(私だ)もいるのでそういうのあると便利かなぁと思いますが、まあ、なんとかなるものです。ランニングレースだけの経験があって、初めてのトライアスロンだと困るかも。

あ、あと初心者の人がたくさんいる大会でした。でやすいレースが増えるのはいいですね。

それからスキップ制っていうのがあって、ある種目を飛ばしたり、途中でやめても、次の種目に行っていいっていうルールがありました。もちろん棄権扱いですが、競技を継続する許可を公式にもらえるわけです。スイムで溺れても、バイクができるってことですね。思わず、スイム途中でやめようかと思います。

すでに来年の6月にも開催する予定だそうです。しかも 51.5km で。私はスプリント好きなので、スプリントでもいいんですけどね。選択肢があればそれはそれで嬉しいですし、6月開催なら51.5km だけでも出たいなと思いました。


2010-07-05

須磨海水浴場アクアスロンと、村上春樹「走ることについて語るときに僕の語ること」

須磨海水浴場アクアスロンに行ってきました。新幹線の品川駅で、村上春樹の「走ることについて語るときに僕の語ること」を買って読みながら行きました。

昨年、このレースに参加したとき、スイムでパニクってしまって、棄権しました。今年は大丈夫なように万全の練習をした、わけではなくて、実は今年に入ってから、のべ1km しか泳いでいません。内緒ですけど。ちなみにこのレースは、スイム 1km 、ラン 10km です。



スタート前にちょろっと泳いでみたら、いきなり怖くなって「あーもう、だめ。むり。もう帰る」っていう気分になりました。

[...] 恐怖が身体を支配して、筋肉がこわばってしまう。胸がわけもなくどきどきして、手足が言うことを聞いてくれない。顔が水につけられない。(村上春樹「走ることについて語るときに僕の語ること」p.233)





しばらく浮いていて、ぶくぶくぱーしていたら、慣れてきて、泳げるようになりました。ふう。というわけで、最後尾からスタート。1km のスイムを22分くらいで終えて、トランジションに数分を使い、ランに入りました。



ここのランコースはちょっと複雑で、「己」字型のコースレイアウトになっていて、しかも下半分を二往復してから、元の書き出し位置に戻るみたいなレイアウトです。で、「『」みたいなところで給水なのですが、復路でしか給水してはいけません。昨年は往復路で水をとれたと思うんですが、往路で水を取ろうといたら、とくに説明もなく「帰りにとれ」と怒鳴られてしまいました。



走るのは、スピーチなんかを暗記する作業に向いているような気がする。ほとんど無意識に脚を運びながら、頭の中で順番に言葉を並べていく。文章のリズムを測り、言葉の響きを想定する。[...] ただ頭の中で話をしながら、つい表情をつけたり、ジェスチャーを交えたりしてしまうことがあって、走りながらこれをやっていると、向かいから走ってくる人に不思議な顔をされる。(村上春樹「走ることについて語るときに僕の語ること」p.154)


暗記ではないけれど、私は組み立てをしていることが多いです。プレゼン、面接、主催者への抗議(実際に抗議することは、ない)、素敵な女性への告白(同じく)なんかを考えています。なので、身振りとかしていることや、ニヤニヤしていることがあって、キモいだろうなぁと思います。



今の職場に転職するときに、面接をする日、昼間にトレッドミルで走っているときには、自己PRをどうやって話そうか考えていました。



そんなこんなで、ラン 10km を55分ほどで終わりました。おもったより早かったです。あーたのしかった。



いずれにせよ、ここまで休むことなく走り続けてきてよかったなと思う。なぜなら、僕は自分が今書いている小説が、自分でも好きだからだ。(村上春樹「走ることについて語るときに僕の語ること」p.122)
「がんばりますね」と言われるんですが、まあ、頑張っていないとは言わないまでも、やっぱり私にとって、スイム、バイク、ランは純粋にエンターテイメントです。やっている最中が楽しいです。フィニッシュしても感動しないし、達成感も大したことないです。思うには私は、生き方がかなり刹那的で、「そのとき」が楽しくないと嫌なんですよね。ごほうびのために頑張るとかも、無理です。やっていること自体に楽しみがないと、とてもじゃないとできません。そしてこういうメンタリティは、スキルを身につける上で、非常にやっかいだという自覚はあります。でも、そうおもうんだからしょうがない。

ってなことを考えながらストレッチです。ストレッチもあんまり好きじゃないので、そろそろやめよっと。







2010-06-03

Evernote につぶやく monolog-evernote for Mac OS X


Evernote になんでもかんでもメモするんですが、いちいち Evenote を開くと、ウインドウが大きいのが嫌なのとで、ちっちゃいのを作りました。ツイッターみたいに1行入力するだけの手軽さ。

http://code.google.com/p/monolog-evernote/



スクリーンショット(2010-06-01 12.00.13)  


タイトルは「monolog」で、時刻とテキストが入ります。タイトルには monolog とだけ入れてあります。時刻は created ad フィールドに入るの冗長だと思ったのですが、日記に書き抜くときにまるごとコピペできて便利なので、そのままにしてあります。



スクリーンショット(2010-06-01 12.00.56)  

あと、Leopard の AppleScript エディタと、Snow Leopard の AppleScript エディタで、それぞれアプリケーションを作ったときの、出来上がるものが違います。ってなわけで、別々のバイナリを作りました。


ちなみに @myen という twitter アカウントに D すると、自分の Evernote に入るというサービスがあります。「d myen 」を書き損じると公開されちゃう、ネットに繋がっていないことだってある、という理由から、ローカルのアプリに書き込むことにしました。あと、AppleScript つかえると、何かと自動化できるかなってことで、習作です。




2010-06-02

エキスパート Python プログラミング




アスキーメディアアートより、「エキスパート Python プログラミング」の見本本(みほんぼん)を頂きました。Python でひととおりコードが書けるようになって、次にステップアップしたいけど、これからどうしよう、みたいな人にオススメだと思います。即物的な知識、たとえばライブラリやフレームワーク固有の知識ではなくて、もうちょっとこう一般的な知識として身につける、とか。



たとえば、4章「良い名前を選ぶ」の132ページ。PEP 8 に則って、Python では、プライベートなメソッド、関数、変数には _lowercase をつけましょうという慣例があります。で、__init__ とか __eq__ みたいに、アンダースコアが2つつくメソッドもあるわけです。Python では、__my_method みたいな命名をすることは文法的には禁じられていません。しかしながら、これはなかなかに落とし穴があります。



>>> class Foo:
... def _hoge(self):
... print "_"
... def __fuga(self):
... print "*******"
... def hello(self):
... self._hoge()
... self.__fuga()
...
>>> f = Foo()
>>> f._hoge()
_
>>> f.__fuga()
Traceback (most recent call last):
File "<stdin>", line 1, in
AttributeError: Foo instance has no attribute '__fuga'
>>> f.hello()
_
*******
>>> Foo.__dict__
{'__module__': '__main__', '__doc__': None, '_Foo__fuga': <function __fuga="" at="" 0xc5730="">, '_hoge': <function _hoge="" at="" 0xc57b0="">, 'hello': <function hello="" at="" 0xc5630="">}


アンダースコアをひとつ接頭したメソッドには外部からアクセスできますが、アンダースコアをふたつ接頭したメソッドにはアクセスできません。この動作だけ見ると、プライベートメソッドには、アンダースコアをふたつ接頭するのかなぁと思ってしまいます。そう思っていた時期が私にもありました。



けど、違うんですね。そういう情報って、PEP とか dev のメーリングリストを読めば分かるのですが、情報が分散していますし、なかなか背景となる理由も分かりにくいです。



そういうところを抑えたのが、本書です。他にもテスト、文書系のアプリやモジュール、パッケージの書き方など、ちょっと気合いの入った開発に役立つ知識がいっぱいです。Code Complete や Pragmatic Programmer とかに近い内容です。



ちなみに上記については「Python には動作を強制するようなプライベートメソッドはない。アンスコ2つの挙動は別の理由」です。





2010-03-03

東京マラソンに出てきました

東京マラソンを完走しました。15年ぶりくらいのマラソンで、しかも、さんざんなタイムでした。


いろんなひとに「すごい」とか「根性ある」とか言われますが、少なくとも私にとって、マラソンは純粋にエンターテイメントですし、マラソンは我慢大会というようりもフィジカルな体験です。


前提として、私の走力は、10km のレースで 55分くらいのものです。これはたぶん週に1回くらい、数キロのジョギングをしていれば出せるタイムです。レースだと後ろから数えたほうが早いです。


この位の走力だと、ペース配分、膝の痛み、補給に気をつければ、東京マラソン6時間くらいでフィニッシュできるんじゃないでしょうか。


まず、ペース配分。息切れするようなペースで走ってはいけません。後半で脚の筋肉が疲れてしまって、走れなくなるからです。ウォームアップなしで、スタートはちんたら歩いて、早歩きを経て、ゆっくり駆け足くらいのペースでちょうどいいです。



膝の痛み。筋肉よりも、私の場合は、膝の(おそらくは)腱が痛くなるほうが問題です。腱はが痛いと、ほぐすことも、だましだまし走ることもできなくなります。痛くなったら躊躇わずに歩きました。それから、5km 走ったら、必ず 100m 歩くみたいな感じで。40km も走るとなると、ちょっとした痛みが効いてくるのです。半分から痛くなったとしても、20km も痛い思いをしないといけません。なので、痛くならないように、フォームに気をつける、歩く、を心がけるわけです。


最後に、補給。エンデュランス競技はどれもそうなのですが、遅い方が大変です。練習している人なら、ほとんど息切れしないペースだと4時間くらいでしょう。ですが私は6時間ですから、似たような負荷で 50 % も長い時間運動を続けます。9時スタートで、15時ゴールですから、おやつの時間まで運動続けるわけですよ。何もしないと、当然、エネルギー切れになってしまいます。東京マラソンでは後半まで補給食がでないのですが、それだとたぶん遅いんですね。なので、パワーバージェルなどを携帯して、最初から 5km ごとに補給しました。それでも足りないくらいでした。おそいと人形焼きとかの補給食がなくなっているんです。というわけで、かなりな勢いで沿道の方からチョコレートもらいました。


東京マラソンはギャラリーが多くて楽しいです。それはそれで勇気づけられますが、おそらくは、ポテンシャルぎりぎりまで実力がでるという効果しかないんですよね。ギャラリーがいるからポテンシャルを超えるのではなくて、ギャラリーがいないからポテンシャルまで実力が出ない、というのが真実に近そうです。


それよりもギャラリーにもらうチョコレートですよ。ほんとのところ、大会が提供する以外のサポート受けるのは失格なのかも知れません。


とまあ、そんなわけで、なんとか完走しました。6時間ちかくかかりました。そして、体力を消耗する体験ですが、同時にこれは私にとっては、やっぱり純粋にエンターテイメントです。あーたのしかった。来年も出たいなぁ。



2010-01-22

Python 3 ハンズオン資料 for Python Hack-a-thon #3

概要



このハンズオンでは、Python 2.x のコードを 3.x に移植するときの簡単な手順を体験します。願わくば午前中に終わらせて、午後は自由に時間を使ってもらうつもりでいます。





使用するソフトウェア





Python 3 のポイント
別の勉強会(BP Study)で使った資料



2.x 版で動作確認



foo.py は Yahoo! の検索 API の結果を受け取って、テキストファイルに保存するプログラムです。そして tests.py は、一部の昨日のユニットテストです。これらが動作することを確認してみましょう。



$ python2.6 2/tests.py
...
----------------------------------------------------------------------
Ran 4 tests in 0.330s

OK
$ python2.6 2/foo.py
$


2to3 の実行



Python 3.x には 2to3 という変換ツールが付属します。これを使って、コードを変換してみましょう。



$ mkdir 3
$ cp -r 2/*.py 3/.
$ 2to3-3.1 -w 3/
RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: set_literal
RefactoringTool: Skipping implicit fixer: ws_comma
RefactoringTool: Refactored 3/foo.py
--- 3/foo.py (original)
+++ 3/foo.py (refactored)
@@ -1,10 +1,10 @@
# -*- encoding: utf-8 -*-
-import urllib
+import urllib.request, urllib.parse, urllib.error
from xml.dom.minidom import parseString
from utils import get_text

def main():
-    query = u'ほげ'
+    query = 'ほげ'
     count = 10
     response = open_yahoo(query, count).read()
     dom = parseString(response)
@@ -18,10 +18,10 @@
def open_yahoo(query, count):
     api = 'http://search.yahooapis.jp/WebSearchService/V1/webSearch'
     appid='CDU9keOxg67iAhAcNjcEjZbj25HFcV2DkA62bAxhQn_4FUoPJN2lFQdP5MfnIksh75e650BR.A--'
-    params = urllib.urlencode({'appid':appid,
+    params = urllib.parse.urlencode({'appid':appid,
                                'query':str(query.encode('utf-8', 'ignore')),
                                'result':count})
-    response = urllib.urlopen(api+'?'+params)
+    response = urllib.request.urlopen(api+'?'+params)
     return response

class Result:
RefactoringTool: Refactored 3/tests.py
--- 3/tests.py (original)
+++ 3/tests.py (refactored)
@@ -14,8 +14,8 @@
                          get_text(dom.getElementsByTagName('bar')[0].childNodes))

     def testJp(self):
-        dom = parseString(u"

こんにちは

".encode('utf-8'));
-        self.assertEqual(u"こんにちは",
+        dom = parseString("

こんにちは

".encode('utf-8'));
+        self.assertEqual("こんにちは",
                          get_text(dom.getElementsByTagName('bar')[0].childNodes))

class AskYahooTest(unittest.TestCase):
RefactoringTool: No changes to 3/utils.py
RefactoringTool: Files that were modified:
RefactoringTool: 3/foo.py
RefactoringTool: 3/tests.py
RefactoringTool: 3/utils.py


ここで 2to3 がやっていることは以下のとおりです。



  • u'...' → '...'


  • print 文 → print 関数


  • urllib の階層変更


3.x 版のユニットテスト



では 3.x 版のユニットテストをしてみましょう。



$ python3.1 3/tests.py
FF..
======================================================================
FAIL: test (__main__.AskYahooTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "3/tests.py", line 29, in test
    self.assertEqual(count, len(dom.getElementsByTagName('Result')))
AssertionError: 10 != 7

======================================================================
FAIL: testURL (__main__.AskYahooTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "3/tests.py", line 36, in testURL
    'http://search.yahooapis.jp/WebSearchService/V1/webSearch?query=yahoo&result=10&appid=CDU9keOxg67iAhAcNjcEjZbj25HFcV2DkA62bAxhQn_4FUoPJN2lFQdP5MfnIksh75e650BR.A--')
AssertionError: 'http://search.yahooapis.jp/WebSearchService/V1/webSearch?query=b%27yahoo%27&result=10&appid=CDU9keOxg67iAhAcNjcEjZbj25HFcV2DkA62bAxhQn_4FUoPJN2lFQdP5MfnIksh75e650BR.A--' != 'http://search.yahooapis.jp/WebSearchService/V1/webSearch?query=yahoo&result=10&appid=CDU9keOxg67iAhAcNjcEjZbj25HFcV2DkA62bAxhQn_4FUoPJN2lFQdP5MfnIksh75e650BR.A--'

----------------------------------------------------------------------
Ran 4 tests in 0.986s

FAILED (failures=2)




2つテストが失敗しています。ひとつめは結果のエントリ数が10であるはずが、7件しか返ってきていないこと。もうひとつは、URL として生成した文字列が一致していないことです。



実は、この場合は URL が間違っているので、件数が期待通りになりません。



3.x 版のユニットテストを通す



    fout = file("result.txt", "w")
    for result in results:
        fout.write(("%s\n" % result.url).encode("utf-8"))
        fout.write(("%s: %s\n"%(result.title, result.summary)).encode("utf8"))
        fout.write("\n")


Python 2.6 では、urlencode() 関数に与える辞書の value は、ASCII 文字列 str 型でなければなりません。なので、このコードでは明示的にエンコードしています。



一方、Python 3.1 で、.encode() メソッドの戻り値は bytes 型というバイトシーケンスです。それを str() すると 「b'...'」のようなユニコード文字列に変換されます。前後に不必要な文字がついてしまうのです。また 3.1 の urlencode() 関数はユニコード文字列を受け取ると、UTF-8 で自動的にエンコードします。



というわけで、ここは 2.x と 3.x の非互換な関数を使っていますので、コードを修正しましょう。



    fout = open("result.txt", "w", encoding="utf-8")
    for result in results:
        fout.write("%s\n" % result.url)
        fout.write("%s: %s\n"%(result.title, result.summary))
        fout.write("\n")


で、テスト実行。


$ python3.1 3/tests.py
....
----------------------------------------------------------------------
Ran 4 tests in 0.474s

OK


テストがとおりました。オレ、できたよ、かーちゃん。



3.x 版の動作確認



ではアプリのほうを実行してみましょう。



$ python3.1 3/foo.py
Traceback (most recent call last):
  File "3/foo.py", line 36, in

    main()
  File "3/foo.py", line 12, in main
    fout = file("result.txt", "w")
NameError: global name 'file' is not defined



がーん。またもやエラーです。Python 3.x では file() 関数が廃止され、open() 関数を使うことになっています。というわけで foo.py を以下のように修正します。ついでにエンコード方法を指定しておきましょう。



    fout = open("result.txt", "w", encoding="utf-8")  # ここ


これでどうでしょう。



$ python3.1 3/foo.py
Traceback (most recent call last):
  File "3/foo.py", line 36, in


    main()
  File "3/foo.py", line 14, in main
    fout.write(("%s\n" % result.url).encode("utf-8"))
TypeError: must be str, not bytes





またもやエラーです。fout はテキストモードで開いているので、write するときには必ず str つまりユニコード文字列を渡さないといけません。




fout.write("%s\n" % result.url)
fout.write("%s: %s\n"%(result.title, result.summary))
fout.write("\n")


これで完成です。



というわけで...



What's New in Python 3.x のガイドのとおりの手順で、2.x から 3.x への移植作業をしてみました。ガイドにも書かれているように、ユニットテストは重要です。2to3 はそこそこやってくれますが、いろいろと細かい修正作業が必要で、とくに文字列周りはアプリケーションが何をしているのか知らないといけません。



また、この例ではサードパーティのライブラリを使っていません。Django のようなおおきなライブラリやフレームワークを使う場合には、ライブラリ側が 3.x 対応していないと、Python 3 への以降は難しいと思います。



さらにここではアプリケーションの移植でしたが、ライブラリの移植では工夫が必要になります。 Python 2.x と Python 3.x の両方をサポートしたいのであれば、できれば 2to3 だけで変換できるようにしておくのが得策でしょう。



というわけで、Happy Hacking!!



pyhack3py3ex.zipをダウンロード






 



メモ





2010-01-08

2009年ふりかえり

人に見せられないノートには、いろいろ書いてあるのですが、それとは別に。



  • 1月 記事や文章をたくさん書いた。


  • 2月 コーチングを受けつつ、マーケティング業務に集中。


  • 3月 社内の部署間調整。Python code reading 08 で話す。


  • 4月 たまには技術的な問題解決に当たる。


  • 5月 BP Study に行ってみる。


  • 6月 覚えていない


  • 7月 新製品のマーケティング戦略/戦術に没頭。夜は運動。よく体こわさなかった。


  • 8月 10年ぶりのトライアスロン中島大会完踏。テレビ愛媛に家族ごと取材される。


  • 9月 残業務を片付けつつ、引き継ぎ。


  • 10月 有給休暇の消化、引っ越し。初めてドイツに行くが、ビールの写真しか残っていない。


  • 11月 新しい職場で働き始める。プロジェクト管理。


  • 12月 プロジェクト管理と PHP 案件引き継ぎなど。


7月の全力投球っぷりに、我ながらびびります。退社0時、出社3時とか、もうやらないですけど。この活動が成功だったか失敗だったかは、市場が決めることですが、いずれにせよ、結果は私自身の実力を反映したものだと思っています。



Python 界隈での活動が増えました。Python Code Reading 08 では初めて勉強会の講師で参加しました。そこで @atusi さんや IanMLewis さんから、BP Study の存在を教えてもらって、そっちにも行ってみたり。LLTV にも呼んでもらいました。そして、NI から Be Proud に転職。Python hack-a-thon #2 も楽しかったです。今年は Hack-a-thon で、ハンズオンさせてもらうことになりました。わーい。



転職してみて自分にとっての強みや弱みも浮き彫りになりました。今年はそれらの課題を克服していきたいな、と。



2010-01-02

「一九八四年」と「五分後の世界」の略語に関する対称性


ジョージ・オーウェルの「一九八四年」と言えば、村上春樹の「1Q84」ですが、それはおいといて(おいとくのかよ)、村上龍の「五分後の世界」です。



「一九八四年」も「五分後の世界」も全体主義となった自国のパラレルワールドが描かれているのですが、こまごまとした設定が対照的です。



一九八四年のオセアニアでは、元の意味が分からなくなるような略語が使われます。たとえば、English Communism の代わりに Engsoc、Ministry of Love の代わりに Miniluv など。



一方、五分後の世界の日本では、正確な意味を忘れないようにという動機から、略語は奨励されません。たとえば、CNN と言った生徒が、Cable News Network と言い直させられるシーンがあります。



前者の政府は国民が無知であることを強く望んでいて、後者の政府は国民が無知であることを危機であると考えています。その根本的な違いの表れとして、略語の扱いが全く逆であるな、と思いました。