본문 바로가기

Computer/Python

파이썬의 추상 클래스 (Abstract Class)

반응형

코드가 고도화되고 모듈화 되면서 클래스 상속을 이용하는 경우가 많습니다. 특히, 여러 메서드의 이름은 공유하지만 각 클래스 별로 기능을 다르게 구현해야 하는 경우도 많죠. 따라서 관련된 함수, 메서드를 하나의 단위로 묶어 응집성을 강화하고자 하는 방편으로 파이썬에서는 추상 클래스라는 기능을 제공합니다. "추상"이라는 말 그대로 디테일한 기능이 구현되어 있지 않지만 이 클래스를 상속해서 만드는 클래스들에 필수적으로 정의해야 할 변수, 메서드를 선언만 해놓은 것이죠. 파이썬에서는 abc (abstract base class) 라이브러리를 제공합니다. 먼저 모델의 이름과 사이즈를 선언해야 하는 추상 클래스를 선언하겠습니다.

from abc import ABCMeta, abstractmethod

class Model(metaclass=ABCMeta):
    @abstractmethod
    def create_model_id(self):
        pass

    def create_model_size(self):
        raise NotImplementedError

위 코드에서 "create_model_id" 메서드는 abstractmethod로 wrapping 되어 있고 "create_model_size" 메서드는 wrapping 되어 있지 않고 "NotImplementedError"만 발생하게끔 되어 있습니다. 이 상황에서 상속받은 클래스가 추상 메서드를 구현하지 않을 시에는 클래스를 로딩하는 단계에서부터 에러가 나게 됩니다. 즉, 추상 메서드로 선언된 메서드는 상속한 클래스에서 "반드시" 구현해야 하는 것이죠.

class Resnet(Model):
    def create_model_size(self):
        return '43Mb'
        
Resnet()
>>> TypeError                                 Traceback (most recent call last)
<ipython-input-6-74045de686d0> in <cell line: 1>()
----> 1 Resnet()

TypeError: Can't instantiate abstract class Resnet with abstract method create_model_id

반면에 추상 메서드가 아닌 메서드를 정의하지 않아도 별도의 에러가 발생하지는 않습니다. 다만 그 메서드를 호출하게 되면 구현하지 않았기 때문에 런타임에서 에러가 발생합니다. 

class MobileNet(Model):
    def create_model_id(self):
        return "mobilenet"

MobileNet()
>>> <__main__.MobileNet at 0x7f89c81e0910>

m = MobileNet()
m.create_model_size()
>>> NotImplementedError                       Traceback (most recent call last)
<ipython-input-11-cc6ddb600ed8> in <cell line: 2>()
      1 m = MobileNet()
----> 2 m.create_model_size()

<ipython-input-4-6ae136a37292> in create_model_size(self)
      5 
      6     def create_model_size(self):
----> 7         raise NotImplementedError

NotImplementedError:

결론적으로 추상 메서드로 지정을 하면 하위 클래스에서 반드시 구현해야 하지만 그렇지 않은 메서드는 런타임 상에서 에러가 나기 때문에 추상 메서드에 비해 제약이 완화된 형태로 볼 수 있습니다. 위에 예에서 "create_model_id" 메서드는 필수이지만 "create_model_size" 메서드는 옵션 (구현해도 되고 안 해도 되지만 안 한 상태에서 호출하면 런타임 에러가 발생한다.)이라고 볼 수 있습니다. 따라서 메서드의 중요도 및 사용처에 따라 유연하게 구현이 가능합니다.

반응형