데이터과학 삼학년

Inheritance and Subclass (상속과 서브 클래스) 본문

Python

Inheritance and Subclass (상속과 서브 클래스)

Dan-k 2020. 4. 6. 15:57
반응형

파이썬에서 부모클래스를 상속받는 서브 클래스의 개념에 대해 알아본다.

 

일단 class를 만드는 가장 큰 목적은 붕어빵을 찍어내는 틀처럼 같은 속성을 가지는 데이터 타입 생성에 대해 반복되는 코드를 줄이고, 필요에 따라 간략한 수정을 가능하도록 하는데 있다.

 

즉 class를 이용하면 불필요한 재활용 코드를 줄이고, 보다 깔끔하고, 명확하게 코드를 작성할 수 있다.

# -*- coding: utf-8 -*-

class Unit(object):
    def __init__(self, rank, size, life):
        self.name = self.__class__.__name__
        self.rank = rank
        self.size = size
        self.life = life
        
    def show_status(self):
        print('이름: {}'.format(self.name))
        print('등급: {}'.format(self.rank))
        print('사이즈: {}'.format(self.size))
        print('라이프: {}'.format(self.life))
        

class Goblin(Unit):
    pass

goblin_1 = Goblin('병사', 'Small', 100)

goblin_1.show_status()


==================
이름: Goblin
등급: 병사
사이즈: Small
라이프: 100

이처럼 Goblin 이라는 class는 Unit class를 상속받아 Unit에서 지정한 method를 모두 활용하여 쓸 수 있다.

단 Goblin은 부모 클래스인 Unit을 참조하여 실행된다.

 

여기서 Goblin class에서 __init__ 정보를 더 추가하고 싶으면 어떻게 할까? --> 메서드 오버라이드

이때는 아래 코드처럼 일일히 다시 메서드를 만들어 줄 수도 있지만....

이 방법은  클래스를 사용하는 의미가 전혀없음

# -*- coding: utf-8 -*-

class Unit(object):
    def __init__(self, rank, size, life):
        self.name = self.__class__.__name__
        self.rank = rank
        self.size = size
        self.life = life
        
    def show_status(self):
        print('이름: {}'.format(self.name))
        print('등급: {}'.format(self.rank))
        print('사이즈: {}'.format(self.size))
        print('라이프: {}'.format(self.life))
        

class Goblin(Unit):
    def __init__(self, rank, size, life, attack_type):
        self.name = self.__class__.__name__
        self.rank = rank
        self.size = size
        self.life = life
        self.attack_type = attack_type
        
    def show_status(self):
        print('이름: {}'.format(self.name))
        print('등급: {}'.format(self.rank))
        print('사이즈: {}'.format(self.size))
        print('라이프: {}'.format(self.life))
        print('공격 타입: {}'.format(self.attack_type))
        
goblin_1 = Goblin('병사', 'Small', 100, '근접 공격')

goblin_1.show_status()


==================
이름: Goblin
등급: 병사
사이즈: Small
라이프: 100
공격 타입: 근접 공격

이런 경우에는 super() 함수를 사용하여 이미 부모 클래스에서 정의된 메소드를 호출하여 같은 코드를 반복하지 않도록 한다. super() 함수를 사용하여 중복된 코드를 줄여 보겠습니다.

 

1. super(<자신의 class명>, self).<부모클래스에서 불러올메서드명>

2. super().<부모클래스에서 불러올메서드명>

두가지 방법 모두 사용 가능

# -*- coding: utf-8 -*-

class Unit(object):
    def __init__(self, rank, size, life):
        self.name = self.__class__.__name__
        self.rank = rank
        self.size = size
        self.life = life
        
    def show_status(self):
        print('이름: {}'.format(self.name))
        print('등급: {}'.format(self.rank))
        print('사이즈: {}'.format(self.size))
        print('라이프: {}'.format(self.life))
        

class Goblin(Unit):
    def __init__(self, rank, size, life, attack_type):
        super(Goblin, self).__init__(rank, size, life)
        self.attack_type = attack_type
        
    def show_status(self):
        super(Goblin, self).show_status()
        print('공격 타입: {}'.format(self.attack_type))
        
goblin_1 = Goblin('병사', 'Small', 100, '근접 공격')

goblin_1.show_status()
# -*- coding: utf-8 -*-

class Unit(object):
    def __init__(self, rank, size, life):
        self.name = self.__class__.__name__
        self.rank = rank
        self.size = size
        self.life = life
        
    def show_status(self):
        print('이름: {}'.format(self.name))
        print('등급: {}'.format(self.rank))
        print('사이즈: {}'.format(self.size))
        print('라이프: {}'.format(self.life))
        

class Goblin(Unit):
    # damage 속성 추가
    def __init__(self, rank, size, life, attack_type, damage):
        super(Goblin, self).__init__(rank, size, life)
        self.attack_type = attack_type
        self.damage = damage
        
    def show_status(self):
        super(Goblin, self).show_status()
        print('공격 타입: {}'.format(self.attack_type))
        # 오버라이드 메소드
        print ('데미지: {}'.format(self.damage))
        
        
    # 공격 메소드 추가
    def attack(self):
        print('[{}]이 공격합니다! 상대방 데미지({})'.format(self.name, self.damage))
        

class SphereGoblin(Goblin):
    def __init__(self, rank, size, life, attack_type, damage, sphere_type):
        super(SphereGoblin, self).__init__(rank, size, life, attack_type, damage)
        self.sphere_type = sphere_type
        
    def show_status(self):
        super(SphereGoblin, self).show_status()
        print('창 타입: {}'.format(self.sphere_type))
        

sphere_goblin_1 = SphereGoblin('병사', 'Small', 100, '레인지 공격', 10, '긴 창')

sphere_goblin_1.show_status()


========================
이름: SphereGoblin
등급: 병사
사이즈: Small
라이프: 100
공격 타입: 레인지 공격
데미지: 10
창 타입: 긴 창

이렇게 만들수 있다.

hero와 같이 새로 class를 만들거나 에러관련 메서드도 추가하면 아래와 같이 서브 클래스를 응용할 수 있다.

# -*- coding: utf-8 -*-

class Unit(object):
    def __init__(self, rank, size, life):
        self.name = self.__class__.__name__
        self.rank = rank
        self.size = size
        self.life = life
        
    def show_status(self):
        print('이름: {}'.format(self.name))
        print('등급: {}'.format(self.rank))
        print('사이즈: {}'.format(self.size))
        print('라이프: {}'.format(self.life))
        

class Goblin(Unit):
    # damage 속성 추가
    def __init__(self, rank, size, life, attack_type, damage):
        super(Goblin, self).__init__(rank, size, life)
        self.attack_type = attack_type
        self.damage = damage
        
    def show_status(self):
        super(Goblin, self).show_status()
        print('공격 타입: {}'.format(self.attack_type))
        # 오버라이드 메소드
        print ('데미지: {}'.format(self.damage))
        
        
    # 공격 메소드 추가
    def attack(self):
        print('[{}]이 공격합니다! 상대방 데미지({})'.format(self.name, self.damage))
        

class SphereGoblin(Goblin):
    def __init__(self, rank, size, life, attack_type, damage, sphere_type):
        super(SphereGoblin, self).__init__(rank, size, life, attack_type, damage)
        self.sphere_type = sphere_type
        
    def show_status(self):
        super(SphereGoblin, self).show_status()
        print('창 타입: {}'.format(self.sphere_type))
        
        
class Hero(Unit):
    def __init__(self, rank, size, life, goblins=None):
        super(Hero, self).__init__(rank, size, life)
        if goblins is None:
            self.goblins = []
        else:
            self.goblins = goblins
            
    def show_own_goblins(self):
        num_of_goblins = len([x for x in self.goblins if isinstance(x, Goblin)])
        num_of_sphere_goblins = len([x for x in self.goblins if isinstance(x, SphereGoblin)])
        print('현재 영웅이 소유한 고블린은 {}명, 창 고블린은 {}명입니다.'.format(num_of_goblins, num_of_sphere_goblins))
        
    def make_goblins_attack(self):
        for goblin in self.goblins:
            goblin.attack()
            
    def add_goblins(self, new_goblins):
        for goblin in new_goblins:
            if goblin not in self.goblins:
                self.goblins.append(goblin)
            else:
                print('이미 추가된 고블린입니다.')

            
    def remove_goblins(self, old_goblins):
        for goblin in old_goblins:
            try:
                self.goblins.remove(goblin)
            except:
                print('소유하고 있지 않은 고블린입니다.')
        

# 고블린 오브젝트 생성
goblin_1 = Goblin('병사', 'Small', 100, '근접 공격', 15)
goblin_2 = Goblin('병사', 'Small', 100, '근접 공격', 15)
sphere_goblin_1 = SphereGoblin('병사', 'Small', 100, '레인지 공격', 10, '긴 창')
        
# 영웅 오브젝트 생성 후, 고블린 오브젝트 할당       
hero_1 = Hero('영웅', 'Big', 300, [goblin_1, goblin_2, sphere_goblin_1])

# 새로운 고블린 생성
goblin_3 = Goblin('병사', 'Small', 100, '근접 공격', 20)
sphere_goblin_2 = SphereGoblin('병사', 'Small', 100, '레인지 공격', 5, '긴 창')

print('# 새로운 고블린 추가 전')
hero_1.show_own_goblins()
hero_1.make_goblins_attack()

# 새로운 고블린 추가
hero_1.add_goblins([goblin_3, sphere_goblin_2])

print('\n# 새로운 고블린 추가 후')
hero_1.show_own_goblins()
hero_1.make_goblins_attack()

# 추가한 고블린 삭제
hero_1.remove_goblins([goblin_3, sphere_goblin_2])

print('\n# 추가한 고블린 삭제 후')
hero_1.show_own_goblins()
hero_1.make_goblins_attack()

# 영웅에게 소유되지 않은 고블린 생성
goblin_4 = Goblin('병사', 'Small', 100, '근접 공격', 20)

# 이미 소유한 고블린 추가
print('\n# 에러 메세지 발생')
hero_1.add_goblins([goblin_1])
hero_1.remove_goblins([goblin_4])


====================================
# 새로운 고블린 추가 전
현재 영웅이 소유한 고블린은 3명, 창 고블린은 1명입니다.
[Goblin]이 공격합니다! 상대방 데미지(15)
[Goblin]이 공격합니다! 상대방 데미지(15)
[SphereGoblin]이 공격합니다! 상대방 데미지(10)

# 새로운 고블린 추가 후
현재 영웅이 소유한 고블린은 5명, 창 고블린은 2명입니다.
[Goblin]이 공격합니다! 상대방 데미지(15)
[Goblin]이 공격합니다! 상대방 데미지(15)
[SphereGoblin]이 공격합니다! 상대방 데미지(10)
[Goblin]이 공격합니다! 상대방 데미지(20)
[SphereGoblin]이 공격합니다! 상대방 데미지(5)

# 추가한 고블린 삭제 후
현재 영웅이 소유한 고블린은 3명, 창 고블린은 1명입니다.
[Goblin]이 공격합니다! 상대방 데미지(15)
[Goblin]이 공격합니다! 상대방 데미지(15)
[SphereGoblin]이 공격합니다! 상대방 데미지(10)

# 에러 메세지 발생
이미 추가된 고블린입니다.
소유하고 있지 않은 고블린입니다.

 

출처 : http://schoolofweb.net/blog/posts/%ED%8C%8C%EC%9D%B4%EC%8D%AC-oop-part-5-%EC%83%81%EC%86%8D%EA%B3%BC-%EC%84%9C%EB%B8%8C-%ED%81%B4%EB%9E%98%EC%8A%A4inheritance-and-subclass/

 

SchoolofWeb :: 파이썬 - OOP Part 5. 상속과 서브 클래스(Inheritance and Subclass)

파이썬 객체 지향 프로그래밍(Object Oriented Programming) 강좌 - Part 5. 상속과 서브 클래스(Inheritance and Subclass)

schoolofweb.net

 

728x90
반응형
LIST
Comments