Python Jarvis 対話型アプリ

Python学習【365日チャレンジ!】107日目のマスターU(@Udemy11)です。

ドラマの【JIN-仁-】と漫画の【JIN-仁-】の結末が違いすぎて、なんとも言えない気持ちになってしまいました。

確かに同じ結末にするのは芸がないのですが、ほんとにそれでいいの?なんて思えてくる結末で、ちょっと残念なような悲しいような。。。

まー、寝不足になりながらもすべて観終えたので、これでPython学習に集中できます。

ということで、今日もPython学習をはじめていきましょう!

昨日の復習

昨日は、オブジェクト指向でJarvisクラスを作成しました。

クラスと関数の骨組みだけなら次のようなコードになります。

import csv

class Jarvis(object):
    def say_hello(self):
    # 質問1

    def ask_main(self):
    # 質問2

    def __del__(self):
    # お礼の挨拶とCSVへの書き込み

if __name__ =='__main__':
    jarvis = Jarvis()
    jarvis.say_hello()
    jarvis.ask_main()
    del jarvis

Jarvisに質問をさせて、CSVファイルに取得したデータを書き込むという感じでしたね。

昨日出来上がったコードはこちらをごらんください。

それでは、2人目の質問をカバーするコードを書いていきましょう。

使用するライブラリ

1人目、2人目の質問までをカバーするのに必要なライブラリは次の2つ。

  • csvライブラリ
  • osライブラリ

CSVファイルを扱うライブラリとファイルの存在を確認するためのライブラリです。

__init__(self)の追加

1人目限定のJarvisと大きく違うのは、__init__(self)で初期化処理を入れるところです。

最初の質問の回答を取得するための関数input__init__に入れることはできませんでした。

初期化ですることは、ranking.csvの有無の確認と、データの取得です。

def __init__(self):
    self.check = os.path.exists('ranking.csv')
    if self.check is True:
        with open('ranking.csv', 'r') as rank_csv:
            ranking = csv.DictReader(rank_csv)
            for k in ranking:
                self.r_sport = k['NAME']

まずos.path.exists()self.checkTrueFalseが代入されます。

クラスJarvis内の関数で共通に使えるように、必要な変数にはself.をつけています。

ファイルの有無を確認して、ファイルが存在する場合は、csv.DictWriterを使って、値を取得しています。

名前を聞く質問

最初のあいさつと名前を聞く質問は、一人目のコードと同じです。

def say_hello(self):
    name = input('こんにちは。わたしはジャービスです。あなたの名前を教えてください。\n')
    self.c_name = name.title()
    return self.c_name

取得した値の先頭の文字を大文字にして、関数の返り値をself.c_nameにしています。

次の質問

次の質問はranking.csvに保存されているスポーツをおすすめして、好きかどうかたずねます。

答えはYesでもNoでも次の質問へいくので、それ以外の回答はないという前提で、条件分岐をつけませんでした。

def y_or_n(self):
    y_n = input('\nわたしのおすすめのスポーツは{}です。\n
                あなたはこのスポーツが好きですか? [Yes/No]\n'.format(self.r_sport))

ただ質問をして、なにか入力してもらうだけの関数ですね。

メインの質問

次は、メインの大好きなスポーツを尋ねる質問です。

def ask_main(self):
    like_sports = input('\n{}さん、あなたの好きなスポーツは何ですか?\n英語で答えてください\n'.format(self.c_name))
    self.c_like_sports = like_sports.title()
    return self.c_like_sports

この質問で取得した値は、1人目のスポーツとは違うという前提で、ranking.csvに追記します。

CSVへの書き込み

ranking.csvへの書き込みですが、__init__で取得したself.checkTrueの場合は、前の質問で取得したself.c_link_sportsを追記して、Falseの場合は、新しくranking.csvを作成して書き込みます。

def write_csv(self):
    if self.check is True:
        with open('ranking.csv', 'a') as rank_csv:
            fieldnames = ('NAME', 'COUNT')
            writer = csv.DictWriter(rank_csv, fieldnames=fieldnames)
            writer.writerow({'NAME': self.c_like_sports, 'COUNT': 1})
    else:
        with open('ranking.csv', 'w') as rank_csv:
            fieldnames = ('NAME', 'COUNT')
            writer = csv.DictWriter(rank_csv, fieldnames=fieldnames)
            writer.writeheader()
            writer.writerow({'NAME': self.c_like_sports, 'COUNT': 1})

デストラクタで出力

最後のあいさつは、デストラクタでprint出力します。

def __del__(self):
    print('\n{}さん、回答ありとうございました。\n良い1日をお過ごし下さい!'.format(self.c_name))

完成コード

Javisクラスに関数を6つ持たせたので、最後にオブジェクトを作成して、関数を実行するコードを追記します。

import csv
import os

class Jarvis(object):
    def __init__(self):
        self.check = os.path.exists('ranking.csv')
        if self.check is True:
            with open('ranking.csv', 'r') as rank_csv:
                ranking = csv.DictReader(rank_csv)
                for k in ranking:
                    self.r_sport = k['NAME']
                    
    def say_hello(self):
        name = input('こんにちは。わたしはジャービスです。あなたの名前を教えてください。\n')
        self.c_name = name.title()
        return self.c_name
                
    def y_or_n(self):
        y_n = input('\nわたしのおすすめのスポーツは{}です。\nあなたはこのスポーツが好きですか? [Yes/No]\n'.format(self.r_sport))

    def ask_main(self):
        like_sports = input('\n{}さん、あなたの好きなスポーツは何ですか?\n英語で答えてください\n'.format(self.c_name))
        self.c_like_sports = like_sports.title()
        return self.c_like_sports
        
    def write_csv(self):
        if self.check is True:
            with open('ranking.csv', 'a') as rank_csv:
                fieldnames = ('NAME', 'COUNT')
                writer = csv.DictWriter(rank_csv, fieldnames=fieldnames)
                writer.writerow({'NAME': self.c_like_sports, 'COUNT': 1})
        else:
            with open('ranking.csv', 'w') as rank_csv:
                fieldnames = ('NAME', 'COUNT')
                writer = csv.DictWriter(rank_csv, fieldnames=fieldnames)
                writer.writeheader()
                writer.writerow({'NAME': self.c_like_sports, 'COUNT': 1})        

    def __del__(self):
        print('\n{}さん、回答ありとうございました。\n良い1日をお過ごし下さい!'.format(self.c_name))

if __name__ == '__main__':
    jarvis = Jarvis()
    jarvis.say_hello()
    if jarvis.check is True:
        jarvis.y_or_n()
    jarvis.ask_main()
    jarvis.write_csv()
    del jarvis

ファイルがインポートされたときのためにif __name__ == '__main__':を使います。

ranking.csvが存在したときのみ、45行目と46行目でJarvisがおすすめするスポーツが好きかどうか尋ねる質問を実行します。

昨日書いたコードでは、デストラクタにCSVを作成するコードを入れていましたが、書き込みが2つのパターンになるため、write_csv()関数に切り分けてみました。

書き方はいろいろ

今回は、初期化作業を入れてコードを書きましたが、ファイルの存在をチェックするための関数を一つ作っても問題ないかもしれません。

CSVへの書き込みは、デストラクタに入れてしまっても大丈夫だし、コードの書き方は違っても同じ動作をさせることができます。

正解はないわけなので、間違いを恐れず、どんどん違うコードを書くようにしましょう!

では、明日もGood Python!