OOP로 Python 구구단 앱 빌드

이 기사에서는 Python의 객체 지향 프로그래밍(OOP) 기능을 사용하여 구구단 앱을 빌드할 것입니다.

OOP의 주요 개념과 완전한 기능을 갖춘 애플리케이션에서 이를 사용하는 방법을 연습합니다.

파이썬은 멀티패러다임 프로그래밍 언어입니다. 즉, 개발자로서 각 상황과 문제에 가장 적합한 옵션을 선택할 수 있습니다. 객체 지향 프로그래밍에 대해 이야기할 때 우리는 지난 수십 년 동안 확장 가능한 애플리케이션을 구축하기 위해 가장 많이 사용된 패러다임 중 하나를 언급하고 있습니다.

OOP의 기본

우리는 파이썬에서 OOP의 가장 중요한 개념인 클래스에 대해 간단히 살펴볼 것입니다.

클래스는 개체의 구조와 동작을 정의하는 템플릿입니다. 이 템플릿을 사용하면 클래스 구성에 따라 만들어진 개별 개체에 불과한 인스턴스를 만들 수 있습니다.

제목과 색상 속성을 가진 간단한 책 클래스는 다음과 같이 정의됩니다.

class Book:
    def __init__(self, title, color):
        self.title = title
        self.color = color

클래스 북의 인스턴스를 생성하려면 클래스를 호출하고 인수를 전달해야 합니다.

# Instance objects of Book class
blue_book = Book("The blue kid", "Blue")
green_book = Book("The frog story", "Green")

현재 프로그램의 좋은 표현은 다음과 같습니다.

놀라운 점은 blue_book 및 green_book 인스턴스의 유형을 확인할 때 “Book”을 얻는다는 것입니다.

# Printing the type of the books

print(type(blue_book))
# <class '__main__.Book'>
print(type(green_book))
# <class '__main__.Book'>

이러한 개념이 명확해지면 프로젝트 구축을 시작할 수 있습니다 😃.

프로젝트 진술

개발자/프로그래머로 일하는 동안 대부분의 시간은 코드 작성에 소비되지 않는다고 합니다. 뉴스 스택 우리는 코드를 작성하거나 리팩토링하는 데 시간의 1/3만 소비합니다.

나머지 3분의 2는 다른 사람의 코드를 읽고 작업 중인 문제를 분석하는 데 사용했습니다.

따라서 이 프로젝트에서는 문제 설명을 생성하고 여기에서 앱을 만드는 방법을 분석합니다. 그 결과 솔루션을 고민하는 것부터 코드로 적용하는 것까지 전체 프로세스를 만들고 있습니다.

초등학교 교사는 8세에서 10세 사이의 학생들의 곱셈 기술을 테스트하기 위한 게임을 원합니다.

게임에는 생명과 포인트 시스템이 있어야 하며, 학생은 3개의 생명으로 시작하고 승리하려면 일정 포인트에 도달해야 합니다. 프로그램은 학생이 자신의 삶을 모두 소모한 경우 “패배” 메시지를 표시해야 합니다.

게임에는 무작위 곱셈과 테이블 곱셈의 두 가지 모드가 있어야 합니다.

첫 번째는 학생에게 1에서 10까지의 무작위 곱셈을 제공해야 하며 점수를 얻으려면 올바르게 답해야 합니다. 그것이 발생하지 않으면 학생은 라이브를 잃고 게임은 계속됩니다. 학생은 5점에 도달했을 때만 승리합니다.

두 번째 모드는 1에서 10까지의 구구단을 표시해야 하며, 여기서 학생은 해당 곱셈의 결과를 입력해야 합니다. 학생이 3번 실패하면 패배하지만 두 테이블을 완료하면 게임이 종료됩니다.

요구 사항이 조금 더 클 수 있다는 것을 알고 있지만 이 기사에서 해결해 드릴 것을 약속드립니다 😁.

분할 및 정복

프로그래밍에서 가장 중요한 능력은 문제 해결 능력입니다. 코드 해킹을 시작하기 전에 계획이 필요하기 때문입니다.

나는 항상 더 큰 문제를 쉽고 효율적으로 해결할 수 있는 더 작은 문제로 나눌 것을 제안합니다.

  Discord에서 2단계 인증(2FA)을 활성화 또는 비활성화하는 방법

따라서 게임을 만들어야 하는 경우 게임을 가장 중요한 부분으로 나누는 것부터 시작하세요. 이러한 하위 문제는 해결하기가 훨씬 쉬울 것입니다.

바로 그때 모든 것을 코드와 함께 실행하고 통합하는 방법을 명확하게 알 수 있습니다.

게임이 어떻게 생겼는지 그래프를 만들어 봅시다.

이 그래픽은 앱의 개체 간의 관계를 설정합니다. 보시다시피 두 가지 주요 개체는 무작위 곱셈과 테이블 곱셈입니다. 그리고 그들이 공유하는 유일한 것은 Points와 Lives 속성입니다.

이 모든 정보를 염두에 두고 코드를 살펴보겠습니다.

부모 게임 클래스 만들기

객체 지향 프로그래밍으로 작업할 때 우리는 코드 반복을 피하는 가장 깔끔한 방법을 찾습니다. 이것은 … 불리운다 마른 (반복하지 마십시오).

참고: 이 목표는 더 적은 수의 코드를 작성하는 것과는 관련이 없지만(코드 품질이 해당 측면으로 측정되어서는 안 됨) 가장 많이 사용되는 논리를 추상화하는 것입니다.

이전 아이디어에 따르면 애플리케이션의 상위 클래스는 다른 두 클래스의 구조와 원하는 동작을 설정해야 합니다.

어떻게 될지 봅시다.

class BaseGame:

    # Lenght which the message is centered
    message_lenght = 60
    
    description = ""    
        
    def __init__(self, points_to_win, n_lives=3):
        """Base game class

        Args:
            points_to_win (int): the points the game will need to be finished 
            n_lives (int): The number of lives the student have. Defaults to 3.
        """
        self.points_to_win = points_to_win

        self.points = 0
        
        self.lives = n_lives

    def get_numeric_input(self, message=""):

        while True:
            # Get the user input
            user_input = input(message) 
            
            # If the input is numeric, return it
            # If it isn't, print a message and repeat
            if user_input.isnumeric():
                return int(user_input)
            else:
                print("The input must be a number")
                continue     
             
    def print_welcome_message(self):
        print("PYTHON MULTIPLICATION GAME".center(self.message_lenght))

    def print_lose_message(self):
        print("SORRY YOU LOST ALL OF YOUR LIVES".center(self.message_lenght))

    def print_win_message(self):
        print(f"CONGRATULATION YOU REACHED {self.points}".center(self.message_lenght))
        
    def print_current_lives(self):
        print(f"Currently you have {self.lives} livesn")

    def print_current_score(self):
        print(f"nYour score is {self.points}")

    def print_description(self):
        print("nn" + self.description.center(self.message_lenght) + "n")

    # Basic run method
    def run(self):
        self.print_welcome_message()
        
        self.print_description()

와우, 이것은 꽤 거대한 수업 인 것 같습니다. 깊이 있게 설명하겠습니다.

먼저 클래스 속성과 생성자를 이해합시다.

기본적으로 클래스 속성은 클래스 내부에서 생성되지만 생성자 또는 메서드 외부에서 생성되는 변수입니다.

인스턴스 속성은 생성자 내부에서만 생성되는 변수입니다.

이 두 가지의 주요 차이점은 범위입니다. 즉, 인스턴스 객체와 클래스 모두에서 클래스 속성에 액세스할 수 있습니다. 반면에 인스턴스 속성은 인스턴스 객체에서만 액세스할 수 있습니다.

game = BaseGame(5)

# Accessing game message lenght class attr from class
print(game.message_lenght) # 60

# Accessing the message_lenght class attr from class
print(BaseGame.message_lenght)  # 60

# Accessing the points instance attr from instance
print(game.points) # 0

# Accesing the points instance attribute from class
print(BaseGame.points) # Attribute error

다른 문서에서 이 주제에 대해 자세히 알아볼 수 있습니다. 그것을 읽으려면 연락을 유지하십시오.

get_numeric_input 함수는 사용자가 숫자가 아닌 입력을 제공하지 못하도록 하는 데 사용됩니다. 알다시피 이 메서드는 숫자 입력을 받을 때까지 사용자에게 묻도록 설계되었습니다. 나중에 자녀의 수업에서 사용할 것입니다.

인쇄 방법을 사용하면 게임에서 이벤트가 발생할 때마다 동일한 것을 인쇄하는 반복을 저장할 수 있습니다.

  iPhone에서 시크릿 기록을 보는 방법

마지막으로 run 메서드는 임의 곱셈 및 테이블 곱셈 클래스가 사용자와 상호 작용하고 모든 기능을 작동시키는 데 사용하는 래퍼일 뿐입니다.

자녀의 수업 만들기

앱의 구조와 일부 기능을 설정하는 부모 클래스를 만들었으면 상속의 힘을 사용하여 실제 게임 모드 클래스를 만들 차례입니다.

무작위 곱셈 클래스

이 클래스는 게임의 “첫 번째 모드”를 실행합니다. 물론 사용자에게 1부터 10까지 임의의 작업을 요청할 수 있는 기능을 제공하는 random 모듈을 사용할 것입니다. 다음은 random(및 기타 중요한 모듈)에 대한 훌륭한 기사입니다 😉.

import random # Module for random operations
class RandomMultiplication(BaseGame):

    description = "In this game you must answer the random multiplication correctlynYou win if you reach 5 points, or lose if you lose all your lives"

    def __init__(self):
        # The numbers of points needed to win are 5
        # Pass 5 "points_to_win" argument
        super().__init__(5)

    def get_random_numbers(self):

        first_number = random.randint(1, 10)
        second_number = random.randint(1, 10)

        return first_number, second_number
        
    def run(self):
        
        # Call the upper class to print the welcome messages
        super().run()
        

        while self.lives > 0 and self.points_to_win > self.points:
            # Gets two random numbers
            number1, number2 = self.get_random_numbers()

            operation = f"{number1} x {number2}: "

            # Asks the user to answer that operation 
            # Prevent value errors
            user_answer = self.get_numeric_input(message=operation)

            if user_answer == number1 * number2:
                print("nYour answer is correctn")
                
                # Adds a point
                self.points += 1
            else:
                print("nSorry, your answer is incorrectn")

                # Substracts a live
                self.lives -= 1
            
            self.print_current_score()
            self.print_current_lives()
            
        # Only get executed when the game is finished
        # And none of the conditions are true
        else:
            # Prints the final message
            
            if self.points >= self.points_to_win:
                self.print_win_message()
            else:
                self.print_lose_message()

여기에 또 다른 대규모 수업이 있습니다 😅. 하지만 이전에 언급했듯이, 얼마나 많은 줄을 읽을 수 있고 효율적이냐가 중요한 것이 아닙니다. 그리고 Python의 가장 좋은 점은 개발자가 마치 일반 영어를 말하는 것처럼 깨끗하고 읽기 쉬운 코드를 만들 수 있다는 것입니다.

이 수업은 여러분을 혼란스럽게 할 수 있는 한 가지가 있지만 가능한 한 간단하게 설명하겠습니다.

    # Parent class
    def __init__(self, points_to_win, n_lives=3):
        "...
    # Child class
    def __init__(self):
        # The numbers of points needed to win are 5
        # Pass 5 "points_to_win" argument
        super().__init__(5)

자식 클래스의 생성자는 동시에 부모(BaseGame) 클래스를 참조하는 슈퍼 함수를 ​​호출합니다. 기본적으로 Python에게 다음과 같이 말합니다.

상위 클래스의 “points_to_win” 속성을 5로 채웁니다!

생성자 내부에서 super를 호출하기 때문에 super().__init__() 부분 내부에 self를 넣을 필요는 없습니다.

우리는 또한 run 메서드에서 super 함수를 사용하고 있으며 해당 코드에서 어떤 일이 발생하는지 확인할 것입니다.

    # Basic run method
    # Parent method
    def run(self):
        self.print_welcome_message()
        
        self.print_description()
    def run(self):
        
        # Call the upper class to print the welcome messages
        super().run()
        
        .....

부모 클래스의 run 메서드를 알 수 있듯이 환영 및 설명 메시지를 인쇄합니다. 그러나 해당 기능을 유지하고 하위 클래스에 추가 기능을 추가하는 것도 좋은 생각입니다. 그것에 따르면, 우리는 다음 조각을 실행하기 전에 부모 메서드의 모든 코드를 실행하기 위해 super를 사용합니다.

  iPhone을 사용하여 Apple Watch를 복원하는 방법

실행 기능의 다른 부분은 매우 간단합니다. 응답해야 하는 작업 메시지와 함께 사용자에게 번호를 요청합니다. 그런 다음 결과를 실제 곱셈과 비교하여 같으면 1점을 추가하고 생명 1점을 빼지 않습니다.

우리가 while-else 루프를 사용하고 있다는 것은 말할 가치가 있습니다. 이것은 이 기사의 범위를 초과하지만 며칠 안에 이에 대한 기사를 게시하겠습니다.

마지막으로 get_random_numbers는 지정된 범위 내에서 임의의 정수를 반환하는 random.randint 함수를 사용합니다. 그런 다음 두 개의 임의 정수로 구성된 튜플을 반환합니다.

무작위 곱셈 클래스

“두 번째 모드”는 구구단 형식으로 게임을 표시해야 하며 사용자가 적어도 2개의 테이블에 올바르게 답해야 합니다.

이를 위해 우리는 super의 힘을 다시 사용하고 부모 클래스 속성 points_to_win을 2로 수정합니다.

class TableMultiplication(BaseGame):

    description = "In this game you must resolve the complete multiplication table correctlynYou win if you solve 2 tables"
    
    def __init__(self):
        # Needs to complete 2 tables to win
        super().__init__(2)

    def run(self):

        # Print welcome messages
        super().run()

        while self.lives > 0 and self.points_to_win > self.points:
            # Gets two random numbers
            number = random.randint(1, 10)            

            for i in range(1, 11):
                
                if self.lives <= 0:
                    # Ensure that the game can't continue 
                    # if the user depletes the lives

                    self.points = 0
                    break 
                
                operation = f"{number} x {i}: "

                user_answer = self.get_numeric_input(message=operation)

                if user_answer == number * i:
                    print("Great! Your answer is correct")
                else:
                    print("Sorry your answer isn't correct") 

                    self.lives -= 1

            self.points += 1
            
        # Only get executed when the game is finished
        # And none of the conditions are true
        else:
            # Prints the final message
            
            if self.points >= self.points_to_win:
                self.print_win_message()
            else:
                self.print_lose_message()

알다시피 우리는 이 클래스의 run 메서드만 수정하고 있습니다. 그것이 상속의 마법입니다. 우리는 여러 곳에서 사용하는 논리를 한 번 작성하고 잊어버립니다 😅.

run 메서드에서 for 루프를 사용하여 1에서 10까지의 숫자를 가져오고 사용자에게 표시되는 작업을 빌드합니다.

생명이 고갈되거나 승리하는 데 필요한 포인트에 도달하면 다시 한 번 while 루프가 중단되고 승패 메시지가 표시됩니다.

예, 우리는 게임의 두 가지 모드를 만들었지만 지금까지 프로그램을 실행하면 아무 일도 일어나지 않습니다.

이제 모드 선택을 구현하고 해당 선택에 따라 클래스를 인스턴스화하여 프로그램을 마무리하겠습니다.

선택 구현

사용자는 플레이할 모드를 선택할 수 있습니다. 그럼 구현 방법을 알아보겠습니다.

if __name__ == "__main__":

    print("Select Game mode")

    choice = input("[1],[2]: ")

    if choice == "1":
        game = RandomMultiplication()
    elif choice == "2":
        game = TableMultiplication()
    else:
        print("Please, select a valid game mode")
        exit()

    game.run()

먼저 사용자에게 1 또는 2 모드 중에서 선택하도록 요청합니다. 입력이 유효하지 않으면 스크립트 실행이 중지됩니다. 사용자가 첫 번째 모드를 선택하면 임의 곱셈 게임 모드가 실행되고 두 번째 모드를 선택하면 테이블 곱셈 모드가 실행됩니다.

다음은 그 모습입니다.

결론

축하합니다, 당신은 단지 파이썬 앱 빌드 객체 지향 프로그래밍으로.

모든 코드는 다음에서 사용할 수 있습니다. Github 리포지토리.

이 문서에서는 다음을 배웠습니다.

  • Python 클래스 생성자 사용
  • OOP로 기능적인 앱 만들기
  • Python 클래스에서 수퍼 함수 사용
  • 상속의 기본 개념 적용
  • 클래스 및 인스턴스 특성 구현

행복한 코딩 👨‍💻

다음으로 생산성 향상을 위한 최고의 Python IDE를 살펴보십시오.