前回、前々回では、日時を教えてくれる対話システムを作成しました。変数と条件分岐を使うことで、ユーザー発話(入力)に応じてシステムの応答を変える処理を行えることがおわかりいただけたかと思います。

この変数や条件分岐のように、プログラムの処理を構成する重要な要素の1つが「繰り返し処理」です。今回は、繰り返し処理を使ってくじびきをする対話システムを作成しましょう。

プログラミングの処理は大きく分けると、「変数への代入」「条件分岐」「繰り返し処理」から成り立っています。そのため、今回の内容を理解することで「プログラミングでできること」の多くがわかるようになるはずです。

くじびき対話システムの概要

今回作成するくじびき対話システムでは、次のようにユーザー発話が「くじびき」の場合、くじびきの結果を返します。

ユーザー発話:くじびき
システム発話:くじびきの結果は…あたりです! おめでとうございます!

くじびきの結果には、「あたり」のほかに「はずれ」もあります。

ユーザー発話:くじびき
システム発話:くじびきの結果は…はずれです! 残念でした。

今回のくじびき対話システムの機能はこれだけではありません。くじびきの結果が出た後、もう一度くじを引くかどうかをユーザーに尋ねます。そして「はい」だった場合はもう一度引き、そうでない場合は終了します。

ユーザー発話:くじびき
システム発話:くじびきの結果は…はずれです! 残念でした。
システム発話:もう一度くじをひきますか?
ユーザー発話:はい
システム発話:くじびきの結果は…はずれです! 残念でした。
システム発話:もう一度くじをひきますか?
ユーザー発話:いいえ
システム発話:くじびきを終了します。

なお、はじめのユーザー発話が「くじびき」でない場合は、以下のように「わかりません」と答えます。

ユーザー発話:おはよう。
システム発話:すみません、わかりません。

それでは、Pythonの機能を理解しながらくじびき対話システムを作っていきましょう。作業ディレクトリは「C:\Users\user\Documents\pychat\lot」としますので、事前に作成しておいてください。

繰り返し処理

はじめに、冒頭で紹介した繰り返し処理について紹介します。

前回紹介した「if文」を思い出してください。if文では、「if」の後ろに条件式を書いて、条件が成立する場合には続くインデント行を実行し、そうでない場合は「else」に続くインデント行を実行するのでしたね。

if 条件式:
    条件が成り立つときの処理
else:
    条件が成り立たないときの処理

繰り返し処理も、これと似た構造を持っています。繰り返し処理の場合は「while文」を使い、「while」の後ろに条件式を書きます。

while 条件式:
    条件が成り立つ場合の処理

if文との違いは、while文は条件式が成り立つ間ずっとその処理を行うということです。より正確には、次のような動作をします。

  1. 条件式が成り立つかどうかチェックする。
  2. 条件式が成り立つ場合には処理を実行し、1に戻る。条件が成り立たない場合は処理を実行しないで繰り返しを終了する。

簡単な例として、ユーザー発話を取得して「はい」が成り立つ間は「条件が成り立ちました。」と表示し、そうでない場合は「条件が成り立ちませんでした。」と表示するプログラムを作成してみましょう。次のプログラムを「while.py」というファイル名で作成してください。

# while.py - 繰り返しのプログラム
utterance = input("ユーザー発話> ")
while utterance == "はい":
    print("条件が成り立ちました。")
    utterance = input("ユーザー発話> ")
print("条件が成り立ちませんでした。")

このプログラムでは、まず2行目でユーザー発話を取得して変数utteranceに束縛し、3行目でutteranceの値が「はい」と一致するかどうかをチェックします。そして、一致している間は続くインデントされた行で「条件が成り立ちました。」と表示し、再度ユーザー発話を取得して変数utteranceに束縛します。この処理を繰り返し、ユーザー発話が「はい」でなくなったタイミングで処理から抜けて「条件が成り立ちませんでした。」と表示します。

それでは実行してみましょう。

$ python while.py
ユーザー発話> はい
条件が成り立ちました。
ユーザー発話> はい
条件が成り立ちました。
ユーザー発話> いいえ
条件が成り立ちませんでした。

期待通りの動作をしていますね!

さて、ここで条件式について詳しく見ていきたいと思います。前回、条件式では演算子==を用いて、2つのオブジェクトの値が等しいかどうかを確認していると説明しました。では、この演算子を用いた「結果」はどのようなオブジェクトなのでしょうか? printで出力して確かめてみましょう。

次のようなプログラム「cond.py」を作成し、実行してみてください。

# cond.py - 条件式の結果を確かめるプログラム
utterance = "はい"
print(utterance == "はい")

すると、以下のように表示されるはずです。

$ python cond.py
True

Pythonでは、条件が「成り立つ」や「成り立たない」といった結果を表すために、「True」または「False」のいずれかの値をとる「ブール値」を提供しています。

今まで条件式に使用していた演算子==は、実は、2つのオブジェクトの値が等しいかどうかを判定し、等しい場合には「True」を、等しくない場合には「False」というブール値を返していました。

そのため、上記のcond.pyでは、utteranceの値と”はい”が等しいかどうかを判定した結果である「True」が、そのままprintで出力されているわけです。

if文やwhile文では、条件式の結果を判定するためにこのブール値を利用しています。

なお、2つのオブジェクトの値が等しくないことを確認するには演算子!=を使います。より詳しくは、2つのオブジェクトの値が等しくない場合は「True」を返し、等しい場合には「False」を返します。今回作成するくじびきプログラムにも登場するので、頭の片隅に留めておいてください。

ここまでの説明で、先ほどのプログラムを違った方法で実装できるようになります。次のプログラム「while_true.py」をご覧ください。

# while_true.py - ブール値を使った繰り返しのプログラム
while True:
    utterance = input("ユーザー発話> ")
    if utterance == "はい":
        print("条件が成り立ちました。")
    else:
        # 条件が成り立たない場合は「break」で繰り返し処理を抜ける
        print("条件が成り立ちませんでした。")
        break

このプログラムには、注目すべき点が2カ所あります。

1つは、2行目の「while True:」です。while文の条件式の部分に直接「True」を指定しています。つまり、常に条件が成り立っている状態です。したがって、このままでは永遠に繰り返し処理が終わらない無限ループになってしまいます。

そこで、次は9行目の「break」に着目してください。break文は、繰り返し処理の中で使用でき、その場で繰り返し処理を終了します。上記のプログラムでは、条件式が成り立たなかった場合に「条件が成り立ちませんでした。」と表示した後、繰り返し処理を終了します。

それでは先ほど実装した「while.py」と同じ挙動をするかどうか、実際に実行してみましょう。

$ python while_true.py
ユーザー発話> はい
条件が成り立ちました。
ユーザー発話> はい
条件が成り立ちました。
ユーザー発話> いいえ
条件が成り立ちませんでした。

予想通り同じ挙動をしているようですね!

これで、while.pyと同等のプログラムを違う方法で実装できたことになります。

このように、プログラミング言語の機能を新たに学んだときは、それを使って既存のプログラムがどう書き直せるか考えると理解が深まります。ぜひ実践してみてください。

今回はくじびき対話システムを作成する準備として、繰り返し処理を行うwhile文を紹介しました。前回までに学んだ変数、条件分岐と合わせて使えば、かなりのことができるようになったはずです。

次回は、ユーザー発話が「くじびき」だった場合に「あたり」か「はずれ」の結果を返す処理について、複数のオブジェクトをまとめて扱うことができる「リスト」機能の紹介を交えながら解説します。

著者紹介


株式会社NTTドコモ
R&Dイノベーション本部 サービスイノベーション部
阿部憲幸

2015年京都大学大学院理学研究科数学・数理解析専攻修了。 同年、NECに入社。 2016年から国立研究開発法人情報通信研究機構出向。 2018年より現職。 自然言語処理、特に対話システムの研究開発に従事。 毎日話したくなるAIを夢見て日夜コーディングに励む。
GitHub:https://github.com/noriyukipy