GAE pythonのwebapp.RequestHandlerクラスのget()に使う引数を探る

Google App Engine for PythonTwitter 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らしいので、改変しない限り大丈夫と認識しています。
何か間違い等ありましたら教えてください。お願いします!