The Trivia API The Quizzler App
Trivia Question API 과제
1️⃣ import requests
- 물음표 앞까지가 API
2️⃣ 파라미터 넣어주기
3️⃣ 예외처리
4️⃣ JSON을 사용해 데이터 받기
5️⃣ 원하는 키값을 받아 객체 저장
HTML 개체 unescape
- Freeformatter 툴을 이용해서 우리가 API로부터 받는 HTML 결과를 unescape할 수 있음
1️⃣ import html 모듈
2️⃣ unescape 메소드 사용
클래스 기반 Tkinter UI
1️⃣ class 키워드 사용, init생성
- 파스칼 표기법
2️⃣ init 안에 사용자 인터페이스 생성
- window
- label
- canvas
(캔버스에 뭔가를 추가할 때는 언제나 x,y값을 인자로 넣어줘야 함) - button
true_image = PhotoImage(file=”images/true.png”)에 self가 붙지 않는 이유
true_image는 QuizInterface 클래스의 init 메서드 내에서만 사용되는 지역 변수이다.
해당 메서드 내에서만 존재하며, 메서드 외부에서는 접근할 수 없음
self가 붙는 변수는 클래스의 인스턴스 변수로, 클래스의 다른 메서드나 인스턴스 외부에서도 해당 변수에 접근할 수 있다.
true_image 변수의 경우, init 메서드 내에서 이미지를 로드한 후 바로 self.true_button을 만드는 데 사용되었고,
이후에는 true_image에 대한 참조가 필요하지 않기 때문에 인스턴스 변수로 만들 필요가 없음
self.true_image로 만들면 해당 이미지는 객체가 존재하는 동안 계속 메모리에 남아있게 된다.
true_image로 만들면 init 메서드가 종료되면서 해당 이미지의 참조도 사라지게 되지만,
이미지 자체는 self.true_button에서 계속 사용되고 있기 때문에 문제 없이 동작한다.
임시적으로만 사용되는 변수는 지역 변수로 선언하는 것이 메모리 관리 측면에서 효율적임
3️⃣ main.py에 import
파이썬 타이핑 & GUI에서 다음 질문 표시하기
1️⃣ 콘솔에 input으로 띄운 질문을 함수의 반환값으로
2️⃣ main.py에서 QuizInterface에 quiz넣어주고 init안에 매개변수 추가
- import QuizBrain
- 데이터 타입 넣어주기
3️⃣ 캔버스 업데이트
4️⃣ 메소드 init안에서 호출
파이썬 타이핑 : Type Hints와 화살표
동적 타이핑: 변수를 생성 후 데이터형 변경
x = int(2.59)
- 오류를 덜 발생하기 위해 다루는 데이터형
- 디버깅 시간을 줄여줌
정답 확인하고 버튼 적용
- 메소드 생성
플레이어에게 피드백 주기, 점수 유지하기, 버그 수정
1️⃣check_answer메소드 수정
2️⃣ give_feedback메소드 생성
3️⃣ 점수 유지 기능
4️⃣ 질문 개수 끝나면 알리기
5️⃣ 게임을 마치면 버튼 기능 끄고 배경 흰색으로 돌리기
Final Code
main.py
from question_model import Question
from data import question_data
from quiz_brain import QuizBrain
from ui import QuizInterface
question_bank = []
for question in question_data:
question_text = question["question"]
question_answer = question["correct_answer"]
new_question = Question(question_text, question_answer)
question_bank.append(new_question)
quiz = QuizBrain(question_bank)
quiz_ui = QuizInterface(quiz)
while quiz.still_has_questions():
quiz.next_question()
print("You've completed the quiz")
print(f"Your final score was: {quiz.score}/{quiz.question_number}")
quiz_brain.py
import html
class QuizBrain:
def __init__(self, q_list):
self.question_number = 0
self.score = 0
self.question_list = q_list
self.current_question = None
def still_has_questions(self):
return self.question_number < len(self.question_list)
def next_question(self):
self.current_question = self.question_list[self.question_number]
self.question_number += 1
q_text = html.unescape(self.current_question.text)
return f"Q.{self.question_number}: {q_text}"
# user_answer = input(f"Q.{self.question_number}: {q_text} (True/False): ")
# self.check_answer(user_answer)
def check_answer(self, user_answer):
correct_answer = self.current_question.answer
if user_answer.lower() == correct_answer.lower():
self.score += 1
# print("You got it right!")
return True
else:
# print("That's wrong.")
return False
# print(f"Your current score is: {self.score}/{self.question_number}")
# print("\n")
ui.py
from tkinter import *
from quiz_brain import QuizBrain
THEME_COLOR = "#375362"
class QuizInterface:
def __init__(self, quiz_brain: QuizBrain):
self.quiz = quiz_brain
self.window = Tk()
self.window.title("Quizzler")
self.window.config(padx=20 ,pady=20, bg=THEME_COLOR)
self.score_label = Label(text="Score: 0", fg="white", bg=THEME_COLOR)
self.score_label.grid(row=0, column=1)
self.canvas = Canvas(width=300, height=250, bg="white")
self.question_text = self.canvas.create_text(
150,
125,
width=280,
text="Some Question Text",
fill=THEME_COLOR,
font=("Arial", 20, "italic")
)
self.canvas.grid(row=1, column=0, columnspan=2, pady=50)
true_image = PhotoImage(file="images/true.png")
self.true_button = Button(image=true_image, highlightthickness=0, command=self.true_pressed)
self.true_button.grid(row=2, column=0)
false_image = PhotoImage(file="images/false.png")
self.false_button = Button(image=false_image, highlightthickness=0, command=self.false_pressed)
self.false_button.grid(row=2, column=1)
self.get_next_question()
self.window.mainloop()
def get_next_question(self):
self.canvas.config(bg="white")
if self.quiz.still_has_questions():
self.score_label.config(text=f"Score:{self.quiz.score}")
q_text = self.quiz.next_question()
self.canvas.itemconfig(self.question_text, text=q_text)
else:
self.canvas.itemconfig(self.question_text, text="You've reached the end of the quiz.")
self.true_button.config(state="disabled")
self.false_button.config(state="disabled")
def true_pressed(self):
self.give_feedback(self.quiz.check_answer("True"))
def false_pressed(self):
self.give_feedback(self.quiz.check_answer("False"))
def give_feedback(self, is_right):
if is_right:
self.canvas.config(bg="green")
else:
self.canvas.config(bg="red")
self.window.after(1000, self.get_next_question)