상속

클래스들의 공통된 속성과 메서드를 뽑아내서 부모 클래스를 만들고 이를 자식 클래스에서 상속 받아서 사용한다. 이렇게 하면 코드의 중복을 제거할 수 있고 유지보수가 편리해진다는 장점이 있다.

class Item:
    def __init__(self, name):
        self.name = name

    def pick(self):
        print(f'{self.name} 를 주웠습니다.')

    def discard(self):
        print(f'{self.name} 를 버렸습니다.')

class Weapon(Item):
    def __init__(self, name, damage):
        super().__init__(name)
        self.damage = damage

    def attack(self):
        print(f'{self.name} 를 이용해 {self.damage}로 공격합니다.')

class HealingItem(Item):
    def __init__(self, name, recovery_amount):
        super().__init__(name)
        self.recovery_amount = recovery_amount

    def use(self):
        print(f'{self.name} 를 이용해 {self.recovery_amount}를 회복합니다.')


w1 = Weapon('총', 110)
h1 = HealingItem('상처약', 20)
>>> w1.attack()
총 를 이용해 110로 공격합니다.
>>> h1.use()
상처약 를 이용해 20를 회복합니다.

추상 클래스

추상 클래스는 추상 메서드를 가질 수 있는데, 추상 메서드는 상속받는 자식 클래스에서 구현을 강제하도록 만드는 메서드이다. 추상 메서드를 하나라도 가지고 있는 클래스를 추상 클래스라고 한다.

추상클래스를 구현하기 위해서는 abc라는 모듈이 필요하고, 부모클래스에서 metaclass=ABCMeta라는 클래스를 상속받아야 한다. 추상 메서드는 @abstractmethod 데코레이터를 사용해야 한다.

from abc import *

class Item(metaclass=ABCMeta):
    def __init__(self, name):
        self.name = name

    def pick(self):
        print(f'{self.name} 를 주웠습니다.')

    def discard(self):
        print(f'{self.name} 를 버렸습니다.')

    @abstractmethod
    def use(self):
        pass

class Weapon(Item):
    def __init__(self, name, damage):
        super().__init__(name)
        self.damage = damage

    def attack(self):
        print(f'{self.name} 를 이용해 {self.damage}로 공격합니다.')
        
class HealingItem(Item):
    def __init__(self, name, recovery_amount):
        super().__init__(name)
        self.recovery_amount = recovery_amount

    def use(self):
        print(f'{self.name} 를 이용해 {self.recovery_amount}를 회복합니다.')

만약에 자식 클래스에서 use()라는 메서드를 구현하지 않았으면 아래와 같은 에러가 발생한다.

>>> w1 = Weapon('총', 110)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Weapon with abstract methods use

반면에 use()함수를 자식 클래스에서 구현하면 문제없이 잘 돌아가는 것을 확인할 수 있다.

>>> h1 = HealingItem('상처약', 20)
>>> print(h1. recovery_amount)
20