引き続き、「作ればわかる! Google App Engine for Java プログラミング」本にてPythonを修行中。
次は、クラウド俳句部を作ってみた時に悩んだところのメモ。
今回はクラスまわりをよく学んだ気がする。
Google App Engine 1.7.1が8/21に出たので、そのバージョンでも動作を確認。
■環境
- Windows7 x64
- Google App Engine SDK for Python 1.7.1 - 2012-08-21
■悩んだところと参考ページ
1.GAE/PでXMPPを使うためには
app.yamlに以下を追加すれば良い。
inbound_services:
- xmpp_message
なお、Pythonの場合、管理者権限の制限は不要の模様。(テキストのJava版では自分で制限をしていた)
受信メッセージを処理するには、この URL パスで POST 要求を受け入れる要求ハンドラを作成します。
この URL パスは、自動的にアプリケーションの管理者に制限されます。XMPP サービスは、この URL パスにアクセスするため、「管理者」の状態でアプリケーションに接続します。この制限を明示的に指定してパスを設定することもできますが、その必要はありません。この URL パスには、Google アカウントを使用して管理者として認証された XMPP サービスおよびクライアントのみがアクセスできます。
Google Developers - Google App Engine - XMPP Python API 概要 - インスタント メッセージの受信
2.開発環境に日本語を使った俳句が出ない
デプロイすれば出るようになる。
3.XMPPの宛先について
- message.sender:自分のアドレス
- message.to:Botのアドレス
逆にして設定したところ、リソースを食い尽くしてしまい、翌日まで待つことに。
BotがBot自身に送信し、それに反応してまたBotが・・・となってしまった。
5.C#の public int Hoge{ get; set; } みたいなプロパティはどのように実装するか
テキストでは makeHaikuメソッドをそれぞれの子クラスで実装していたものの、ほぼ同じ処理であったため、
のような方向で作ろうと考えた。
C#のようなプロパティは、Pythonでもプロパティを使えば良さそう。
ただ、実装を見ると、いわゆるコンストラクタ(__init__)にて実装しているため、そのまま子クラスで利用できるのか分からなかった。
そこで、「__init__」を子クラスで記述せずに問題ないかを以下のコードで確認。
class Bot(object): def __init__(self): self._firstWords = ['a1', 'a2'] @property def firstWords(self): return self._firstWords @firstWords.setter def firstWords(self, values): self._firstWords = values class EriBot(Bot): # これでプロパティを書き換えることができているのか?ログ出力を作成し、確認する def __init__(self): import logging logging.info(self.firstWords[0]) Bot.__init__(self) logging.info(self.firstWords[0]) self.firstWords = ['f1','f2','f3','f4','f5'] logging.info(self.firstWords[0])
すると、初回の「logging.info(self.firstWords[0])」でエラーが発生。
そこで、親クラスのコンストラクタを呼んだ後に、プロパティを使用することとした。
ログの書き方の参考:Google Developers - Google App Engine アプリケーションのイベントのログ
6.super()を使ったら「must be type, not classobj super」エラー
古い書き方をしていて、親クラスが object 継承をしていなかったため。
誤) class Bot():
正) class Bot(object):
参考:stackoverflow - python super() raises TypeError ! Why?
■フォルダ構成
__init__.py
app.yaml
bots.py
index.py
■ソース
GitHubには、chap3として追加。
app.yaml
application: <your application id> version: 1 runtime: python27 api_version: 1 threadsafe: true inbound_services: - xmpp_message handlers: - url: /.* script: index.app
index.py
# -*- coding: utf-8 -*- from google.appengine.api import xmpp import webapp2 from google.appengine.ext.webapp.util import run_wsgi_app import bots class XMPPHandler(webapp2.RequestHandler): def post(self): message = xmpp.Message(self.request.POST) fromMe = message.sender toBot = message.to bot = bots.Bot.get_bot(toBot.split('@')[0]) haiku = bot.make_haiku() xmpp.send_message(fromMe, haiku) app = webapp2.WSGIApplication([('/_ah/xmpp/message/chat/', XMPPHandler)], debug=True)
bots.py
# -*- coding: utf-8 -*- #class Bot(): class Bot(object): def __init__(self): self._firstWords = [] self._middleWords = [] self._lastWords = [] self._author = '' @property def firstWords(self): return self._firstWords @firstWords.setter def firstWords(self, values): self._firstWords = values @property def middleWords(self): return self._middleWords @middleWords.setter def middleWords(self, values): self._middleWords = values @property def lastWords(self): return self._lastWords @lastWords.setter def lastWords(self, values): self._lastWords = values @property def author(self): return self._author @author.setter def author(self, values): self._author = values @classmethod def get_bot(cls, botName): bots = {'eri': EriBot(), 'soun': SounBot(), 'o2': O2Bot()} return bots[botName] def make_haiku(self): haiku = self.choice(self.firstWords) + u' ' + self.choice(self.middleWords) + u' ' + self.choice(self.lastWords) + u' ' + self.author return haiku def choice(self, words): import random randomIndex = random.randint(0, len(words) - 1) return words[randomIndex] class EriBot(Bot): def __init__(self): super(Bot, self).__init__() self.firstWords = [u'淡雪や', u'向日葵や', u'名月や', u'クリスマス', u'初夢や'] self.middleWords = [u'あなたのそばで', u'なじみのカフェで', u'ブランコに乗り', u'10年後にも', u'映画のように'] self.lastWords = [u'見つめたい', u'手に取りたい', u'歌いたい', u'送りたい', u'眠りたい'] self.author = '(Eri Bot)' class SounBot(Bot): def __init__(self): super(Bot, self).__init__() self.firstWords = [u'簡単に', u'楽しげに', u'悲しげに', u'おおまかに', u'盛大に'] self.middleWords = [u'旅先決める', u'小物を買うや', u'家路につきし', u'予定を立てる', u'友を祝いし'] self.lastWords = [u'蜃気楼', u'五月晴れ', u'秋の空', u'除夜の鐘', u'年賀状'] self.author = '(Soun Bot)' class O2Bot(Bot): def __init__(self): super(Bot, self).__init__() self.firstWords = [u'気モ早ク', u'待チ切レズ', u'腹ガヘリ', u'俳句部デ', u'機械ナノニ'] self.middleWords = [u'甘酒飲ミシ', u'ソウメン流シ', u'オ芋恋シヤ', u'鍋ヲツツキシ', u'豪華ナオセチダ'] self.lastWords = [u'すかいつりー', u'名古屋城', u'西浦和', u'瀬戸内海', u'普賢岳'] self.author = '(O2 Bot)'