ABOUT ME

IT와 컴퓨터 관련 팁, 파이썬 등과 아파트 정보, 일상적인 경험 등의 생활 정보를 정리해서 올리는 개인 블로그

  • 파이썬 클래스 연습 - 이즈리얼, 리신, 몬스터 예시로 알아보기
    코딩 연습 2022. 6. 4. 11:22
    반응형

    [파이썬 클래스 연습] 객체 지향 개발 언어 스터디 중 난해하다고 하는 클래스 개념을 이해하기 위해 패스트캠퍼스의 파이썬 웹 개발에서 이즈리얼, 리신, 몬스터 예시로 설명하는 '클래스 개념' 강의 내용을 정리했다.

     

     

    클래스를 사용하는 이유 - RPG 게임을 활용하여 설명

     

    ■ 클래스를 사용하지 않았을 때

    - 공격 함수를 하나 만들고 챔피언 '이즈리얼', '리신'이 이를 사용한다.

    # 공격 함수
    def basic_attack(name, attack):
        print(f'{name} 기본 공격: {attack}')
    
    champion1_name = '이즈리얼'
    champion1_health = 700
    champion1_attack = 90
    print(f'{champion1_name}님 소환사의 협곡에 오신 것을 환영합니다.')
    basic_attack(champion1_name, champion1_attack)
    
    champion2_name = '리신'
    champion2_health = 800
    champion2_attack = 95
    print(f'{champion2_name}님 소환사의 협곡에 오신 것을 환영합니다.')
    basic_attack(champion2_name, champion2_attack)
    
    
    [실행 결과]
    이즈리얼님 소환사의 협곡에 오신 것을 환영합니다.
    이즈리얼 기본 공격: 90
    리신님 소환사의 협곡에 오신 것을 환영합니다.       
    리신 기본 공격: 95

     

    - 챔피언 '야스오' 하나를 더 만든다.

    champion3_name = '야스오'
    champion3_health = 800
    champion3_attack = 95
    print(f'{champion3_name}님 소환사의 협곡에 오신 것을 환영합니다.')
    basic_attack(champion3_name, champion3_attack)
    
    
    [실행 결과]
    야스오님 소환사의 협곡에 오신 것을 환영합니다.     
    야스오 기본 공격: 95

     

    클래스를 사용하지 않을 때는 챔피언을 추가할 때마다 5줄의 코딩이 추가되었다.

     

     

    ■ 클래스를 사용할 때

    ## Champion 클래스
    class Champion:
        def __init__(self, name, health, attack):
            self.name = name
            self.health = health
            self.attack = attack
            print(f'{self.name}님 소환사의 협곡에 오신 것을 환영합니다.')
        
        def basic_attack(self):
            print(f'{self.name} 기본 공격: {self.attack}')
    
    
    # 챔피언 이즈리얼 객체 생성
    champion1_ezreal = Champion('이즈리얼', 700, 90) 
    champion1_ezreal.basic_attack()
    
    # 챔피언 리신 객체 생성
    champion2_leesin = Champion('리신', 800, 95)
    champion2_leesin.basic_attack()
    
    
    [실행 결과]
    이즈리얼님 소환사의 협곡에 오신 것을 환영합니다.   
    이즈리얼 기본 공격: 90
    리신님 소환사의 협곡에 오신 것을 환영합니다.       
    리신 기본 공격: 95

     

    - 챔피언 '야스오' 객체를 만든다.

    # 객체 추가
    champion3_yasuo = Champion('야스오', 770, 96)
    champion3_yasuo.basic_attack()
    
    
    [실행 결과]
    야스오님 소환사의 협곡에 오신 것을 환영합니다.     
    야스오 기본 공격: 96

     

    챔피언 1,000개를 구현한다면, 
    클래스 미사용 시, 코드수 5줄 * 1,000개 = 5,000줄
    클래스 사용 시, 2줄 * 1,000개 = 2,000줄

     

    클래스를 사용하지 않는 경우는 챔피언을 추가할 때마다 동일한 코드량을 추가하지만, 클래스를 사용할 때는 객체만 만들면 되기 때문에 수백수천의 많은 챔피언을 만든다고 가정하면 클래스를 이용하는 방식이 더 효율적이다. (중복 코드 최소화)

     

     

    ■ 클래스의 효용성 측면과 클래스 생성자, 상속, 오버라이딩에 대해 설명

    # Monster 클래스
    class Monster:
        def __init__(self, health, attack, speed):  # 속성 초기화
            self.health = health
            self.attack = attack
            self.speed = speed
    
        def decrease_health(self, num):  # 체력 감소
            self.health -= num
    
        def get_health(self):  # 남은 체력 얻기
            return self.health
    
    
    goblin = Monster(800, 100, 300)
    wolf =  Monster(1000, 300, 400)
    
    goblin.decrease_health(50)
    print(goblin.get_health())
    
    
    
    [실행 결과]
    750
    • Monster 클래스 내에는 __init__() (이를 생성자라 함), decrease_health(), get_health() 메서드가 있다. 
    • goblin과 wolf 객체를 만들 때, 속성 초기화를 위해서 생성자에 매개변수 3개(health, attack, speed)를 넣어 생성했다.
    • 생성된 객체 goblin이 decrease_health() 메서드를 호출(체력 50 사용)하였고, 이를 확인하기 위해 get_health() 메서드를 호출했다.
    • wolf도 goblin처럼 객체를 만들어서 메서드를 호출할 수 있다.

     

    # 클래스 생성자

    • 생성자 메서드 __init__()은 클래스로 인스턴스(객체)를 만들 때 자동으로 가장 먼저 호출되는 메서드이다.
    • 생성자 메서드에는 매개변수가 0 ~ n개로 설정할 수 있다.
    • 생성자 메서드의 매개변수를 통해 클래스의 속성들을 초기화시킨다.
    • 매개변수 self는 클래스로 생성되는 인스턴스(객체) 자신, 즉 goblin 또는 wolf를 지칭하는 특수한 매개변수이다.

     

    good4me.co.kr

     

    상속(inheritance)과 메서드 오버라이딩

    # 상속을 활용하는 이유

     

    - 캐릭터를 키워서 몬스터를 잡고 레벨업을 하고 아이템을 얻는 RPG 게임에서 몬스터의 종류(땅 몬스터, 물 몬스터, 공중 몬스터,...)가 여러 개 있다고 했을 때, 

    • 각각의 몬스터에 대해 속성과 메서드를 지정하는 코드를 만든다면 엄청난 코드를 작성해야 하고, 코드에 문제가 발생했을 때 유지보수를 위한 많은 노력과 시간이 들게 된다.
    • 이러한 문제점을 해결하는 방법으로 이 몬스터들의 공통적인 특징을 하나의 클래스로 만들어서 사용하면 중복된 코드를 제거할 수 있다. 즉, 상속은 클래스들의 중복된 코드를 제거(코드의 효율적 재사용성 제고)하고 유지보수를 편리하게 할 수 있다.

    - 상속을 위해 부모 클래스와 자식 클래스를 만든다.

    ## 부모 클래스 정의
    class Parent_Monster:
        def __init__(self, name, health, attack):
            self.name = name
            self.health = health
            self.attack = attack
    
        def move(self):
            print(f'{[self.name]} 지상에서 이동하기')
        
    
    ## 자식 클래스 정의
    class Dragon(Parent_Monster):
        def move(self):
            print(f'{[self.name]} 날기')
    
    class Shark(Parent_Monster):
        def move(self):
            print(f'{[self.name]} 헤엄치기')
    
    class Wolf(Parent_Monster):
        pass
        
    
    dragon = Dragon('드래곤', 1000, 300)
    dragon.move()
    
    shark = Shark('샤크', 1500, 400)
    shark.move()
    
    wolf = Wolf('울프', 1200, 200)
    wolf.move()
    
    
    
    [실행 결과]
    ['드래곤'] 날기
    ['샤크'] 헤엄치기
    ['울프'] 지상에서 이동하기
    • Parent_Monster 클래스의 속성과 메서드 전체를 Dragon, Shark, Wolf 클래스가 상속을 받기 때문에 Parent_Monster의 속성인 name, health, attack을 Dragon, Shark, Wolf에서 그대로 사용할 수 있고,
    • Dragon과 Shark의 이동은 다르기 때문에 Parent_Monster의 move() 메서드를 각 자식 클래스에서 다시 만들어 사용할 수 있다. 이를 메서드 오버라이딩(메서드 재정의)라고 한다.

     

    생성자(__init__()) 오버라이딩, 클래스 변수

    # 생성자 오버라이딩(메서드 오버라이딩)

    • 드래곤의 스킬 향상을 위해 자식 클래스인 드래곤 클래스의 속성(인스턴스 속성)에 스킬 3개 추가하되, 드래곤이 스킬을 쓰면 속성 중에 무작위로 하나가 사용되도록 한다.
    • 스킬 속성을 주기 위해 드래곤 생성자 활용함 (부모 생성자 오버라이딩 포함)

     

    # 클래스 변수(클래스 자체의 속성)

    • 클래스 자체의 속성 변수이며, 인스턴스(객체)들이 모두 공유하는 변수임
    • 부모 클래스에서 사용하는 이유 : 몬스터가 너무 많으면 서버에 부하가 될 수 있으니 몬스터 개수에 제한을 걸기 위해 사용하는 변수
    import random
    
    ## 부모 클래스 정의
    class Parent_Monster:
        monster_max_num = 1000
        def __init__(self, name, health, attack):
            self.name = name
            self.health = health
            self.attack = attack
            self.get_monster_count()
            Parent_Monster.monster_max_num -= 1
            print(f'몬스터 생성수: {Parent_Monster.monster_max_num}')
    
        def move(self):
            print(f'{[self.name]} 지상에서 이동하기')
    
        def get_monster_count(self):
            if Parent_Monster.monster_max_num == 0:
                print('더이상 몬스터를 만들 수 없습니다!!')
                
    
    ## 자식 클래스 정의
    class Dragon(Parent_Monster):
        # 부모 생성자 오버라이딩
        def __init__(self, name, health, attack, skills):
            super().__init__(name, health, attack)  # 부모 생성자 호출        
            self.skills = skills[random.randint(0, len(skills)-1)]
    
        def move(self):
            print(f'{[self.name]} 날기')
    
        def skill(self):
            print(f'{[self.name]} 스킬 사용 - {self.skills}')
    
    
    class Shark(Parent_Monster):
        def move(self):
            print(f'{[self.name]} 헤엄치기')
    
    
    class Wolf(Parent_Monster):
        pass
    
    
    dragon = Dragon('드래곤', 1000, 300, ('불뿜기', '꼬리치기', '날개치기'))
    # 호출할 때 스킬을 입력할 수 있음
    dragon.move()
    dragon.skill()
    
    shark = Shark('샤크', 1500, 400)
    shark.move()
    
    wolf = Wolf('울프', 1200, 200)
    wolf.move()
    
    
    
    [실행 결과]
    몬스터 생성수: 999
    ['드래곤'] 날기
    ['드래곤'] 스킬 사용 - 날개치기
    몬스터 생성수: 998
    ['샤크'] 헤엄치기
    몬스터 생성수: 997
    ['울프'] 지상에서 이동하기
    • 클래스 변수에 접근할 때는 '클래스명.클래스변수명'으로 접근함(변수가  '__변수명'으로 선언하면 private 속성 변수)
    • 이 코드에서는 변수가 private 속성이 아니기 때문에 객체에서도 접근이 가능하다.(print(wolf.monster_max_num) 등으로 접근 가능)
    • 부모 생성자 오버라이딩 부분을 보면, 자식의 생성자에서 부모 생성자를 호출할 때 매개변수가 기본적으로 들어가고 skills라는 매개변수도 들어간다. 이 skills가 dragon만의 스킬 리스트가 되며, random.randint() 함수로 임의 지정이 되도록 했다.
    • dragon은 shark, wolf가 없는 skill() 메서드가 있고 이를 사용할 수 있다.
    • 몬스터의 생성 수를 체크하기 위해 부모 클래스에 클래스 변수(monster_max_num)를 삽입하고, 이를 고지하기 위해 생성자 메서드에서 출력하도록 했다.
    • 부모 클래스에 추가한 get_monster_count() 메서드는 메인 함수에서 몬스터 수를 확인한 후 프로그램을 종료할 때 출력하는 용도로 사용할 수 있다. (메인 함수에서 이 기능을 작성해도 됨)

     

    결론적으로, 클래스를 만들어서 사용하면, 몬스터를 수없이 쉽게 만들 수 있고 몬스터마다 특징을 줄 수 있다.

     

    [관련 포스팅 더보기]

    파이썬 클래스 연습 - 게임 아이템의 종류 구입, 사용, 버리기 메서드

     

    파이썬 클래스 연습 - 게임 아이템의 종류 구입, 사용, 버리기 메서드

    [파이썬 클래스 예제] 기 포스팅 한 [파이썬 클래스 연습 - 이즈리얼, 리신, 몬스터 예시로 알아보기]에 이어 패스트캠퍼스의 연습 문제(게임 아이템의 종류를 구분 문제)를 포스팅함 파이썬 클래

    goodthings4me.tistory.com

     

    반응형
Designed by goodthings4me.