Programming/Python

[Python 3.7] 파이썬 다중 상속과 추상 클래스

Nirsa 2020. 2. 7. 14:10
반응형

 

  • 다중 상속

다중 상속은 말 그대로 여러 부모 클래스들로부터 상속 받는것을 말하는데 아래는 다중 상속 중 대표적으로 나오는 다이아몬드 상속이지만, 다이아몬드 상속은 문제가 굉장히 많아서 Diamond of Death 라고도 부릅니다.

 

아래 이미지와 같은 다중 상속으로 코드를 만들텐데, 다중 상속은 그냥 상속에서 부모 클래스를 여러개 쓴다는 차이밖에 없어서 자세한 설명은 생략 하겠습니다. 상속의 개념만 잡혀 있다면 코드만 보고도 이해하고 넘어가실 수 있으실 겁니다.

class parent_class1:
    def parent1(self):
        print('부모 클래스1 입니다.')

class parent_class2:
    def parent2(self):
        print('부모 클래스2 입니다.')

class child_class(parent_class1, parent_class2):
    def child(self):
        print('자식 클래스 입니다.')

test = child_class()

# 자식 클래스의 child 메소드 호출
test.child()

# 부모 클래스2의 parent2 메소드 호출
test.parent2()

# 부모 클래스 1의 parent1 메소드 호출
test.parent1()

결과값 : 자식 클래스 입니다.
결과값 : 부모 클래스2 입니다.
결과값 : 부모 클래스1 입니다.

 

  • 추상 클래스(abstract class)

추상 클래스의 특징은 크게 3가지가 있습니다.

  1. 추상 클래스는 인스턴스를 생성할 수 없다.
  2. 자식 클래스들이 각각의 독립된 공통적인 기능을 갖출 때 사용 한다.
  3. 각각의 독립된 공통적인 기능이 값을 공유하면 안되므로 구현하지 않은 빈 메소드를 사용 한다.

말 그대로 무엇인가 확립되지 않고 추상적으로 사용되는 클래스 입니다.

이전에 파이썬의 클래스에 대해 설명할때 사용했던 게임 예시를 한번 더 들어보자면, 각각의 클래스(직업, 전사 마법사 궁수 등)은 각각 독립된 공통적인 기능(힘, 민첩, 지력, 운, 물리공격력, 마법공격력)을 가지고 있습니다.

모든 직업이 똑같은 속성과 기능(메소드) 사용하기는 하나 이 안에 들어가는 값들은 직업별로 달라야할 것 입니다.

* 단순히 이해하기 쉽게 하기 위한 예시일 뿐입니다.

 

 

위의 그림을 본 후 아래 코드를 이해하시면 편하실겁니다.

우선 추상 클래스를 사용하기 위해선 abc 모듈을 가져와야 합니다. (abc모듈은 abstract base class 약자이며 기본적으로 파이썬에 들어있습니다) abc모듈을 가져온 후 사용할 추상 클래스명의 옆에 (metaclass=ABCMeta) 를 적어주고, 메소드 위에 @abstractmethod 를 적어서 추상 메소드임을 정의 해줍니다.

자식 클래스에서 기능을 구현하기 위해 추상 메소드는 pass 를 사용하여 빈 메소드로 해줍니다.

from abc import *

# 추상 클래스
class Jobs(metaclass=ABCMeta):

# 추상 메소드
    @abstractmethod
    def stats(self):
        pass

    @abstractmethod
    def item(self):
        pass

class Warrior(Jobs):
    def stats(self, str, dex, int, luk, ad, ap):
        self.str = str
        self.dex = dex
        self.int = int
        self.luk = luk
        self.ad = ad
        self.ap = ap
        print('전사 직업 능력치')
        print('힘: {0}'.format(self.str, self.dex))
        print('민첩: {0}'.format(self.dex))
        print('지력: {0}'.format(self.int))
        print('운: {0}'.format(self.luk))
        print('물리 공격력: {0}'.format(self.ad))
        print('마법 공격력: {0}'.format(self.ap))

    def item(self):
        print('소지중인 아이템: 검')

class Wizard(Jobs):
    def stats(self, str, dex, int, luk, ad, ap):
        self.str = str
        self.dex = dex
        self.int = int
        self.luk = luk
        self.ad = ad
        self.ap = ap
        print('마법사 직업 능력치')
        print('힘: {0}'.format(self.str))
        print('민첩: {0}'.format(self.dex))
        print('지력: {0}'.format(self.int))
        print('운: {0}'.format(self.luk))
        print('물리 공격력: {0}'.format(self.ad))
        print('마법 공격력: {0}'.format(self.ap))

    def item(self):
        print('소지중인 아이템: 지팡이')

class Archer(Jobs):
    def stats(self, str, dex, int, luk, ad, ap):
        self.str = str
        self.dex = dex
        self.int = int
        self.luk = luk
        self.ad = ad
        self.ap = ap
        print('궁수 직업 능력치')
        print('힘: {0}'.format(self.str))
        print('민첩: {0}'.format(self.dex))
        print('지력: {0}'.format(self.int))
        print('운: {0}'.format(self.luk))
        print('물리 공격력: {0}'.format(self.ad))
        print('마법 공격력: {0}'.format(self.ap))

    def item(self):
        print('소지중인 아이템: 활')

# 전사 능력치        
test1 = Warrior()
test1.stats(30, 10, 10, 10, 40, 10)
# 전사가 소지중인 아이템
test1.item()

# 마법사 능력치
test2 = Wizard()
test2.stats(10, 10, 30, 10, 10, 50)
# 마법사가 소지중인 아이템
test2.item()

# 궁수 능력치
test3 = Archer()
test3.stats(10, 30, 10, 10, 50, 10)
# 궁수가 소지중인 아이템
test3.item()

이제 위의 코드를 실행해보시면 모두 같은 부모 클래스를 사용하지만 직업별로 각자 다른 능력치를 출력 합니다.
이와 같이 자식 클래스들이 각각의 독립된 공통적인 기능을 갖추지만 공통적인 기능이 값을 공유하면 안되기 때문에 구현하지 않은 빈 메소드(추상 메소드)로 사용 됩니다.

아니면 어떠한 관계로 인해 특정한것을 표현하기 위해서 무조건 부모 클래스가 필요하고, 부모 클래스는 구체적이지 않고 어떠한 추상적인 개념일 때 사용할수도 있습니다.

그리고 추상 클래스를 사용할때는 자식 클래스의 메소드와 추상 클래스의 메소드가 일치 해야 합니다.

 

반응형