そうだ! EuroPython 2011へ行こう

#4アプリケーションに関する講演、LT、PSFメンバーミーティング、まとめ

前回はCPythonの講演PyPyの講演を紹介しました。今回は、Pythonで開発されたフレームワークやライブラリといったアプリケーションに関する講演を紹介します。

Application:アプリケーション

Beyond Python Enhanced Generators:Python拡張ジェネレーターの先へ

動的にシーケンスを生成するものとしてジェネレーターがあります。本講演を紹介する前にPythonのジェネレーターについて簡単に紹介します。ジェネレーターは、関数を定義してreturnの代わりにyieldというキーワードを使うことで作成できます。

>>> def f():
...   for i in range(3):
...     yield i

>>> g = f()
>>> g.next()
0
>>> g.next()
1
>>> g.next()
2
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

forループの中でyield文が実行される毎に、この関数の処理が一時停止して呼び出し元に値が返されます。呼び出し元ではnext()メソッドを実行することで、 ジェネレーター関数を再開しyieldされた値を受け取れます。

ジェネレーターを任意の場所で終了させるときは、ジェネレーター関数内で明示的にStopIterationを発生させます。また、このサンプルのように関数の終了時に自動的にStopIterationが発生します。

yield文は、Python 2.2から利用できるようになりましたが、その後、PEP 342によりyield文はyield式として再定義されました。

>>> def f():
...   msg = yield "send me message"
...   print msg
...   yield

>>> g = f()
>>> g.next()
'send me message'
>>> g.send("Hello")
Hello

send()というメソッドでジェネレーター内へメッセージを送り、ジェネレーターの処理を再開させます。この仕組みを応用したデータストリーミングライブラリがWeightlessです。

本講演はWeightlessの開発者でもあるErik Groeneveld氏によって行われました。なお、本講演はBEYOND PYTHON ENHANCED GENERATORSスライドから視聴できます。

Erik Groeneveld氏
Erik Groeneveld氏

Weightless

Weightlessは、HTTPのようなプロトコルスタックを含め、Pythonでコルーチンを実装するためのライブラリで次の3つのコンポーネントからなります。

Weightlessは、ジェネレータが次々にジェネレーターを呼び出して処理を委譲するモデルをとります。講演の中ではcomposeモジュールで、サブジェネレーターに処理を委譲するサンプルコードが紹介されました。

Weightlessモデル
Weightlessモデル

トランポリンモデル

一方でWeightlessのモデルと対比してトランポリンモデルも紹介されていました。筆者はトランポリン(trampoline)という言葉は聞いたことがあるものの、具体的にどういったものかが理解できていなかったので参考になりました。

トランポリンモデル
トランポリンモデル

トランポリンモデルを表す次のサンプルコードが紹介されていました。

def demo_coroutine():
  """coroutine a la COBOL"""
  def coroutine_a(n = 0):
    while n < 10:
      n = yield b, n + 1
      print ">", n
  def coroutine_b(n = 0):
    while n < 10:
      n = yield a, n + 1
      print "<", n
  a = coroutine_a()
  b = coroutine_b()
  a.next()
  b.next()
  g = (a, 0)
  while True: # トランポリン
    try:
      g = g[0].send(g[1])
    except:
      break
>>> demo_coroutine()
> 0
< 1
> 2
< 3
...

coroutine_acoroutine_bを、coroutine_bcoroutine_aを交互に呼び出します。この2つのジェネレーターを交互に呼び出す制御部にあたるのがwhileループの部分です。

while True:  # トランポリン
  try:
    g = g[0].send(g[1])
  except:
    break

g = g[0].send(g[1])はそれぞれのジェネレーターを交互に呼び出します。a.send(0)を実行するとcoroutine_aではn = 0がセットされ、print “>”, nが呼び出され、ループの先頭に戻ってyield b, (n + 1)によりcoroutine_aが一時停止します。呼び出し元ではg = (b, 1)が返されて、次のループでb.send(1)が実行されます。それからb.send(1)を実行すると、先ほどと同様にyield a, (n + 1)coroutine_bが一時停止して、g = (a, 2)が返されます。

このように、ある関数を呼び出すと次に呼び出す関数が得られて、次々に繰り返し関数を呼び出す仕組みのことをトランポリン(trampoline)と呼ぶそうです。

composeとPEP 380

composeモジュールを使ってジェネレータの処理をサブジェネレーターへ委譲します。Pythonのジェネレーターは、その直前の呼び出し元に対してのみyieldするという制約があります。この制約により、ジェネレーターの処理をサブジェネレーターに分解しようとした場合、その仕組みが複雑になります。

実際に簡単なサンプルコードを書いてみます。

>>> def f():
...   yield "Hello"
...   msg = yield
...   yield msg

>>> def g():
...   yield f()

>>> _r = g()
>>> _r
<generator object g at 0x10078ca00>

>>> r = _r.next()
>>> r
<generator object f at 0x10078c550>
>>> r.next()
'Hello'
>>> r.next()
>>> r.send("World")
'World'

composeを使うと、この処理は次のように書けます。

>>> from weightless.core import compose
>>> r = compose(g())
>>> r
<generator object _compose at 0x10078c910>
>>> r.next()
'Hello'
>>> r.next()
>>> r.send("World")
'World'

g()というジェネレーターが返すサブジェネレーターを意識せずに操作できます。委譲の考え方から、呼び出し元はg()ジェネレーターが何をするかを知る必要はないのでcomposeがサブジェネレーターを適切に扱ってくれると、呼び出し元とg()ジェネレーターとの結合度が低くなります。

そしてcomposeはデコレーターとして使うこともできます。

@compose
def g():
  yield f()

また、PEP 380により、Python 3.3で導入予定のyield from式を使って次のように記述できるようになる予定です。

def g():
  yield from f()

composeyield fromとよく似た概念であり、さらに少し拡張したものだそうです。

5 Years Of Bad Ideas:過去5年間のバッドアイディア

日本でも人気のあるmitsuhikoことArmin Ronacher氏による講演です。氏はFlask,Jinja2,Sphinxといったフレームワークを開発しているPocooという開発チームのリーダーの1人でもあります。

本講演は、過去5年間、様々なフレームワークやライブラリを開発してきた氏の経験から「バッドアイディア」を紹介するものでした。こういったテクニックは、普通のアプリケーション開発では多用するものではないのでご注意ください。

なお、本講演は5 YEARS OF BAD IDEASから視聴できます。資料とサンプルコードも公開されているので、興味のある方はそちらも参照してください。ここでは、その中から一部の内容を紹介します。

Armin Ronacher氏
Armin Ronacher氏

Pythonとは何か?

Armin氏は、次の3つの要素をPythonの本質的な価値として挙げていました。

  • 美しいコード
  • 統合性のある整然とした構文
  • 関数を含め、すべてがファーストクラス

また、今回の講演の題材として次の要素が紹介されました。これらは、Pythonの深い部分の仕組みを知るきっかけとして筆者は興味深く聞いていました。

魔法について

@zedshaw氏による魔法についての見解を引用していました。少し調べてみましたが、この見解の意図することを筆者は掴めていません。どなたか分かる方がいましたら筆者に教えてください。

“And honestly, I only find this shit in web frameworks. WTF is up with Python people going ballistic when a web app uses magic? Bullshit.”

― Zed Shaw about Magic

また、本講演で言う魔法というのは、Webアプリケーションが正常に動かなかったときにデバッガを起動して対話的に調べるヘルパー機能の提供や、いざというときに動的にパッチを当てて対応するような用途においては、有効な場合もあると紹介されていました。

魔法の書

普通の魔法
普通の魔法
フレームオブジェクト

sys._getframe()は、コールスタックのフレームオブジェクトを返します。このフレームオブジェクトは、インタープリターからの情報源になります。例えば、実行中のソースの行番号は次のようにして取得できます。

>>> import sys
>>> sys._getframe().f_lineno
1

また標準ライブラリにあるオブジェクトの情報を調べるinspectモジュールも、内部的にsys._getframe()を使ってフレームオブジェクトを取得します。上述した行番号の取得は次のコードと同じです。

>>> import inspect
>>> inspect.currentframe().f_lineno
1
メタクラス

Pythonでメタクラスを使うには__metaclass__という特殊メソッドにtype()を継承したクラスを指定します。例えば、クラスの生成時にhelloというメソッドをもっているかをチェックするサンプルが次になります。

class MyMetaclass(type):
  def __new__(cls, name, base, d):
    rv = super(MyMetaclass, cls).__new__(cls, name, base, d)
    if not getattr(rv, "hello", None):
      raise NotImplementedError("Need to implement hello method")
    return rv

class MyClass(object):
  __metaclass__ = MyMetaclass

  def hello(self): pass

通常はこのようにメタクラスへtype()を継承したクラスを指定しますが、この方法だとクラスに対して1つのメタクラスしか持てません。Pythonのclass文はtype()のシンタックスシュガーなので、__metaclass__はクラスでなくても、型オブジェクトを返すファクトリ関数を指定することもできます。

def implements(*interfaces):
  cls_scope = sys._getframe(1).f_locals
  metacls = cls_scope.get('__metaclass__')
  metafactory = make_meta_factory(metacls, interfaces)
  cls_scope['__metaclass__'] = metafactory

class MyClass(object):
  implements(Interface1, Interface2)

implements関数内でクラスの__metaclass__にファクトリ関数を指定するサンプルが紹介されていました。この方法だと、implementsは複数のインターフェイスを受け取れます。このサンプルの完全なソースはinterfaces.pyにあるので、興味がある方はそちらを参照してください。

AST(抽象構文木)のハック

標準ライブラリにPythonのソースコードを抽象構文木というツリー状のデータに変換するastモジュールがあります。抽象構文木の演算子を書き換えるサンプルコードが紹介されていました。

>>> import ast
>>> x = ast.parse("1 + 2", mode="eval")
>>> x.body.op = ast.Sub()
>>> eval(compile(x, "<string>", "eval"))
-1

インタープリターとの魔大戦

インタープリターとの魔大戦
インタープリターとの魔大戦
変数名の取得

簡単にできそうで、いざやろうとすると、どうして良いのか悩むような課題です。 ガベージコレクタとのインターフェイスを提供するgcモジュールを使って変数名を取得しています。

import gc
import sys

def find_names(obj):
  frame = sys._getframe(1)
  while frame is not None:
    frame.f_locals
    frame = frame.f_back
  result = set()
  for referrer in gc.get_referrers(obj):
    if isinstance(referrer, dict):
      for k, v in referrer.iteritems():
        if v is obj:
          result.add(k)
  return tuple(result)
>>> a = []
>>> b = a
>>> find_names(a)
('a', 'b')
暗黙のself

Pythonの特徴の1つ、明示的なselfを隠してしまうハックです。

class User(ImplicitSelf):

  def __init__(username, password):
    self.username = username
    self.set_password(password)

  def set_password(password):
    self.hash = hashlib.sha1(password).hexdigest()

  def check_password(password):
    return hashlib.sha1(password).hexdigest() == self.hash

メタクラスを使ってメソッドのバイトコードを書き換えているようです。

class ImplicitSelfType(type):
  def __new__(cls, name, bases, d):
    for key, value in d.iteritems():
      if isinstance(value, FunctionType):
        implicit_self(value)
    return type.__new__(cls, name, bases, d)

def implicit_self(function):
  code = function.func_code
  bytecode, varnames, names = inject_self(code)
  function.func_code = CodeType(code.co_argcount + 1,
    code.co_nlocals + 1, code.co_stacksize, code.co_flags,
    bytecode, code.co_consts, names, varnames,
    code.co_filename, code.co_name, code.co_firstlineno,
    code.co_lnotab, code.co_freevars, code.co_cellvars)

このサンプルの完全なソースはimplicitself.pyにあるので、興味がある方はそちらを参照してください。

lightning talks:ライトニングトークス

技術系イベントでは、定番といって過言ではないでしょう。5分間で持ちネタを発表するライトニングトークスというセッションがあります。

ライトニングトークスは、イベント期間中に2回行われました(水曜日と金曜日⁠⁠。誰でも発表できる自由応募形式で、募集用の模造紙に名前を書けば良いというものでした。小宮さん@tk0miyaと筆者もライトニングトークスで発表しました。

ライトニングトークス募集板
ライトニングトークス募集板

blockdiag

小宮さんは、自身が開発しているダイアグラム生成ツールblockdiagについて発表されました。

blockdiagの発表開始
blockdiagの発表開始

英語で発表というのはやや敷居が高くなりますが、アプリケーションだと細かいことを(英語で)説明しなくても、デモをすれば分かってくれるので発表しやすいと思います。小宮さんは堂々とした様子で発表されているように筆者からは見えました。

blockdiagの発表風景
blockdiagの発表風景

そして、ライトニングトークスで発表した翌日、Raymond氏によるThe Art Of Subclassing:アート・オブ・サブクラスの講演中「クラスの動作を説明するのに良いツールがあってね」と、seqdiag(シーケンス図の作成ツール)を使って説明されました。

講演の中で使われたseqdiagのダイアグラム
講演の中で使われたseqdiagのダイアグラム

その後もblockdiagに数式を記述できるようにしてほしい、フィッシュボーン・チャートを生成できるようにしてほしい、といった要望が海外から寄せられているようです。

ライトニングトークスという、ほんの5分間の発表であっても日本から世界へ情報発信したことが良い結果につながったようです。筆者は、アプリケーションというのは、積極的に普及に努めない限り、それが優れたものであっても広く浸透しないものだと考えています。

開発者から見ると、普及することが目的ではないという意見もあるでしょうが、より多くの場面や多様な人に使ってもらうことで、機能要望やバグ報告が増え、自然にアプリケーションの品質を高めることにつながります。何よりもたくさんの人に使ってもらえることは、開発者にとっては幸せなことであり、モチベーションに影響します。

ikazuchi

筆者もせっかくの機会なのでikazuchiという翻訳ツールについて発表しました。

7割ぐらいは準備していった通りに進められたのですが、いざ発表してみて、失敗したことが1つありました。慣れない英語の発表だからと、手元の画面で資料やコマンドを見えるようにするために、ディスプレイのミラーリング機能を無効にしてプレゼンテーションに臨みました。

会場ではスクリーンが発表者の真後ろにありました。ミラーリング機能を無効にしていたため、デモのコマンド入力において、実際のスクリーンに映される画面が見えず、タイピングするのが困難な状況でした。そんなこともあろうかと、ターミナルにコマンドのヒストリを残しておいて、それを使ったのですが、実際にタイピングできなかったのが残念でした。

慣れない環境や状況で実際にやってみると、その場で気付くことがあります。とはいえ、筆者はこの失敗のおかげで今後の発表では同じ失敗をしないでしょう。筆者は海外のイベントで英語のライトニングトークスでしたが、日本でもやるような失敗をしてしまい、あまり特別なものではなかったというのが率直な感想です。

読者の皆さんも臆せず、海外イベントへ行ってどんどん発表しましょう。

PSF membership meeting:PSFメンバーミーティング

本カンファレンスとは直接関係ありませんが、筆者は会場の一室で開催されたPSF(Pythonソフトウェア財団)メンバーミーティングにも参加しました。

PSFミーティングのスライド
PSFミーティングのスライド

meeting:ミーティング

ミーティングの参加者は25名程度でした。PSFは、Pythonの実装以外をサポートする組織であり、CPython財団ではないと説明がなされました。

Pythonの実装には、C言語以外にJava VM向けのJython.NETフレームワーム向けのIronPythonPythonで実装されたPyPyなどがあります(参考:PyPyについての講演、ハンズオン、スプリント⁠。

ミーティングでは、昨年の財団の活動内容や収支報告が行われました。また、PSFの今後の活動方針や役割についても質疑応答で活発に議論されました。

wikiやメーリングリストでは、コミュニケーションが取り難いといった、組織の規模が大きくなり、メンバー間のコミュニケーションをどう取るかについての話題が出ました。難しい問題であり答えはないのですが、こういったミーティングに参加して話し合うということそのものに意義があるように筆者には感じられました。

membership election:メンバー投票

PSFメンバーになるには、現PSFメンバーに推薦してもらう必要があります。筆者は、本カンファレンスに向かう前に、Python Insiderプロジェクトを統括しているDoug Hellmannに推薦してもらいました。その後、PSFメンバーで投票が行われ、一定数の賛成を得るとPSFメンバーになれます。

今回開かれたPSFメンバーミーティングは、私も含め、新たに推薦された数名のPSFメンバーの投票案内も行われました。推薦を受けているメンバーでミーティングに参加したのは筆者だけだったので、その場で簡単に自己紹介させてもらい、筆者にとっては良い思い出になりました。

つい先日、投票結果のメールが届きましたが、筆者はPSFメンバーに選出されました(参考: PSFメンバーの投票結果⁠。筆者は今後もPythonに関する活動に深く関わっていこうという思いがあります。日本に閉じた活動だけでなく、もっと世界の人々と交流していければ良いなと考えています。

brochure project:ブローシュアプロジェクト

Pythonの幅広い展開を狙い、プログラミングやコンピューターの知識をもたない経営者、先生や学生といった技術者以外の方にもPythonを知ってもらい、様々な場面や場所で活用してもらえるように普及活動を行うPSF Pythonブローシュアプロジェクトが紹介されていました。

いまは20ページ程度で構成されたパンフレットが用意されています。残念ながら、いまのところ国際化の取り組みはないようにみえます。逆に考えれば、国際化の取り組みをつくる余地があるとも言えます。国際的なマーケティング(?)に興味がある方は、参加されてみてはいかがでしょうか。

Sprint:スプリント

本カンファレンスは月曜日から金曜日までの5日間の開催でしたが、その週末の土曜日と日曜日にスプリントという開発イベントが開催されました。

スプリントは、本カンファレンスのイベントではなく、参加者の有志がグループ(プロジェクト)毎に分かれ、そのグループで目標を設定して課題に取り組むというイベントです。大抵は、その対象のプロジェクトのバグ修正や機能拡張を行います。

今回はCPython,PyPyといった言語処理系から、DjangoMoinMoinといったアプリケーションまで、全部で10個のグループがありました。

小宮さん@tk0miyaは、MoinMoinのグループに参加して、blockdiagMoinMoinに組み込む拡張を行っていました。池さん@rokujyouhitomaは、PyPyのグループに参加して、日本でPyPyのコミュニティの立ち上げをコミットメントされました(参考:PyPyスプリント⁠。筆者は、Django REST fraweworkのグループに参加しましたが、グループワークのようにはいかず、チュートリアルを読んで黙々とやってました。

MoinMoinスプリントに参加中の小宮さん
MoinMoinスプリントに参加中の小宮さん
PyPyスプリントに参加中の池さん
PyPyスプリントに参加中の池さん

観光

せっかくの機会なので少し観光もしてきました。筆者は、初めてイタリアへ行き、イタリアという国がとても好きになりました。食べ物はおいしいし、気候も良いし、街の外観も素晴らしかったです。イタリアの雰囲気が分かるような写真を紹介します。

季節にもよるのでしょうが、朝5時から夜の21時過ぎまで外が明るくて、自然にイベント終わったら出掛けようという気になります。イタリアの19時は、日本で言う16時の明るさです。

19時過ぎのイタリアの明るさ
19時過ぎのイタリアの明るさ

Florence:フィレンツェ

フィレンツェは、美術館や教会も多くまさに観光都市とった感じでした。その中でも筆者は、ホテルの近くの高台から展望したこの風景が一番好きです。

フィレンツェ市街の展望
フィレンツェ市街の展望
夕暮れの教会
夕暮れの教会

Roma:ローマ

特に期待して行ったわけではなかったのですが、行ってみたらすごくテンションがあがったのがコロッセオでした。筆者は、時間的・空間的なスケールを感じるものに感動するということがコロッセオと出会って初めて気付きました。

コロッセオ
コロッセオ
コロッセオの内部
コロッセオの内部
ヴァチカン市国のサン・ピエトロ大聖堂
ヴァチカン市国のサン・ピエトロ大聖堂
トレヴィの泉でお金を投げ入れる小宮さんと筆者
トレヴィの泉でお金を投げ入れる小宮さんと筆者

Dishes:料理

骨付きのお肉は、海外ならでは豪快な雰囲気で味もおいしかったです。日本だと、きっと値段が高そう…と躊躇してしまいますね。

カルボナーラ
カルボナーラ
骨付きのお肉(1Kg)
骨付きのお肉(1Kg)
生ハムメロン
生ハムメロン
ピッツァ
ピッツァ

PyCon JP

PyConというPythonの公式カンファレンスは、これまで海外でしか開催されていませんでしたが、日本においても2011年8月27日(土)PyCon JP 2011が開催されます。既にプログラムが公開され、参加登録が始まっていますので、Pythonもおもしろそうだなと少しでも興味をもたれた方は是非ご参加ください。

またイベントの雰囲気を掴むには、今回のPyCon JPのリハーサルとして2011年1月27日(土)に開催し、136名の来場者を迎えたPyCon mini JPのサイトに発表資料や動画が公開されているのでそちらも参考にしてください。

あとがき・謝辞

本カンファレンスは、小宮さん@tk0miyaと池さん@rokujyouhitoma)と筆者の3人で参加し、ホテルに3人一部屋で滞在しました。朝夕を問わず、筆者が分からないことを教えてもらったり、困ったときに助けてもらったり、一緒に観光したり、お二方のおかげでとても良い旅行になりました。

タイトルの「そうだ!EuroPython 2011へ行こう」というのは、筆者がSkypeのグループチャットで呼びかけたところ、⁠よし、行こう」と即決してしまったというゆるい気持ちを表しています。海外の技術イベントに参加したことがなかった筆者にとって、意思をかためる後押しとなりました。この場を借りてお二方にお礼を述べます。

また、本カンファレンスへ参加するきっかけでもあり、旅行の心得を助言してもらい、さらに本稿のレビューまで快く行って頂いた、寺田さん@terapyon⁠、たかのりさん@takanory⁠、清水川さん@shimizukawaに感謝します。みなさんのフォローがなければ、筆者は本カンファレンスへ参加せず、本稿が執筆されることもなかったかもしれません。

どんなことでも自身の経験がないことに初めて挑戦するのは不安があります。そんなときに仲間がいて、相談できる場があるのは心強いものです。自分ができることを行い、できないことを助けてもらう、筆者はそういったコミュニティの展望にとても興味があります。自分が良いと思ってやったことがどんな未来へつながるのか、筆者はそこに幸せ感があり楽しさがあります。

おすすめ記事

記事・ニュース一覧