Hatena::Groupbugrammer

蟲!虫!蟲!

Esehara Profile Site (by Heroku) / Github / bookable.jp (My Service)
過去の記事一覧はこちら

なにかあったら「えせはら あっと Gmail」まで送って頂ければ幸いです。
株式会社マリーチでは、Pythonやdjango、また自然言語処理を使ったお仕事を探しています

2013-06-25

[] DCIもどきみたいなものをPythonで実装してみる 21:51

 たまには、サービス改善はお休みして、プログラミングネタを。

 一時期、ScalaからRuby界隈で、「DCI」について議論されていた印象があります。で、自分がよく使う言語はPythonなのですが、Pythonでは、あんまりDCI的なアプローチを試験的に実装してみよう、という試みは余り見なかったように思われます。

 DCIについては、自分の下手な解説より、下のドキュメントを読んだほうが、正確な理解が得られるでしょう。

DCIアーキテクチャ - Trygve Reenskaug and James O. Coplien - Digital Romanticism

 自分の(たぶん間違っているであろう)理解によれば、何かしらの「オブジェクト」の振舞を「状況」によって、「役割」を与えることで決定しよう、というところにあると思っている。また、「そのオブジェクトが必要であるが、しかしそれがどのような役割を持ちうるかということが決定しずらいとき」にも有効なのかな、と思うけれど、その辺は詳しくないので、識者に頼みたいところ。

 また、現実的な実務としては、オブジェクトに対して「ありうるメソッド」を組み込んだり、継承で深くしたりするよりも、「役割」という単位で分割したほうが、ソースの見通しが良くなるというメリットも存在するとも考えれるようです。

 そういう感じで、自分はDCIを理解しているわけですが、今回の目的は、DCIを正確に理解することではなく、とりあえず上記の「ゆるふわな」理解を元に、ではPythonで実装するとするならば、どのようになるか、ということを考えていきたいと思います。

その前に具体的なイメージを

 比喩というのは、往々にして間違った理解を生みやすいのですが、とりあえず、今から実装されるストーリを考えます。

 目の前に二人の村人がいます。この村人は、とりあえずいることはわかっているのですが、その人たちがどんな人かはわかりません。しかし、その中の一人が風呂敷を広げて商売を始めました。彼は「商人」として振舞い始めたわけですね。もう一人が商人として振る舞ったわけですから、もう一人はお客さんとして、財布を見て、いくらくらいなら買えるのか確かめる、といった感じです。

まずベースになるclassを定義する

 そこで、最初にDCI的な機能をもつベースのclassを定義してみましょう。

# -*- coding: utf-8 -*-
import re


class MethodProvider(object):

    not_use_method = re.compile('^_')

    @classmethod
    def bind(cls, target):
        instance = cls()
        use_methods = instance._find_method()
        print use_methods
        for method in use_methods:
            setattr(
                target,
                method,
                getattr(instance, method))

    def _find_method(cls):
        return_method = []
        method_list = dir(cls)
        for method in method_list:
            if cls.not_use_method.match(method) is None:
                return_method.append(method)
        return return_method

 個人的には、かなり「黒いコード」だとは思うのですが、解説していくと、targetが「何らかのメソッド組み込みたい対象のインスタンス」であり、そしてそのクラスの属性/メソッド一覧に関しては、dir関数で取れるので、そこから、Python紳士協定であるところの先頭アンダーバープライベートメソッドをのぞき、あとは、それらをsetattrとgetattrでとにかく組み込んでいくという形になります。setattrとgetattrを使っているのは、文字列を使ってメソッドを引っ張って来れるからですね :)。

 さて、このclass継承した形で、次のような役割を与えるclassを作ってみましょう。

class Trader(MethodProvider):

    def sell(self):
        for goods in self.has_goods:
            print goods[0], goods[1]


class Visiter(MethodProvider):

    def buy(self):
        print "i have %d money." % self.has_money

 さらに、これらの役割が与えられる「人間」を定義してみましょう。

class Person(object):

    def __init__(self):
        self.has_goods = [
            (u'ひのきのぼう', u'10G'),
            (u'やくそう', u'5G')]
        self.has_money = 100

 では、実際にPersonに対してTraderの役割を与える関数も定義してみましょう。

def test():
    person = Person()
    Trader.bind(person)
    person.sell()

 これらを組み合わせたものは、gistにアップしてあるので、実際に実行してみるといいでしょう。

https://gist.github.com/esehara/5857997#file-dci_test_error-py

 しかし、これを実行してみるとエラーが起きてしまいます。

Traceback (most recent call last):
  File "test_dci_error.py", line 57, in <module>
    test()
  File "test_dci_error.py", line 54, in test
    person.sell()
  File "test_dci_error.py", line 32, in sell
    for goods in self.has_goods:
AttributeError: 'Trader' object has no attribute 'has_goods'

 これはいったいどういうことなのでしょうか。

他のインスタンスから引っ張ってきたメソッドは、引っ張ってきた元のコンテキストを保持する

 これは一つの罠(というより多分仕様なのですが)、他のインスタンスからメソッドを引っ張ってきても、selfのコンテキストは変わりません。つまり、この場合のselfはMethodProviderを参照にしているわけです。証拠に、下のように改造してみましょう。

class MethodProvider(object):
    not_use_method = re.compile('^_')
    has_goods = (
        (u'てつのけん', '500G'),
        (u'はがねのけん', '1000G'))
    @classmethod
    def bind(cls, target):
        instance = cls()
        ....

 has_goodsをMethodProviderに追加するとどうなるか。

https://gist.github.com/esehara/5857997#file-dci_badfix-py

$ python test_dci_badfix.py 
てつのけん 500G
はがねのけん 1000G

 確かに、selfがMethodProviderのほうに向いています。これはよろしくない。我々の目的は、メソッドをはやして、あたかも「Person」のメソッドのように取り扱うことです。つまり、selfの参照先はMethodProviderではなく、Personであるべきなのです。

解決

 これで、どうしたものかと考えていたら、d:id:nishiohirokazu さんがチャットで解決方法を教えてくれました(Thanks!!)。要するに下のようにするといいとのことです。

class MethodProvider(object):

    not_use_method = re.compile('^_')

    @classmethod
    def bind(cls, target):
        instance = cls()
        use_methods = instance._find_method()
        for method in use_methods:
            setattr(
                target,
                method,
                getattr(instance, method).im_func.__get__(target))

    def _find_method(cls):
        return_method = []
        not_use_method = ['bind', 'not_use_method']
        method_list = dir(cls)
        for method in method_list:
            if (not method in not_use_method and
                    cls.not_use_method.match(method) is None):
                return_method.append(method)
        return return_method

 どうやら、このim_funcという属性がポイントになるようです。どういうことか。そこで、あえてテストコードを下のように書いてみます。

# -*- coding: utf-8 -*-

class TestClass(object):

    def test(self):
        pass

    def func_print(self):
        print self.test
        print self.test.im_func

if __name__ == "__main__":
    test = TestClass()
    test.func_print()

 この結果として得られる出力が下の通りになります。

$ python im_func_test.py
<bound method TestClass.test of <__main__.TestClass object at 0x7f46af202e50>>
<function test at 0x7f46af206a28>

 つまり、self.testの場合は、それがどのクラスのメソッドとして束縛されているのか、というのを示すのに対して、im_funcを使うと、そのメソッド関数として取り出すことが可能になるっぽいです。(ちなみに、これはPython2.x系の実装らしく、Python3になると__func__になるとかならないとか)

 さて、メソッド関数として取り出せたのはわかったのですが、じゃあどうやってそれを他のクラスに埋め込むのか。そこで、使われるのが__get__メソッドのようです。上記のコードを次のように改造してみましょう。

# -*- coding: utf-8 -*-


class BoundTest(object):
    pass


class TestClass(object):

    def __init__(self):
        self.bound_test = BoundTest()
        self.bound_test.test = self.test.im_func.__get__(self.bound_test)
    def test(self):
        pass

    def func_print(self):
        print self.test
        print self.test.im_func
        print self.bound_test.test

if __name__ == "__main__":
    test = TestClass()
    test.func_print()

 そうすると、下のような出力が得られます。

$ python im_func_test.py
<bound method TestClass.test of <__main__.TestClass object at 0x7fdcd2a65e90>>
<function test at 0x7fdcd2a69b18>
<bound method ?.test of <__main__.BoundTest object at 0x7fdcd2a65f10>>

 というわけで、最終的なコードは下のようになります。

https://gist.github.com/esehara/5857997#file-dci_goodfix-py

 これを実行すると、無事、下のような出力が得られます。

$ python test_dci_goodfix.py
[Trader]
ひのきのぼう 10G
やくそう 5G

[Visitor]
i have 100 money.

 こうして、クラスとは別に、メソッドのselfの参照を、個別のインスタンスへと向け直すことが出来ました。

まとめ

 正直、このようにコードを書いてみましたが、いまいちDCIのメリットがどのようなものなのか、あるいはDCIが目指しているものとは何なのか、ということについては、まだまだ曖昧なところではありますが、このアプローチは便利だなあと思うところもある一方で、ちょっと「黒いかな?」という気持ちも拭えません。とはいえ、便利そうな雰囲気はあるので、機会があれば使ってみたいなと思うところです。

謝辞

 この方法を試している最中に、下の方々から助言を頂きました。改めてお礼を言いたいと思います。

2013-06-20

[] Pythonでシンプルにキューメッセージ管理をする方法 00:56

 自分の趣味といえば、いろんなサイトをスクレイプして、そのデータで遊ぶというのが趣味だったりします。で、単純に実装すると、だいたい1レスポンスで数秒かかったりして、非効率だったりします。例えば下のような感じですね。

# -*- coding:utf-8 -*-
from bs4 import BeautifulSoup
import urllib

def main():
    html = urllib.urlopen('http://www.hatena.ne.jp').read()
    soup = BeautifulSoup(html)
    print soup.title.text

if __name__ == '__main__':
    main()

 この場合だと、対象が一つだから、urlopenでデータを習得する時間が遅くなってもまあいいかな、と思うわけですが、しかしこれが何万件のデータを取得する段階になると、とても遅くてやってられないのも事実です。

 Pythonには、並列的に処理をする一つの方法としてthreadingという標準モジュールがあります。これらによって複数のプロセスで習得できれば、ある程度効率化できます。今ではRabbitMQなどもありますが、ここは一つ、Pythonスレッドとその管理者にわけで、簡単に状況を受け渡しできるようなものを作ると便利ではないかと。

 たぶん、いろんな方法はあるとは思われますが、自分は配列を使うのが好きだったりします。以前にも記事にしていたと思うのですが、Python配列は、使用上、参照渡しになることになります。

 といわれてもピンとこないと思うので、実際にやってみましょう。

In [1]: a = [0, 1, 2]

In [2]: b = a

In [3]: b[1] = 9

In [4]: a
Out[4]: [0, 9, 2]

 どういうことかといえば、aとbは同じ配列を使っているので、bが変更されたとするならば、同時にaも変更されてしまうわけです。

 これはたしかにまどろっこしい仕様ではあると思うのですが、しかしこの仕様は、複数のスレッドで同じ状態を共有するのに便利だったりします。なので、そういうものを簡単に書いてみます。

# -*- coding:utf-8 -*-
import threading
import time
import random


def main():
    thread_number = 3
    child_ques = [[] for i in range(thread_number)]
    sampleque = list(range(100))
    threads = generate_thread(child_ques)
    run_thread(threads)

    while len(sampleque) > 0:
        for que in child_ques:
            if len(que) == 0:
                que.append(sampleque.pop(0))
        print "[Current Que Status]"
        print child_ques
        time.sleep(1)


def do_something(que_list):
    while 1:
        if len(que_list) != 0:
            number = que_list.pop()
            print "Do Something: No.%d" % number
            time.sleep(random.randint(1, 3))
            print "End, No.%d" % number


def generate_thread(common_array):
    generated_thread = []
    for number, arr in enumerate(common_array):
        th = threading.Thread(
            target=do_something,
            args=(arr, ),
            name="thread%d" % number)
        th.setDaemon(True)
        generated_thread.append(th)
    return generated_thread


def run_thread(threads):
    for thread in threads:
        thread.start()

if __name__ == '__main__':
    main()

 ちょっと長くなってしまいましたが、Threadは、何かしらの関数スレッドとして実行する、ということを宣言することができます。そのスレッドに対して、あらかじめ使おうと思っているスレッド数分の、配列配列を渡してあげます。前にもいったように、配列は参照というか、片方が変更すれば、片方も同じところで変更されているように見えるわけです。

 これを利用することによって、メインのスレッドからキューを追加することによって、他のスレッドに対して仕事を詰むことが可能になります。

まとめ

 というわけで、RabbitMQみたいな大げさなキュー管理をする必要はないけれども、ちょっとした処理のときに、キューを使って、効率よく処理していきたいなーと思ったときに、上のような実装をするとはかどるかもしれません。いや、もっといい方法があるのかもしれませんが、もしそのときは教えてください :).

2013-06-18

[][][] Python(というわりには少なめな)で土日を使ってサービスを作るための中途半端なモダン環境構築メモ 02:45

 というわけで、土日を使ってサービスを作ってみました。

f:id:nisemono_san:20130618013959p:image

FXでの失敗ケース | Just another WordPress site

 サービスの内容としては、過去にブックマークされた本を、ユーザー毎にカラムに分けてランダムに表示するという、非常にシンプルな作りとなっています。レイアウトおよび配色は、知人である豊井さんに指定してもらいました。ありがとうございます!

 で、今回の記事は、サービスの宣伝もかねて、どういう環境で開発したか、という話をメモがてら、ブログの記事にしようと思います。

tmux, あるいはscreenの薦め

 自分は、秘伝のタレ的なものとして、tmuxの画面分割を使って、それぞれのプロセスを立ち上げて監視しています。実際に監視しているものとしては、下の通りになります。

  1. django server
  2. compassの自動生成
  3. testの結果表示
  4. その他コンソール

 で、実際に生成される画面としては、下の通りになります。

f:id:nisemono_san:20130618040139p:image

 このように、画面に情報を一括することにより、便利な感じになります。

testはwatchr.rbで一括管理

 もちろん、言語を統一したほうがはかどるのではあるんですが、自分はwatchrを使ったりしています。watchrはRubyで書かれており、ファイルの更新があるごとに、任意のコマンドを実行するという優れたものです。自分は、ファイルを保存するたびにテストを走らせることで、テスト駆動にできるだけモチベーションを保とうと思っています。

 ただ、このwatchrは、新規ファイルは、変更を見てくれないという欠点があるので、その辺に注意が必要です。

 とはいえ、変更がされるたびにテストを動したとしても、結果をいちいち見に行くのは面倒くさいので、自分はballonを表示するようにしています。その方法については、下のレポジトリが参考になるので、その辺を見ると早いでしょう。

GitHub - hirocaster/phpunit-stack: 車窓からの TDD

蛇足: Pythonのwatchdogについて

 twitterで「watchdogについてはどうなの」というご指摘を頂きました(Thanks!!)。

 で、過去にちょっとwatchdogを使ってみたのですが、少し癖があるところが多いのが欠点なのかなーと思ったりします。具体的には、下のissueを見て頂ければわかりやすいかもしれません。

 恐らくファイル管理で発火するイベントを取得しているのですが、mac osでVimを使うと習得できないとか、その辺が割とだるかった記憶があったり、あるいはVimでファイルを更新すると、createdとmodifedが同時に発火するとかよくわからないことが起きたりとかして、ちょっと避けていたというのも大きかったです。

 このあたりについては上手く使える方法があるのならば、是非こちらのほうを採用したい、という気持ちはあります。なぜならPythonで書かれていますからね! :)

上記の解決について

……と思ったら、解決を教えてくれた人が!(thanks by @kashew_nuts )

どうやらこんな感じらしい。

djangoのテンプレート引数は便利だ

Pythonの情報が少ないよバカ、もっと真面目にやれ」(意訳)というご指摘を頂きました(Thanks!!)

自分はdjangoを使っているのですが、各人に、djangoスケルトン的な、秘伝のタレがあると思います。(例えば、どんなライブラリを普段使っているのか、とか)。そのタレを使って初期状態でプロジェクトをスムーズにするのに、startprojectのオプションとして--templateを渡してあげると超便利です。

例えば、django1.4であるならば、下のようなスケルトンが作られています。

このあたりを使うと、いちいち面倒くさい設定をしなくても、過去のスケルトンで作った設定を使いまわしできるので、とても便利です :)。こういう風にタレを作っておくのも、土日に気軽にサービスを作るときに、効率的になります。

バッチ処理するならdjangoにカスタムコマンドを追加するとはかどるぞ

 ここは常識の範囲かと思われるのですが、バッチ処理に関しては、個別にPythonスクリプトを書くよりも、djangoのmanage.pyにコマンドを追加したほうがはるかに便利です。特にModelなんかでやりとりをする場合は、コマンドを発行して、その上で実行するというのがベターな気がしています。実際に、自分ははてなブックマークを習得するさいに、個別にコマンドを切って、それを実行することによって対応していました。

compassは使え、絶対だ

 実は、このサービス、割とNexusやipadなどの「タブレット」からも、ちゃんとレイアウトしてくれます。場合によっては、タブレットの方が使いやすいかもしれません。これは、compass + susyという組み合わせによって実現されています。

 自分は、sassではなく、scssというのを使っていました。sassはほぼyamlなんですが、scssのほうがcssと近い感じで書けるので、最初から結構書きやすいです。

 まず一つに変数が使えるということ、またmix-inという関数っぽいものが使えること、またネストして構造化できるという、既存のcssではどうしても足りなかった部分を補完してくれます。また、compassは、border-radiusなどの、指定が面倒くさいものに対しても、一括してやってくれます。

 さらにsusyは、それにプラスとしてグリットデザイン、それにレスポンシブな機能を追加してくれるという、至れり尽くせりなので、覚えておいて損はなく、逆に言うならば、普通のCSSなんて書いてらんないよー!と思ったりする部分が出てくるのは避けられないなーと。

サーバーの設定、デプロイfabricを使う

 最近だと、サーバーの環境構築も出来るだけ自動化しようというわけで、例えばChefだったり、Pappetだったりなどのオープンソースが出てきていますが、この両者はよく指摘される通り、学習コストが余りにも高くなってしまうという欠点があります。で、比較的学習コストは低くても力を発揮してくれるものの一つにfabricがあります。そして、このfabricをもっと使いやすくしたものにfabtoolsというものが存在しています。

fabricのいいところは、単に「ssh先で動かしてくれるシェルスクリプト」を構築できるという点にあるでしょう。なので、必要なパッケージであったり、あるいはライブラリをまとめておくことで、構築漏れを防ぐことができます。

デプロイには、.git hookにpost-commitを追加しておくと便利だぞ

 恐らく、gitを使う場合は、何らかのGUIソフトを使う場合か、コンソール画面からいじるかのどちらかだと思うのですが、今回は、post-commitにスクリプトを書いて引っ掛けておきました。その内容は下の通りです。

  1. コミットが走ったら、テストを実行する
  2. テストが成功したら、そのままレポジトリに反映させる
  3. レポジトリに反映させたら、fabricで本番環境に反映させる
  4. Supervisorなど、レポジトリの内容をちゃんと送信できるようにする

 そういう感じでコマンドを書いていると、commitするたびに反映が走るのが面倒くさくなる部分もあるのですが、ただリアルタイムに更新している感覚は出てくるので、そのあたりはデメリットとメリットを比較する必要がありそうです。

蛇足

 サーバー本番環境で、git pullで反映させるのもいいんですけど、ただそれだけだとサーバーに入ってちょっと検証のためにコードを足した場合、余計なコンフリクトが起きてどうしようもないということもあると思うので、git reset --hardとか、その辺を使ってサーバー本番環境のソースは潰してます(もちろん、本番を直接いじるのはよくないですし、それが正論です)。サーバーにあるのは、レポジトリの内容にあるものである必要があるので、むしろ余計な衝突を避けるためにはいいのかなと。

さらなる蛇足

 例えば、継続的デリバリーに関しては、Jenkinsでビルド・パイプラインを作るという手もあるのですが、どちらかというと、これは共同開発の部分において重要になってくるところではあって、一人でやっていて、かつ常にテストをぶんなげていると、その辺の利点が実は薄いのかな、という気はしたので、上記のアプローチになっています。もちろん、何かしらの共同開発の環境では、Jenkinsは便利だし導入するべきだと思います。

Supervisor + gunicorn + nginxで作成

 基本的にフロントに立っているのは軽量なもので足っているのでいいだろう、というのが一つと、どうせgunicornと連携するんだったら、連携しやすいものがいいだろう、ということでこういう構成になっていたりする。で、Supervisorは、daemontoolsの強力版と考えると正しい。例えば、死んだプロセスを自動的に立ち上げたりなどの管理を一括してやってくれるので便利だ。gunicornは、Rubyunicornみたいなもので、とにかく早いのが特徴(?)と言うべきだろうか。

 さらには、Supervisorのコマンドツール(Supervisorctl)を使うことによって、持ってきたソースを反映させるということが非常に楽になるというところも利点だろう。

Vim限定

Vimのプラグインであるsyntasticは超絶便利なので導入するといいかと。とりあえず、pip8標準であったり、あるいは静的解析(pyflakes)を使うならば、入れておいて損はないでしょう。もちろん、単独のpep8というコマンドや、pyflakesを入れて定期的にぶんなげるのもいいでしょう。

まとめ

今回は、とりあえず「今のところこういう環境で作っています」ということを解説してみましたが如何でしょうか。次回は、個別の情報に関して共有することで、実際にはどういう風なプロセスで書いたのか、あるいはどういう風に企画をFixされたのかなどを考えたいと思っています。

あともうちょっとだけ続くんじゃよ……

takano32takano322013/06/18 05:38pyflakes のかわりに vim-flake8 を使っているなぁ。

2013-05-24

[]変数に代入せず、関数でandやorで判定しているときに気をつけたいこと 20:01

 ちょっとしたメモとして。

 例えば、メソッドを呼び出すことで、そのクラス自体が副作用を引き起こし(=つまり、何らかの値やデータが変化する)、かつそのメソッドが成功したかどうかを真偽値で返すような、メソッドを持つクラスを考えてみる。例えば次のようなクラスだ。

class Foobar(object):

    def __init__(self, numbers):
        self.numbers = numbers

    def has_odd(self):
        odds = []
        has_odd = False
        for number in self.numbers:
            if number % 2 == 1:
                odds.append(number)
                has_odd = True
        self.odds = odds
        return has_odd

 たとえば、このクラスを下のような形で実行したとする。

foo = Foobar([1, 3, 5, 9])
bar = Foobar([2, 4])
foobar = Foobar([1, 2, 4])

if foo.has_odd() and bar.has_odd() and foobar.has_odd():
    print "ALL ODD"
if foo.has_odd() or bar.has_odd() or foobar.has_odd():
    print "SOME ODD"

 この場合、どちらにしろ"foobar"のほうの、has_oddは実行されない。実際に、foo.oddsと、bar.oddsは作られているが、foobar.oddsは作られていない。

どうして?

 単純に、"and"の場合は「一つでもFalseがあるならば、その先は見ない」で、"or"は「一つでもTrueがあるならば、その先は見ない」ということになる。

 "and"は「AとBのどちらもがTrueの場合はTrueになる」と言われるが、また「AとBのどちらかがFalseの場合、Falseである」と言い換えることができる。このように言い換えた場合、Aが既にFalseの場合は、既にFalseが見つかっているので、BがTrueだろうが、Falseだろうが、関係なく、その全体の評価式はFalseになる。

 "or"も同様に「AとBのどちらかがTrueの場合はTrueになる」なわけだが、Aが既にTrueの場合は、Bが同様にFalseだろうがなんだろうが、式全体はTrueになる。

 なので、リソース制約のために、参照しないことが多い。

例えば?

 実際に、あるメソッドが実行されることを前提とした実装というのはある。Pythonであるならば、有名なフレームワークであるdjangoのformがそれにあたる。formは、is_validという、入力されたフォームの値が全部正しいかどうかをチェックするためのメソッドがある。そして、これらが全て「正しくチェックされたとき」だけ、cleaned_dataが出来たりする。また、値が間違っている場合は、そのフォームに合わせてエラーを自分の中に持つことができる。

def sample_view(request):
    form = FormHogehoge(request.POST)
    if form.is_valid():
        print form.cleaned_data['foobar']
        return render(
            request,
            'sample_template.html',
            {'message': 'Yappy!!'})
    else:
        return render(
            request,
            'failed_template.html',
            {'message': 'Boo!!'})

 この実装のメリットは、そのフォームの値が正しいかどうかを調べる前に、フォームの値にアクセスすることを禁止することが出来る。つまり、フォームの値のチェック忘れを未然に防ぐことが出来るのだけれども、一方で、下のような書き方をついついしてしまう。

def bad_view(request):

    form_foo = FromFoo(request.POST, prefix="foo")
    form_bar = FromBar(request.POST, prefix="bar")

    if form_foo.is_valid() and form_bar.is_valid():
        return render(
            request,
            'sample_templete.html',
            {'message', 'Yappy!!'})
    else:
        return render(
            request,
            'failed_template.html',
            {'message', 'Boo!!'})

 例えば、form_foo, form_barという両方のフォームの値が間違っている場合、form_foo.is_valid()だけが実行されることになる。これで問題がないようにも思えるのだけれど、上記で触れた通り、djangoのフォームに関しては、is_valid()によって、フォームの値が間違っているかのエラーメッセージを、フォームの中にもつことができる。form_barのis_valid()は実行されていないのだから、当然のことながら、フォームの値もチェックされておらず、間違っている場合のエラーメッセージも持たない。

まとめ

 で、まとめとして、メソッド関数のまま、andやorを使う場合には、下のことについて気をつけなければならない。

 ということに注意しないといけない。もし、上記に当てはまる場合は、真偽値を一度変数に代入して持っておき、あとでそれをandやorによって比較したほうが安全だと思う。

2013-05-11

[][]Pythonの条件演算子の順番について、ちょっと思うこと 00:00

 こないだ、Python使いの人との飲み会をする機会がたまたまありまして、知人の誘いを受けて出席しました。そこでPythonの条件演算子について、ちょっと話題になったので、自分の私見をメモしておきます。

 Pythonの条件演算子は、一般的には「三項演算子」の代わりに使うことが多いと思いますが、この条件演算子、順番が特殊です。どういう風に書くかといえば、下のように書かれます。

true_case = "This is True."
false_case = "This is False."

print true_case if True else false_case
print false_case if False else false_case

 簡単に言ってしまえば、何かしらの変数や値のあとにif-elseの構文を付け加えることで、もし何らかの式が偽である場合は、後ろの値を使う、みたいに使えます。

 で、この条件演算子なんですけれども、普通の言語だったら、下のように書けたりする。例えば、PHPだったりしたら、次のように書けますね。

<?php

$true_case = "This is True.\n";
$false_case = "This is False.\n";

echo true ? $true_case : $false_case;
echo false ? $true_case : $false_case;

 つまり、まず最初に判定式かBooleanがきて、そのあとにどちらの値を返すか、といったように書かせる言語のほうが多いように感じます(Java, JavaScriptもそうだったような)。で、この条件演算子の順番が気持ち悪いという話になりまして、実は自分も最初は思っていたんですけど、この順序にもメリットがあるな、と。

 どういうことかというと、基本的に何かしらの変数を読み返すときって、「どんな値がその変数に入るのか、あるいはどういう値がその変数に入ってくるのか」ということだと思うんですが、そういった場合に、先に式があるよりも、値が近いほうがわかりやすいのではないかと。例えばこういうの。

#最初に「どんな値が代入されそうなのかがわかりやすい」
hogehoge_foorbar_check = True
output_str = "Good" if hogehoge_foobar_check else "Bad"

print output_str
<?php
$hogehoge_foobar_check = True;
$output_str = hogehoge_foobar_check ? "Good" : "Bad";

 PythonPHPを比較した場合、Pythonは、どうもoutput_strには文字列が入りそうだぞ、というのが、とりあえず後ろのif文を無視してもわかるのですが、一方でPHPの場合だと、まず「?」があって、式の評価が入るわけではなく、その後ろの文字列が代入される、そしてそのあとにどういう値が入りそうなのかわかる、というのは、それこそほんの少しだけど、ちょっと一行に対する労力がちょっとだけ違いますね(そんなことを気にしてなんになるんだという話ではありますが)。

 そういうわけで、個人的には、Pythonのこの条件演算子の順番が好きだったりするのですけど、結局のところは慣れの問題だよなあ、みたいなことを昨日話したりしていました。