UdemyでPythonを勉強した結果を残すブログ。

40歳でプログラミング始めて転職までいけるのかを実録してみます。

DAY17 クラスの初期化してクイズアプリを作る

DAY16 のclassはメソッドを格納して1つのコーヒーメーカーだけでなく

他のコーヒーメーカーでも使えるように基本的な機能を格納する記述を勉強したけど、

 

今回は呼び出したら機能を使えるだけでなく、

元々のデフォルト設定ができるようなコーディングを勉強する。

 

流れとしては、

 

  1. クイズをネットからゲットする
  2. クイズデータとしてpyにリストとして保存する
  3. クイズマシーンをクラスとして用意し、そこにクイズデータを入れてクイズを出してもらう
  4. クイズが尽きるまで繰り返し、終わったら何ポイントか教えてもらう

こんな感じ。

 

main.pyでいうと、

#用意するのは main.py, quiz_brain.py, quiz_model, questionsの4つ

#import quiz_data

#append list to quiz_list

#app quiz_machine!

#if quiz number = 0, finish

#print your point!

 

こんな感じ。

 

では始めます。

 

questions.pyから。

 

trivia databaseから質問をjsonでコピペする。

opentdb.com

 

ページに行ったら右上のAPIをクリック

今回は10問のクイズアプリを作るので、

Number of Questions : 10

Select Category : 好きなの

Select Difficulty : 好きなの

Select Type : 今回は2択クイズにするので True  False

Select Encoding : Default Encoding

 

でGenerate APIをクリック

すると、APIアドレスが出てくるのでコピペでジャンプする。例:

https://opentdb.com/api.php?amount=10&category=11&difficulty=easy&type=boolean#

JSON format でコピー。

 

今回作るmain.pyと同じフォルダ内にquestions.pyとかの名前で保存する。

(今後はAPIで取得すると毎回違うクイズが自動で出てきたりもできる)

 

一番最初にquestion_data = [をつけて、一番最後に]をつけてリスト化する。

 

クイズデータはこんな感じ

questions_data = [
{
"response_code": 0,
"results": [
{
"category": "Entertainment: Film",
"type": "boolean",
"difficulty": "easy",
"question": "Han Solo's co-pilot and best friend, "Chewbacca", is an Ewok.",
"correct_answer": "False",
"incorrect_answers": [
"True"
]
},
クイズが続く...
]

 

 

quiz_machine.py詳細

 

これでクイズデータができたので、次はクイズマシーンをクラスで作る。

別のファイル quiz_machine.pyを作成。

 

作る内容はこちら

  1. スコア・クイズ数・クイズデータの初期化
  2. クイズが最後かどうかを確認する機能
  3. クイズを出す機能
  4. 答えが合ってるかどうかをチェックする機能

 

初期化

クイズマシーンでクイズを出すときはスコア・クイズ数・取り込むクイズデータを初期化したいので、最初にコーディングしていく。

 

初期化するときはいままでの def function()... ではなく、

def __init__ (self, args):  でコーディングする。

selfというのはそのクラス自身ということで必ずいる。

argsは適当に今回つけただけでここには他のファイルから出力されたデータを受け取ることができる。

今回の場合はクイズデータを取り込むので、argsの部分はq_dataなどにする。

 

class QuizMachine:
def __init__(self, q_data):
self.q_num = 0
self.score = 0
self.q_data = q_data

 

これでまずクイズマシーンを始めるたびにクイズ数・スコア・取り込むデータが初期化される。

クラスの中で使う機能は全て最初にself.を入れる。

(ちょっとしつこいけど)

 

次にクイズが最後かどうかを確認する機能。

クイズナンバーが最後のクイズ数より大きくなったらfalseを返す。

クイズを出すごとにq_numが増えていく想定にしているので、

それが取り込むクイズデータの数より大きかったらfalseに。

    def continue_q(self):
return self.q_num < len(self.q_data)

このコーディングではfalseは書いてないのは、

これだけですでにbooleanを吐き出すようになっているから。

 

クイズを出す機能

クイズを出すにはこの機能がいる。

  • 今何問目かを取得する
  • その数字にあてられた質問を出して、答えてもらう
  • 回答者と質問の答えを出力して、チェックする機能に渡す

 

これをコーディングすると、


def next_q(self):
current_q = self.q_data[self.q_num] #今の質問ナンバーを取得
self.q_num += 1 #1つ増やす
user_a = input(f"{self.q_num} : {current_q.text} \n T / F ? : ")
self.check_a(user_a, current_q.answer) #check_answerで合ってるかチェック

 

となる。

 

最後に、チェック機能であってるか確認する

next_qの中に書いたcheck_aを書いていく。

これはシンプルにif であってたらスコアアップする感じ。

このコードにある[:1]というのはデータをスライスしていて、

最初の1文字だけを取得しています。

回答者もめんどくさいので trueとかfalseとか毎回書くのめんどくさいし笑

打ち間違いもあるかもと思ってとりあえず.lower()で小文字にして1文字だけを見ています。

問題にもTかFかにしています。

 


def check_a(self, user_a, correct_a):
if user_a[:1].lower() == correct_a[:1].lower():
self.score += 1
print("Got it!")
else:
print("It's wrong...")
print(f"Now your score is {self.score} / {self.q_num}.")

 

これでquizmachineクラスは完成。

 

もう1つquestion_modelがあるが、途中で書くとして最後の仕上げに。

 

main.pyでクイズアプリをまとめる

 

終盤になってきました。

main.pyで作ったファイルをインポートしていきます。

import html
from questions import questions_data
from quiz_machine import QuizMachine
from question_model import QuestionModel

 

最初に import htmlをいれているのは、後で説明します。

次に、questions_data のデータ指定のコードを少し短くしたいので、

ショートカットの変数を作ります。

 


#import quiz_data
q_list = questions_data[0]["results"]

 

questions_dataのjsonデータから必要なものだけ(クイズと正解)を辞書型リストとして作っていきます。

 


#import quiz_data
q_list = questions_data[0]["results"]

#append list to quiz_list

quiz_data_to_list = []
for quiz in q_list:
q_text = quiz["question"]
q_text = html.unescape(q_text)
q_a = quiz["correct_answer"]
new_q = QuestionModel(q_text,q_a)
quiz_data_to_list.append(new_q)

 

ここでQuestionModel()がでてきました。

これは取得したデータを辞書型リストにするためにはオブジェクトとして登録しなくてはいけないのですが、

それをクラスとして別ファイルにしてコーディングしています。

 

question_model.py

class QuestionModel:
def __init__(self, q, a):
self.text = q
self.answer = a

 

展開するときにはこれは合った方がいいのかもしれないけど、

ここだけであれば

 

new_q = {q_text, q_a}

にしても問題なし。

ただこの場合はnext_q()のuser_a以下をこちらに変更する必要がある。

keysとvaluesで呼び出す必要がある。


user_a = input(f"{self.q_num} : {list(current_q.keys())[0]} \n T or F ? : ")
self.check_a(user_a, list(current_q.values())[0]) #check_answerで合ってるかチェック

 

脱線しましたが、jsonを辞書型リストに保存して、

次はクイズマシーンをここで呼び出します。

先ほどappendしてクイズデータをリストにしたquiz_data_to_listを中に入れます。

 


#app quiz_machine!

quiz = QuizMachine(quiz_data_to_list)

 

 

クイズが終わるまで次の問題を出し続けるクイズマシーンの機能を

呼び出します。


#if quiz number = 0, finish

while quiz.continue_q():
quiz.next_q()

 

クラスのオブジェクトの中からメソッドのみを呼び出す場合は

呼び出したクラス変数にドットをつけてメソッドを書けば起動してくれます。

これは同じく初期値なども呼び出せます。

 

最後にクラスの初期値であるスコアとクイズ数を呼び出します。

初期値といったもののクイズが終わった後なので、

スコアとクイズ数は変わっています。

 


print("Finish Quiz!")
print(f"Your final score is {quiz.score}/ {quiz.q_num}")

 

これで完成!

 

最終コードはこちら。

 

main.py

import html
from questions import questions_data
from quiz_machine import QuizMachine
from question_model import QuestionModel

#import quiz_data
q_list = questions_data[0]["results"]

#append list to quiz_list

quiz_data_to_list = []
for quiz in q_list:
q_text = quiz["question"]
q_text = html.unescape(q_text)
q_a = quiz["correct_answer"]
# new_q = QuestionModel(q_text,q_a)
new_q = {q_text:q_a}
quiz_data_to_list.append(new_q)

# print(quiz_data_to_list)

#app quiz_machine!

quiz = QuizMachine(quiz_data_to_list)

#if quiz number = 0, finish

while quiz.continue_q():
quiz.next_q()

print("Finish Quiz!")
print(f"Your final score is {quiz.score}/ {quiz.q_num}")


#print your point!

 

questions.py

questions_data = [
{
"response_code": 0,
"results": [
{
"category": "Entertainment: Film",
"type": "boolean",
"difficulty": "easy",
"question": "Han Solo&#039;s co-pilot and best friend, &quot;Chewbacca&quot;, is an Ewok.",
"correct_answer": "False",
"incorrect_answers": [
"True"
]
},....

]

 

quiz_machine.py

class QuizMachine:
def __init__(self, q_data):
self.q_num = 0
self.score = 0
self.q_data = q_data

def continue_q(self):
return self.q_num < len(self.q_data)

def next_q(self):
current_q = self.q_data[self.q_num] #今の質問ナンバーを取得
self.q_num += 1 #1つ増やす
# user_a = input(f"{self.q_num} : {current_q.text} \n T or F ? : ")
# self.check_a(user_a, current_q.answer) #check_answerで合ってるかチェック

user_a = input(f"{self.q_num} : {list(current_q.keys())[0]} \n T or F ? : ")
self.check_a(user_a, list(current_q.values())[0]) # check_answerで合ってるかチェック

def check_a(self, user_a, correct_a):
if user_a[:1].lower() == correct_a[:1].lower():
self.score += 1
print("Got it!")
else:
print("It's wrong...")
print(f"A : {correct_a}")
print(f"Now your score is {self.score} / {self.q_num}.")

question_model.py

 

class QuestionModel:
def __init__(self, q, a):
self.text = q
self.answer = a