PythonのWebフレームワークについて

寺田学氏(以下、寺田):それでは「Python Webフレームワーク比較」ということで、45分間のトークをしていきたいと思います。

資料は基本的に英語ですが、大事なところは日本語で書いています。もともと英語で発表したいという想いがあったんですけど、日本語で伝えたほうがいいなと思ったので、今日は日本語です。

私は寺田学といいます。CMSコミュニケーションズという会社を経営しています。PyCon JPではBoard Chairということで、2013年の設立当時から代表理事をやっています。他にも、スポンサーになっているPython EDの理事や、Plone Foundationのアンバサダー、PSFのコントリビュートメンバーなど、会社をやりながらいろいろなコミュニティ活動をしています。

CMSコミュニケーションズは、Plone、PythonやWebにずっと関わっている会社です。2005年に立ち上げたので、もう約15年間ですね。Pythonは2.3ぐらいから使っていて、ようやく3に移行しました。Webとはずっと縁が深くて、仕事としてずっとやってきています。私たちは、Pythonを中心にWebに関する技術という感じでやっています。

一般社団法人PyCon JPという法人がこのイベントをやっているというより、実はイベントをやるための法人格があるんですね。イベント自体は、イベントチームがあって、吉田座長のもと、約50名のスタッフで支えているわけですが、それには法人格というものがあって、契約やお金の管理や、その他のPythonを広めるためのいろいろな活動を私たちがやっております。

ということで、今日の内容を紹介します。

まず「Webフレームワークとは? Webフレームワークをどう定義する?」。定義をしないと今日の話が分散してしまうと思うので、まずはフレームワークの定義をします。

そのあと、Webフレームワークの機能一覧を紹介します。一覧なので淡々としてしまいますが、Webフレームワークを選択するためには、どんな機能があるか、なんのための機能なのかを理解しておかないと大変だと思うので、我慢して聞いてください。

そのあとは、実際のWebフレームワークをいくつか紹介します。最後に、プロジェクトでフレームワークをどう選んだらいいかという、私なりの指標をご提示して、Q&Aに入っていきたいと思います。

Webフレームワークの歴史

まずは、Webフレームワークの歴史的な話をします。今回紹介するWebフレームワークは、私が恣意的に選んだ9個です。Django、Flask、Pyramid、Zope、Tornado、aiohttp、Guillotina、Bottle、responder。

この中で1つ以上知っている人は手を挙げてください。

(会場挙手)

ほとんど全員ですね。ありがとうございます。3つ以上知っている人はどのくらいいますか?

(会場挙手)

半分ちょっとですね。この会場で60パーセントぐらいの方が、3つ以上知っている。じゃあ、全部知っているという人。

……これは、これまでやった中でも全部知っている人はなかなか現れないですね。全部使ったことのある人なんて、もっといないですよね。

私は、実験は全部したことがあります。仕事で使っていないものも何個かありますし、比較するためにあえて入れたものもあります。これらの歴史について話していきます。

(スライドを指して)一番左側に、Zopeというものがあります。この年表は2005年からですが、実はZopeは2000年より前からあって、なかなか歴史が調べられません。

Pythonを作ったグイド(・ヴァンロッサム)さんは、Zopeコーポレーションの社員だったんです。PythonはZopeと一緒に伸びてきたところがあって、Zopeというと「Python……懐かしいですね」なんて言われることがあります。

そのあと、PythonではなくRubyでになりますが、Ruby on Railsのような軽量フレームワークが入ってきました。そんな時代、2006~2008年ぐらいに、PythonでもDjango、Flaskのようなフレームワークが登場して、実際に使われるようになってきています。

Pyramidは、前身のPylonsや、TurboGearsの血を引いていることもあって、少しあと(2011年頃)です。Tornadoもすでにこのへん(2010年頃)にはあったし、Bottleもこのへん(2009年頃)にはすでにあったはずです。aiohttpも案外早い(2013年頃)んですよね。それから、最近出たGuillotinaとかresponder。今日紹介するのはこの9つです。一応この9個を歴史的に並べてみました。

Webフレームワークをどう定義する?

次に「Webフレームワークとは? Webフレームワークをどう定義する?」。これは難しいですよね。フレームワークという言葉はいろいろなところで使われますけれど、Webフレームワークとはなんなのかという定義をしないと、けっこう難しいと思うんですね。

じゃあなにか? 当たり前ですが、Webアプリケーションフレームワークです。当たり前のことを言っている。ブラウザにHTMLやJSONみたいなものを配信するためのもの。これがないとWebフレームワークやWebの世界としてはちょっとおかしいですよね。

それから、これも当たり前ですが、HTTPプロトコルや、GETやPOST、200番とか、404 NOT FOUNDとかを返すためのステータスコードをサポートしていること。Webの世界ではそういうことをやるわけですから、Pure Pythonで自分で全部書いてもWebの世界は作れますけれど、こういうものは最低限持っていないといけない。

もうちょっというと、/〇〇みたいな、URLというものがWebフレームワークに飛んでくるわけですよね。そこに沿ったコンテンツを見つけ出すために、ルーティングという機能や、トラバーサルという機能がある。コンテンツを見つけ出す機能を自分で書こうとすると大変です。

先ほどの繰り返しになりますが、だいたいのフレームワークは、POSTやGETを扱えるほか、HTMLテンプレートの「こういうものを使ったらいいよ」というおすすめがだいたい内蔵されています。

あとはデータベースの接続。データベースを使わないWebの世界ももちろんあり得るんですが、多くの場合はデータベースも接続したいと思います。セッションやCookieの扱いは、ミスがあったらセキュリティの問題になってしまうので、自分で書くよりフレームワークにお任せしたいわけです。

Webフレームワークの重要な機能

Webフレームワークの重要な機能を紹介していきます。HTMLテンプレート、URLディスパッチャ、リクエスト管理、Cookieの管理、ログイン機能、ユーザ管理、Persistent layerは永続化ということで、データベースとか、なにかデータをとっておくというかたちです。それからWebサーバの機能、コマンドをどうやって起動するのか、それはデーモン管理をするのか。REST APIにどうやって対応していくのか。ハンドリングのローカルデータはちょっと難しいんですが、セッションデータなどをどこかに溜めてリクエストごとに管理をしていくわけです。

リクエストごとに「この人のリクエストはこのブラウザから来たこの人のリクエスト」と、別の人のリクエストとは別々に管理をしていかないといけないので、それをどうやって管理するか。最近はPythonにも非同期の仕組みが標準で入ってきたので、Asyncサーバみたいなことも広く盛んに言われています。

最後、セットアップのconfファイル。confファイルで環境変数などをどう管理しているかは、フレームワークによって違います。そのへんは、のちほどもう少し深く話します。

テンプレート機能の説明です。テンプレート機能としては、動的なHTMLを作る機能、部分的なテンプレート群をつなげられる機能、テンプレートの継承、フィルター機能や小さなファンクションの実行、全部Pythonコードでやってテンプレートでコードを書けたりとか、ulタグ・liタグの繰り返し機能とかはだいたいテンプレートの中でやるので、そういう分岐の機能などがあります。

次に、テンプレートの主な種類です。Pythonのテンプレートの種類はたくさんあるので、ここでは4つだけ紹介しています。Django Template Engineは、Djangoの標準で入っているテンプレートです。jinja2は、かなり有名ですよね。それから、超高速で、Pythonも中に書けちゃうmako。Chameleonや Zope Page Templateといった伝統的で歴史的なXML系のテンプレート。実際にはまだまだ他にもありますが、これらがよく比較されるテンプレートです。

次はURLディスパッチャ。URLをどう見つけるかというと、URLを分析してルーティングしたり、トラバーシングしたりします。これは関数との結び付けだったりクラスのメソッドとの結び付けだったり、たいていはそうなっていることが多いです。

どうやってURLを見つけ出すかという話で、オブジェクトトラバースについて。Zopeは歴史的にオブジェクトトラバースという仕組みを使っていて、ルーティングと言ってしまうと少しおかしい感じがします。そういうものもあります。

リクエストオブジェクトや永続化について

リクエストオブジェクトについて。ブラウザからアクセスが来たときにレスポンスを返すわけですが、リクエストが来たときの情報はすごく重要な情報がたくさん詰まっています。URLや、Cookie、POSTの情報などをリクエストのオブジェクトといいます。当然、多くのフレームワークでサポートされている機能ですが、それぞれアプローチが少しずつ違います。引数を使っていたり、ローカルスレッドなグローバル変数で扱ったり、それぞれ特徴があります。

Cookieの管理。自分で管理するのは危ないので、Cookieの管理機能もだいたいのフレームワークには入っています。リクエストオブジェクトから取得したり、レスポンスオブジェクトから操作したりします。

ログイン機能。Webフレームワークを使ってなにかサイトを作るとき、だいたいログインを作りたくなるんですね。標準でサポートしているフレームワークもあれば、サポートされていなくて自分で作ったり、サンプルがあったりアドオンがあったり、いろいろです。

ユーザ管理。ログインの機能があれば、当然ユーザを管理する機能が必要です。これも、最初から入っているものと、ユーザ管理は自分で作ってログインの場合はデコレータで管理するというものもあります。アドオンで提供しているケースもけっこうあると思います。

永続化。データベースになにかを保存したり、データベースからデータを持ってくるというアプローチが、絶対に必要になってきます。Djangoは、専用のRDBMSとつなぐ仕組みがあります。他のフレームワークだと、SQLAlchemyを使ったり、今だとKVSとか違うデータソースから持ってきたり、ObjectDBみたいなものが内蔵されているObjectDBと一緒につないだりします。

こういうふうにつなごうとすると、次はデータの管理をしたくなりますね。どうやってデータを見るか。SQL文を打ってください、あとは全部自分で作ってくださいというタイプと、フレームワークで管理できるタイプがあります。

WebサーバやREST APIについて

Webサーバ。これがないと、当然いろんなものがホストされない。データのレスポンスが返せないわけです。ご存知だと思いますが、PythonではWSGIという規格があって、このWSGIに沿っているケースが多いです。最近だとAsyncのASGI、これはPEPでどこかで規格が決まっているわけではないらしいですが、ASGIをサポートしているサーバも出始めています。

また、自分でオリジナルのWebサーバを持っているケースもあります。例えばDjangoはWSGIに対応していますが、8080とか5000番とかのポートを開けてレスポンスを返すサーバという意味ではGunicornとかuWSGIとセットでDjangoやFlaskやPyramidが使われている。あと、Pyramid系で使われているWaitressもWSGI Serverです。

機能を作るDjangoのフレームワークとサーバ部分は、多くの場合は分離されているわけです。もちろん、オリジナルの場合はオリジナルのサーバを使う、またはWSGIに対応しています。ASGIのサーバもあるそうです。Asyncは私自身あまりやっていないので詳しくはありませんが、そういうものもあります。

runサーバをどうやって起動するのか。さっき話したようにWSGIに対応していたらWSGI Serverの起動方法の話になるので、Djangoの起動方法ということではないわけです。DjangoとWSGI(サーバ)、DjangoとGunicornを組み合わせて機能させるというような仕組みになるのですが、そうやってデーモン管理をしなくてもいい。逆に、オリジナルの場合だとデーモン管理の方法を考えなければいけない。そんなことになります。

(REST APIについて)最近のWebの世界は、どんどんフロントエンドを作らなくなって、フロントエンドはiPhoneアプリやAndroidアプリです。となるとAPIサーバ、それもRESTfulなAPIサーバの提供がサーバサイドの仕事ということも多くなっている。

そうすると、REST APIをどうやって対応していくかという問題があります。フレームワークによって、サポートしていたり、アドオンで提供していたり、サポートされていなくて、APIサーバを作るために自分たちで書かないといけないこともあります。

非同期、Async。今はすごくAsyncが増えています。さっきも言った通り、アプリ側になればアプリからのアクセスがものすごく多くなるかもしれなくて、そうするとテンプレートを返さないでAPIしか返さないのでAsyncでやりたいという場合がある。今、PythonではAsyncサーバが作りやすいので、フレームワークによってはAsyncをサポートしています。

次にセットアップ。ほとんどのフレームワークがpipを使っています。pipだけではなくbuildoutを使わないとセットアップしにくいものもありますが、その中でもpipを使っているケースや、昔ながらのオリジナルの方法でやるケースもあります。

環境設定も、iniファイル形式や、Pythonのコードで.pyで書かなければいけなかったり、ymlで書けたり、いろんなタイプのコンフィグがあります。Pythonのコードで書くと、Pythonコードなのでいいんですけど、誰かが環境変数を変えたらSyntaxエラーを起こしてしまうようなこともあります。それはそれで仕方ないかもしれませんが。なので、ymlを使ったほうがセットアップするときに書きやすいとか、iniファイル形式がいいなどとも言われています。

お疲れ様でした。今のところで大きな項目がだいたい終わったんですが、ここからが本番です。