pythonic - interface, abc

Kenneth·2021년 1월 4일
0

pythonic

목록 보기
2/6

python으로도 oop를 할 수 있습니다. 다른 언어와 좀 모양새가 다를 뿐.

혹시 이게 당연하다고 생각하지 않는 분들은 wikipedia의 python 문서 (링크)의 본문 최상단 혹은 우측 요약 테이블의 맨 위 paradigm 항목에 oop가 포함된 걸 확인하실 수 있습니다.

프로그래밍 언어의 패러다임이란게 따로 이론적으로 공부하는게 아니라 프로그래밍 언어라는 구현체를 통해서 접하게 되면, 해당 언어에서 발현된 특징을 패러다임의 일부로 오해하기 쉬운 부분이 있는 것 같습니다. 저도 아직도 그런 부분에 대해서 공부하고 있구요. 소프트웨어 마에스트로 과정 교육에서 모 대학 교수님이 scala 강의를 하시며 프로그래밍 패러다임과 프로그래밍 언어사에 대해 설명해주셨던게 생각납니다. 전기전자과에서는 들을 수 없는 강의라 꽤 재미있게 들었었는데. first class object나 tail recursion같은 언어적 특징을 표현하는 개념도 그때 처음 접했었습니다.

oop 스타일의 프로그래밍 경험은 짧지만 저는 oop 스타일로 짠 코드의 특징으로 무수히 많은 클래스와 인터페이스가 먼저 떠오릅니다. java + spring boot 서버 개발에서도, swift 앱 개발에서도 그랬으니까요.

그런데 python 에 인터페이스가 있었나요?

일단 명시적인, java나 swift에서 interface라고 할만한 무언가는 없는게 맞습니다. 가장 유사한건 abstract base class 이죠. 명확하게 구분되어있는 언어도 있지만, 기능적으로 함수 셋을 선언할 수 있다는 점에서 동일하죠.

하지만 python은 duck typing을 사용하죠. 타입에 민감하지 않습니다. 오리처럼 생겼고, 오리처럼 걷고, 오리처럼 꽥꽥대는 것이 있다면 그건 오리죠? 일일히 DNA 검사를 할 필요가 없습니다. 뭐, 가능성만 놓고 보면 오리와는 본질적으로 다른 외계에서 온 입에서 불을 뿜어내는 유사-오리-생물체일 수도 있습니다 (포켓몬?). 하지만 우리가 관심 있는 어떻게 생겼는가, 어떻게 걷는가, 어떻게 우는가 만 놓고 봤을때는 오리라고 해도 전혀 문제될 것이 없다는 말입니다. 마찬가지로, 무언가가 interface 처럼 함수를 정의하고, interface를 구현하려는 class에 해당 함수들이 정의되어있지 않을 때 에러를 던진다면 그건 interface라고 해도 무방합니다.

이 realpython 글에서는 python에서 interface처럼 작동하는 것을 만드는 몇 가지 방법을 소개합니다. __instancecheck__와 __subclasscheck__를 이용해서, 혹은 abc 모듈과 __subclasshook__을 이용해서 구현체에서 함수들을 정의하고 있는지 체크합니다. 원문 설명이 자세하니 최종적으로 어떤 형태가 되는지만 가져와보겠습니다.

# source: https://realpython.com/python-interface/#using-__subclasshook__

class FormalParserInterface(metaclass=abc.ABCMeta):
    @classmethod
    def __subclasshook__(cls, subclass):
        return (hasattr(subclass, 'load_data_source') and 
                callable(subclass.load_data_source) and 
                hasattr(subclass, 'extract_text') and 
                callable(subclass.extract_text) or 
                NotImplemented)

    @abc.abstractmethod
    def load_data_source(self, path: str, file_name: str):
        """Load in the data set"""
        raise NotImplementedError

    @abc.abstractmethod
    def extract_text(self, full_file_path: str):
        """Extract text from the data set"""
        raise NotImplementedError

class PdfParserNew(FormalParserInterface):
    """Extract text from a PDF."""
    def load_data_source(self, path: str, file_name: str) -> str:
        """Overrides FormalParserInterface.load_data_source()"""
        pass

    def extract_text(self, full_file_path: str) -> dict:
        """Overrides FormalParserInterface.extract_text()"""
        pass

사실 python 으로 백엔드 개발을 하면서 여러 dependency 소스코드를 봤지만, 이런 형태로 interface를 구현한 코드는 아직 보지 못했습니다. 제가 본 코드는 대개 일반 class를 구현하고, subclass에서 반드시 정의해야 하는 것이 있다면 assert로 체크하는 형태가 많았습니다. pure-oop 스타일의 코드 자체를 드물게 본 것 같습니다. 생각해보니까 pure-fp 스타일의 코드도 못 본 것 같네요. 애당초 python이 fp에 최적화된 언어도 아니니까요. 갑자기 분위기 haskell? 학술적인 의미에서 특정 스타일의 요소가 완성된 언어는 아닌 것 같고, 스크립트 언어의 자유로움 속에서 스타일을 명확히 지향하는건 개발자의 몫인 것 같습니다.

profile
개발자 + @

0개의 댓글