前回は、くじびき対話システムを作成する準備として繰り返し処理を行うwhile文を紹介しました。今回は、システムを作成する上で必要となる複数のオブジェクトをまとめて扱う仕組み「リスト」を紹介してから、いよいよ実装に入ります。

リスト

プログラミングをしていく上で、複数のオブジェクトをまとめて扱いたくなるようなケースは度々発生します。例えば、今回作成するくじびき対話システムでは、くじびきの結果として「あたり」と「はずれ」の2つの文字列オブジェクトを用意するのですが、これらのオブジェクトはまとめて扱えると便利です。

複数のオブジェクトをまとめて扱うための機能として、Pythonは「リスト」を提供しています。リストは、次のように「,(カンマ)」区切りで括弧でオブジェクトを囲んで記述します。

# 2つの文字列オブジェクトを含むリストを作る
results = ["あたり", "はずれ"]
print(results)  # => ['あたり', 'はずれ'] と表示される

リストは、その内部でオブジェクトに順序をつけて保持しています。リストの「インデックス」を指定することで、保持している値をリストから取り出すことができます。ただし、インデックスは「0」から始まることに注意してください。例えば、リストの1番目の要素を取り出すには次のようにインデックスに「0」を指定します。

# リストの1番目の値を取り出す
print(results[0])  # 「あたり」と表示される

リストを使うことで複数の要素をひとまとめにし、そこから必要に応じて値を取り出すことができるわけです。

さて、このリストを使ってくじびきに必要な機能を実装してみましょう。くじ引きでは、「あたり」と「はずれ」のどちらか1つをランダムに選択してユーザーに表示します。このようなランダムな処理はrandomモジュールとしてPythonが提供しています。このrandomモジュールが提供するchoice関数が、リストから1つの値をランダムに返してくれるのです。

では、random モジュールを使って「あたり」か「はずれ」のどちらか1つをランダムに表示するプログラムを実装してみましょう。「rand.py」という名前でファイルを作成し、以下のようなスクリプトを記述してみてください。

# rand.py - 「あたり」と「はずれ」からランダムに1つを表示するプログラム
import random

results = ["あたり", "はずれ"]
result = random.choice(results)
print(result)  # => "あたり" か "はずれ" を表示する

保存したら何度か実行して、ランダムで「あたり」か「はずれ」が出力されることを確かめましょう。

$ python rand.py
あたり
$ python rand.py
はずれ
$ python rand.py
はずれ

くじびき対話システムの実装

ではいよいよ、繰り返し処理とリストを使ってくじびき対話システムを作成しましょう。今回のプログラムは今までよりも複雑なので、初めに全体の構造から考えてみます。

最初のユーザー発話が「くじびき」の場合にはくじびきを行い、そうでない場合は「わからない」と答えるので、プログラムはif文を使った次のような構造となります。

utterance = input("ユーザー発話> ")
if utterance == "くじびき":
    ここでくびじきの処理を書く
else:
    print("すみません、わかりません。")

後は、「くじびきの処理」を実装すればよいので、その部分に集中しましょう。くじびきの処理では、次の内容を実行します。

  1. くじびきの結果を表示する。
  2. もう一度くじをひくかどうかユーザーに聞く。「ひく」の場合は1に戻り、そうでない場合は「くじびきを終了します。」と表示して終了する。

この一連の流れは、まさに繰り返し処理ですね! 早速、while文で実装してみましょう。

utterance = input("ユーザー発話> ")
if utterance == "くじびき":
    while True:
        ここでくじびきの結果を表示する
        retry_check = input("もう一度くじを引きますか? > ")
        if retry_check != "はい":
            print("くじびきを終了します。")
            break
else:
    print("すみません、わかりません。")

「if retrycheck != “はい”: 」の部分で、オブジェクトの値が等しくないことを確認するために演算子!=を使っていることに注意してください。ここでは、変数retrycheckの値が”はい”ではなかったときに「くじびきを終了します。」と出力し、break文で繰り返し処理を抜けています。

最後に、くじびきの結果を表示する部分を実装して完成です。

くじびきの結果は、「あたり」か「はずれ」のいずれか1つをランダムに選択してその結果をユーザーに表示します。ここは、先ほど紹介したrandomモジュールを使って実装してみましょう。

# lot.py - くじびき対話システム
import random

utterance = input("ユーザー発話> ")
if utterance == "くじびき":
    while True:
        # くじびきの結果を表示する
        results = ["あたり", "はずれ"]
        result = random.choice(results)
        if result == "あたり":
            comment = "おめでとうございます!"
        else:
            comment = "残念でした。"
        print("くじびきの結果は...{}です!{}".format(result, comment))

        # もう一度くじをひくか確認する
        retry_check = input("もう一度くじを引きますか? > ")
        if retry_check != "はい":
            # 「はい」でない場合は break で繰り返しを終了する
            print("くじびきを終了します。")
            break
else:
    print("すみません、わかりません。")

くじびきの結果が「あたり」か「はずれ」かに応じて「おめでとうございます! 」か「残念でした。」を一言つける必要があるので、変数resultの値をif文で確認し、対応する一言を変数commentに束縛して表示していることに注意してください。

これでくじびきシステムが完成しました! このプログラムを「lot.py」という名前で保存して実行してみましょう。

$ python lot.py
ユーザー発話> くじびき
くじびきの結果は...はずれです!残念でした。
もう一度くじを引きますか? > はい
くじびきの結果は...あたりです!おめでとうございます!
もう一度くじを引きますか? > いいえ
くじびきを終了します。

期待通りの出力ですね。それでは、初めのユーザー発話が「くじびき」でない場合はどうでしょうか?

$ python lot.py
ユーザー発話> おはよう。
すみません、わかりません。

こちらも問題ないようです。ちなみに、「もう一度くじを引きますか?」に対しての入力は、「いいえ」に限らず「はい」以外の入力であれば「くじびきを終了します。」と表示して終了します。これは、変数retry_checkの値が「はい」と等しいかどうかしか確認していないからです。

これでついに、最初にイメージした通りのくじびき対話システムが完成しました!

* * *

前回、今回と2回にわたり、プログラミングの主な構成要素となる繰り返し処理とリストを紹介しながら、くじびき対話システムを作成しました。

より対話システムらしいプログラムになるにつれて、作成するプログラムのサイズも次第に大きくなっていることを実感されているかと思います。こうして少しずつ巨大になっていくプログラムをどうやってうまく扱っていくかは、プログラミングにおける課題の1つです。本連載でも今後、このプログラムの巨大化に立ち向かっていく方法を紹介していきますので、楽しみにしていてください。

しかしその前に、まだ紹介しておかなければいけないPythonの機能があります。次回もPythonへの理解を深めつつ、対話システムを実装していきましょう。

著者紹介


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

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