GAE pythonのwebapp.RequestHandlerクラスのget()に使う引数を探る
Google App Engine for PythonでTwitter bot作りたいなーといつしか言っていたのを思い出したので、最近取り組んでます。
GAEもしばらく触ってなかったので、こういった連載を見ながら、コードを読んでみてたり。
ASCII.jp:サンプルコードで分かるGAE&Twitter API開発|Twitter&Google App Engineで始めるWebプログラミング入門
読んでみると初めて見たコードがありました。
このサンプルでは、用意してあるURLの各処理をある程度一つのクラスにまとめて処理するそうで、指定したURLの末尾にある単語などを検出して処理しているとか。例えばこれです。
class MainHandler(webapp.RequestHandler): #----------------------------------------------------------- #Get(URLパラメータ)情報の処理 #----------------------------------------------------------- def get(self, mode=""): #TwitterClient、Cookiesクラスの作成 (client, cookie) = CreateClientAndCookie(self) #Twitterの認証画面表示 if mode == "login": #Twitterの認証画面へリダイレクトする return self.redirect(client.get_authorization_url())
はて、get()に値が入ってるけど、そんな定義されていたの?? とどうも納得出来ず。
説明では、末尾のワードごとに判断しているということで、そこのmodeにはloginとかlogoutとか入るわけです。指定すれば何でもmodeで使えるってことかな?
(下のWSGIApplicationでの、URLの指定では正規表現を使ってるようですし)
実際のコードを眺めてみた
そこで、Googleのリファレンスを見てみるものの、なんだか簡素な説明が書いてあるだけ。
RequestHandler クラス - Google App Engine - Google Code
もちろん納得が行かなくて、それなら実際の動きはどうなのかコードを眺めてみることに。
継承元のwebappモジュールはWindowsの64bitなら
にありますね。その中の__init__にRequestHandlerとかWSGIApplicationがあります。
RequestHandlerの本体を見てみると、get(self, *args)ですので、self以外の引数は複数対応している模様。
定義なので、実際に中身を実行されるだろうWSGIApplicationを見てみます。この辺からずいぶん難解になってきた・・・(RequestHandlerでもget_url()メソッドなるものがありますがスルーしています)
WSGIApplicationクラスを見ると、まず__init__()で _init_url_mappings(url_mapping) が呼ばれています。url_mappingは正規表現のURL指定と、設定したハンドラクラス(MainHandlerとか)がタプルで入っています
def __init__(self, url_mapping, debug=False): """Initializes this application with the given URL mapping. Args: url_mapping: list of (URI regular expression, RequestHandler) pairs (e.g., [('/', ReqHan)]) debug: if true, we send Python stack traces to the browser on errors """ self._init_url_mappings(url_mapping) self.__debug = debug WSGIApplication.active_instance = self self.current_request_args = ()
(ここから解説があやふやですが、なんとなく理解程度なのでご了承を・・・)
_init_url_mappingsはプライベートメソッドってやつですね。URLのマッピング処理をしているようです。
で、この後に呼ばれるのが__call__なのかな? ここで引数の正体が隠されているっぽいです。次の処理でhandler.get()に渡しているのもあるので。
def __call__(self, environ, start_response): """Called by WSGI when a request comes in.""" request = self.REQUEST_CLASS(environ) response = self.RESPONSE_CLASS() WSGIApplication.active_instance = self handler = None groups = () for regexp, handler_class in self._url_mapping: match = regexp.match(request.path) if match: handler = handler_class() handler.initialize(request, response) groups = match.groups() break self.current_request_args = groups if handler: try: method = environ['REQUEST_METHOD'] if method == 'GET': handler.get(*groups)
groupsがそれらしいです。正規表現をかけてマッチものをタプルかしているらしい(なぜタプルなのかが分からない、brakeしている時点でひとつしか入らないように思うけど?)
正規表現の処理の後に、handlerの処理をしていますね。そこでも*groupsを引数にしているようですし、これかなーと思います。
なんとなくですが正体がわかったかなと。
最後に
挙動も確認できたことなので、コード読みに戻ります。
GAEのモジュールのコードを載せていますが、Apache Licenseらしいので、改変しない限り大丈夫と認識しています。
何か間違い等ありましたら教えてください。お願いします!