프로그래밍/python

파이썬 강좌 - python abc 추상 클래스

콘파냐 2022. 4. 8. 10:31

이 강의는 python3 문법입니다.
추상클래스라는 용어는 C++의 추상클래스와 비슷하게 이해할 수 있다. 자바(java)라면 interface라 볼 수 있다.

C++이나 JAVA를 몰라도 상관은 없다.

쉽게 말해 추상클래스는 메소드의 구체적인 구현이 없는 클래스를 말한다. 이런 클래스를 왜 만들까 한번 10초만 고민해보자.

추상클래스의 목적은 일종의 틀을 제공해주는 역할을 한다. 이 틀은 추상클래스를 상속하는 클래스들에게 특정 메소드의 구현을 강제하는 효과가 있다. 앞서 말한 C++의 추상클래스라면 메소드를 _순수 가상함수_라는 형식으로 정의하여 이를 상속하는 클래스들에게 순수 가상함수를 강제구현하도록 하는 지시를 하는 것이다. 자바의 경우는 interface가 같은 역할을 한다.

우선 본론에 들어가기 전에 파이썬에서 일반적인 상속을 알아보자.

# 부모 클래스
class Animal():
    def act(self):
        ... # 구현해 주세요.

# 자식 클래스
class Cat(Animal):
    def myAct(self):
        print("Do my Act!")


if __name__ == "__main__":
    Cat().myAct()

위 코드를 실행해보면 Do my Act!가 콘솔에 찍힌다. 얼핏 봐서는 이 코드가 문제가 있는 코드인지 모를 수 있다. 위 예는 간단하여 act가 하위클래스에 구현되지 않았다는 걸 알 수 있지만, 코드가 복잡해진다면 쉽게 발견하기 힘들 수 있다.

다시 말해, 이 코드의 문제점은 부모클래스(Animal)에서 선언한 act 메소드가 어디에서도 구현되지 않았다는 것이다. 그럼에도 이 코드는 잘 동작하며 자식클래스(Cat)는 부모클래스의 코드를 들춰보지 않는 한 act를 구현해야할 지도 모르기 때문에 Animal 추상클래스를 제공한 자의 의도에 맞지 않는 구현이 된 것이다.

추상클래스의 중요성

우선 추상클래스를 인터페이스와 같다고 생각하자. 인터페이스란 일종의 포맷 스펙이다. 사용자는 특정 물건을 사용할 때 인터페이스가 맞는지 확인해야 한다. 인터페이스는 형식을 강제한다. 우리가 전기를 쓸 때 꼽는 돼지코의 모양이 동일한 규격인 것 처럼.
다시 위 예로 돌아가자.
누군가 Animal 클래스를 만들 때 act 메소드가 반드시 구현되길 원한다고 가정하자. 앞서 예제와 같은 방식으로는 abc 메소드의 구현을 강제할 수 없다.
이를 강제하기 위해 파이썬은 abc모듈을 제공한다. abcabstract class의 약자다.

from abc import ABCMeta, abstractmethod

class Animal(metaclass= ABCMeta):
    @abstractmethod
    def act(self):
        ...

class Cat(Animal):
    def myAct(self):
        print("Do my Act!")

if __name__ == "__main__":
    Cat().myAct()
  1. 앞서 예제의 Animal 클래스에 ABCMeta 설정을 하였다.
  2. 상속받는 클래스에서 구현을 강제할 메소드에 @abstratmethod 장식자를 추가하였다.
  • 이제 다시 코드를 실행해보면 에러가 발생한다.
    Traceback (most recent call last):
    File "abc.ex.py", line 13, in <module>
      Cat().myAct()
    TypeError: Can't instantiate abstract class Cat with abstract methods act

abc 추상 메소드를 가진 Cat 추상 클래스를 초기화 할 수 없다고?
이 에러는 C++에서도 비슷한 상황에서 비슷한 에러가 난다. 그냥 abc 추상메소드를 구현하면 해결된다고 생각하자.
주의할 점은 이 에러는 클래스 정의단계에서는 발생하지 않는다. Cat()라는 객체 생성단계에서 발생하므로 주의해야한다.

추상 메소드의 구현

from abc import ABCMeta, abstractmethod

class Animal(metaclass= ABCMeta):
    @abstractmethod
    def act(self):
        ...

class Cat(Animal):
    def act(self):  # 추상메소드 구현
        print("Do my Act!")

if __name__ == "__main__":
    Cat().act()  

추상메소드를 구현하였다. 에러는 발생하지 않고 Do my Act! 가 깔끔하게 출력된다.

참고

metaclass=ABCMeta 가 아닌 ABC를 상속하여 구현해도 된다.

from abc import ABC, abstractmethod
class Animal(ABC):
    ...

모든 설명은 추상베이스클래스에 기반합니다.

반응형