.. title:: Pythonで心理実験 - 例題1-1 例題1-1:とりあえず5秒待つ ============================== **A:** さて、今回の例題は5秒待つわけだが。唐突だが、B君は「5秒待て」って言われたらどうするかね。いや、5秒だと忙しいから5分にしとこうか。「資料室で5分待っとれ」と言われたらどうする? **B:** えーと。適当に本を読むかネットで時間をつぶします。 **A:** いや、別に何しててもいいんだけど、ただ本とか読んでたら5分過ぎたのに気付かず約束をすっぽかしてしまうだろ。そうしないためには何をしないといけない? **B:** 何をって…時計を見て5分経ったか確認するとかですか。 **A:** そう。人に頼む時は「5分待て」と言えば適当に待ってくれるけど、コンピュータはその「適当に」が出来ない。時計を確認するとかいったことを具体的に指示してやらないといけない。 **B:** はあ、そりゃ面倒くさいですね。 **A:** じゃあ改めて、「5分待て」と言われたらどうすればいいか、ちょっと書いてごらん。 **B:** んーっと…こんな感じでどうでしょうかね。 #. 待ち始めの時間を調べる #. 現在の時間と待ち始めの時間を比べる #. もし5分経っていたらおしまい #. 5分経っていなければ少しの間本などを読む #. 2.に戻る **A:** ちゃんと最初に「待ち始めの時間を調べる」が入ってるのがいいね。これも指示してやらないとコンピュータにはわからないからね。 じゃあこれを踏まえて今回の例題の説明に入ろう。下の灰色の部分が例題の解答例のソースファイルだ。説明用に行番号を付けてあるので、自分のコンピュータで実行してみたい場合は「行番号なしのソースファイルをダウンロード」の右のリンクからダウンロードしてほしい。 **B:** あのー、ダウンロードしようとすると画面にそのまま表示されちゃうんですが。 **A:** ああ、そういう場合はリンク右クリックして「名前を付けてリンク先を保存」とかなんとかかんとかいう項目を選べばいい。このあたりは使っているブラウザによるので各自でなんとかすること。 + 行番号なしのソースファイルをダウンロード→ `01-1.py `_ .. literalinclude:: source/01-1.py :language: python :encoding: shift-jis :linenos: :lineno-match: **A:** さて、さっそく解説するわけだが、とりあえず13行目までは今回はパス。14行目からが今回の課題だ。 **B:** えー。それじゃ半分以上パスになっちゃうじゃないですか。大事なことが書いてあるんでしょう? **A:** そりゃそうなんだが、最初からここの解説をするのはちょっと難しいんじゃないかと思うんだよね。まあいいか。 簡単に解説しておくと、3行目から6行目の **import** というコマンドは誰かが作ってくれた **モジュール** というものを読み込んでいる。 モジュールってのはいずれ詳しく解説するとして、とりあえず時間を測ったり画面に図形を描いたりする機能をまとめたものだと思っておけばいい。 Pythonでは、他の人が製作してくれたモジュールをimportすることによって、わざわざ自分で制作しなくてもその機能を使う事が出来るようになるんだ。 ここでは全画面表示をするためにVisionEggとVisionEgg.Core、オペレーティングシステムからのメッセージを処理するためにpygame、時間を測るためにtimeという モジュールをimportしている。 **B:** …なんか最後の方がさっぱり分かりませんが。 **A:** きちんと解説してないからね。この辺りの解説はいずれ。あと8行目から12行めではVisionEggの力を借りて灰色のスクリーンを作成している。 **B:** ふんふん。(あまり分かっていない) **A:** で、14行目からが本番だ。さっきB君が書いてくれた「『5分待て』と言われた時にすること」と並べて書いてみよう。 厳密に対応させようとするとちょっと難しいんだけど、こんな感じかな。 .. code-block:: python :linenos: :lineno-start: 13 ct = st = VisionEgg.time_func() # 待ち始めの時間を調べる while ct-st<5.0: # 現在の時間と待ち始めの時間を比べて5分経っていたらおしまい ct = VisionEgg.time_func() # (時計を確認する) event.get() # ↑ screen.clear() # 5分経っていなければ少しの間本などを読む swap_buffers() # ↓ まず14行目では、待ち始めの時間を調べて記憶している。VisionEgg.time_func()というのが現在の時間を調べろという命令。 ctとstは **変数** と呼ばれるもので、後で参考にしたい数値などを入れておける箱のようなものだ。 変数をうまく使いこなす事がプログラミングには必須なので、少しずつ慣れていってほしい。 **B:** わかるようなわからないような…。ctとstという名前の紙があって、そこへ現在の時間をメモしているってことでいいんですかね。ctとかstとかって名前のつけ方にルールはあるんですか? **A:** 紙とメモの例えはそれでOKかな。名前のつけ方にはもちろんルールがある。たとえば空白やピリオド、+、#などといった記号を名前に含む事は出来ない。 詳しくはpythonの文法書を参考にしてほしい。 **B:** なんかどんどん手抜きされているような気が… **A:** いや、きちんと説明しようとすると長くなるからね。いずれ機会があればページを改めて。14行目についてあともうひとつ重要なキーワードを。 ctやst、VisionEgg.time_func()の間にある = の記号は、 = の右側にある値を左側の変数へ納めるという操作を示している。このような記号を **演算子** という。 **B:** 左から右へっていうことは、ct = stと書くとctにstの値が、st = ctと書くとstにctの値が入るってことですね。 **A:** その通り。ct=3.0と書けばctに3.0という値が入る。3.0=ctとは書けない。理由はわかるね? **B:** 3.0は変数じゃないから、ですか? **A:** 正解。演算子にはいろいろな種類があるけど、まあおいおい説明していくとして、話を先に進めるよ。 **B:** は~い。 **A:** えーと、では続いて15行目から16行目。ここが今回のカギだ。 **while** というのは **制御構文** 呼ばれるもので、指定された条件に応じてプログラムの動作を変化させる働きをします。 pythonの制御構文には他にも **if** や **for** といったものがありますが、その辺りはは次回のお楽しみ。 whileは続く式を **評価** して、結果が **真(True)** である間はそれに続く **字下げ** された行を実行し、 **偽(False)** であればwhile以後の最初の字下げされていない行へ飛ぶ。 **B:** うわ、何言ってるのかさっぱり分かりません。 **A:** サンプルを見ながら説明した方が早いかな。14行目ではwhileの後にct-st<5.0って書いてあるでしょ。これの意味はわかる? **B:** んー、csからstを引いた数が5.0より小さい? **A:** 正解。この<や-も演算子なんだけど、なんとなく意味はわかるよね。例えばctが12.5でstが9.2だとしたら、この式は正しいかな? **B:** 12.5引く9.2は3.3だから、正しいですね。 **A:** 正しい場合、「ct-st<5.0という式の評価は真である」というのさ。pythonではTrueと表現する。もしctが54.2でstが9.2なら、ct引くstは5.0より大きくなるよね。この場合、「ct-st<5.0を評価すると偽になる」という。Pythonでは偽をFalseと表現する。 **B:** …なんでわざわざ英語を使うんですか。 **A:** なんでって言われてもなあ。pythonの文法ではそういう風に決められているんだから仕方がない。 で、字下げというのは16~19行目を見てほしいんだけど、行の先頭に空白が入っているでしょ。これが字下げで、pythonは **字下げを見てどこからどこまでをwhileで繰り返すのかを判断する** 。 だから空白は適当に入れちゃいけないんだよ。空白の入れ方については… **B:** pythonの文法書を参考にすること、ですか。 **A:** そのとおり。そろそろわかってきたな。 **B:** はあ。まあそれでいいです。 **A:** …で、16行目なんだが、ここで現在の時間をもう一度調べ直して、ctに入れている。さらに17~19行目の命令を実行して、15行目に戻ってきた時にはctに収められた時間が少しだけ進んでいることになるんだ。 これを何度も何度も繰り返しているうちに、そのうち5秒経つ。5秒経ったらct-st<5.0は偽になるので、15行目以降の字下げされていない行へ飛ぶ。 **B:** 19行目までずっと字下げされていて、そこでサンプルプログラムは終わっているんですが。 **A:** プログラムの最後の行まで進むと、Pythonのプログラムは停止する。つまり「5秒待て」の任務完了というわけだ。 **B:** ふむふむ、なるほど。それで、17~19行目はなんなんですか? **A:** ああ、これね。これは待ち時間の間にしなきゃいけない作業が書いてある。B君の「5分待つ」では「本などを読む」って書いてあるけど、コンピュータは別に本を読むわけじゃない。 **B:** いくらなんでもそれくらいわかります。 **A:** そりゃ失礼。これはVisionEggとpygameから借りてきた命令で、event.get()はキーボードやマウスが操作されたなどの情報を得る、 screen.clear()はスクリーンを灰色に塗りつぶす、swap_buffers()はウィンドウを描画するという機能がある。まあこの辺りは次回のサンプルに向けた布石なので、次回もうちょっと詳しく説明するよ。 今回の例題のサンプルプログラムの説明はだいたい以上かな。 **B:** …ところでさっきからずっと気になってるんですが。 **A:** ん? 何が? **B:** VisionEgg.time_func()とかevent.get()の最後にくっついている()って何ですか? **A:** む。なかなか良いところに目をつけたな。pythonではよく使う手続きをひとまとめにして、それに名前を付けて呼び出すという機能がある。 正確には手続きではなく **関数** というんだけど、手続きと関数の区別を言い出すとちょっと難しい話をしないといけないのでいずれ機会を改めて。 で、関数を呼び出す時には、関数の名前の後ろに()をつける。もし関数が値を必要とするものであるときは、()の中に値を書く。たとえばmathというモジュールには正弦を求めるsin()という関数があるんだけど、 0.5の正弦を求めたい時にはsin(0.5)と書くんだ。event.get()もscreen.clear()もswap_buffers()も今回の用途では値を必要としないので、ただ()だけが付いている。 まあこれはおいおい説明していくよ。わかったかな? **B:** (なんとも言えない表情) **A:** まあ、最初からいきなり理解するのは無理さ。いろんなサンプルを見ながら少しずつ身に付けていけばいいよ。では最後にサンプルプログラムを実行してみよう。 **B:** 実行、と。あれ、なんか変な画面が出てきました。 .. figure:: img/01-1-01.png **A:** これはVisionEggの設定ダイアログだね。VisionEggのウィンドウの大きさや色の設定などをここで変更し、保存する事が出来る。 インストール後にまだ何も設定を変更していないんだったらこのダイアログの右中央付近Window width (pixels)とWindow height (pixels)がそれぞれ640と480になっていると思うけど、 **この講座でのサンプルプログラムは幅1024×高さ768ピクセルで動かす事を前提としている** ので、ここで設定を変更して保存してみよう。 #. Window width (pixels)に1024と入力 #. Window height (pixels)に768と入力 #. ダイアログの一番下、Save current settings to config fileと書かれたボタンをクリック **B:** ほい、ほい、ほい、っと。…特に何も変化がありませんが? **A:** これで今ダイアログに表示されている内容が設定ファイルに保存されたから、次回以降VisionEggを起動したときには今保存した変更が反映される。じゃあOKを押してプログラムを実行してみよう。 **B:** じゃあOK、と。灰色の画面が出てきました。 .. figure:: img/01-1-02.png (数秒後) **B:** あ、消えちゃいましたね。これで終わりですか。 **A:** その通り。5秒待ち終わったら自動的に終了する。 **B:** なんだか5秒以上出てたような気がするんですが。 **A:** 灰色のウィンドウをまず描いてから5秒数え始めて、5秒経った後にウィンドウを後片付けする処理をしているからね。灰色のウィンドウが表示されている時間は5秒よりほんの少し長くなる。 **B:** ぴったり5秒出ているようにする事は出来ないんですか? **A:** うーん、初期化処理や終了処理に必要な時間はPCのスペックなどにもよるから難しいだろうな。 あと、もしOKボタンを押した後にエラーが出て来てしまう場合は、残念ながらプログラムを実行しているマシンがVisionEggのデフォルトの設定に対応していない。 大抵の場合は"Requiested total color depth"や"Requested green (blue, red)bits per pixcel"の値がマシンの性能を上回ってるのが原因なので、これらの値を下げるとよい。"Attempt vsync"のチェックを外したらうまくいった例もあったっけな。 こればかりは個々のマシンによって設定が違ってくるので、いろいろと試してもらうしかない。 **B:** ううっ。うちのボロPCは大丈夫かなあ。 **A:** とにかくこれで今回の例題は達成だ。次回は画面に文字を描いたりキーボードからの入力を待ったりするぞ。