Home [Python] 추상 기반 클래스(Abstract Base Class), collections.abc 모듈
Post
Cancel

[Python] 추상 기반 클래스(Abstract Base Class), collections.abc 모듈

1. collections.abc 모듈

1-1. 추상 기반 클래스(Abstract Base Class, ABC)

파이썬의 collections.abc 내장 모듈 안에는 컨테이너(container) 타입에 정의해야 하는 전형적인 메서드를 제공하는 추상 기반 클래스(abstract base class, ABC) 정의가 들어있다.

이러한 ABC는 인터페이스를 정의하는 방법을 제공함으로써 덕 타이핑을 보완한다.

실제로는 상속 관계가 아니지만 isinstance()issubclass()로는 True로 인식되는 virtual subclasses 개념을 도입한다.


1-2. collections.abc를 이용하여 커스텀 컨테이너 타입 정의하기

커스텀 컨테이너 타입을 정의할 때는 collections.abc 모듈에서 제공하는 ABC를 상속받아 정의된 abstract method를 구현하는 것을 권장한다.

해당 custom container 타입이 정상적으로 작동하기 위해 필요한 interface 및 method를 제대로 구현하도록 보장할 수 있다.

하지만 간단한 경우에는 built-in container 타입(ex. list, tuple, set, dict)을 상속받아 구현해도 된다.

관련 포스팅: [Better Way #43] 커스텀 컨테이너 타입은 collections.abc를 상속하라


2. isinstance()issubclass()가 동작하는 세 가지 방법

ref: https://docs.python.org/3/library/collections.abc.html

  1. newly written class의 경우, ABC를 직접 상속(direct inheritance)할 수 있으므로 직접 상속된 ABC와 비교한다.

    • 상속받은 interface에 정의된 abstract methods를 모두 구현해야 한다.
    • 나머지 mixin methods는 inheritance로부터 받아오거나 override 될 수 있다.
    • 그 외의 methods는 필요에 따라 추가될 수 있다.
    1
    2
    3
    4
    5
    
    class C(Sequence):                      # Direct inheritance
        def __init__(self): ...             # Extra method not required by the ABC
        def __getitem__(self, index):  ...  # Required abstract method
        def __len__(self):  ...             # Required abstract method
        def count(self, value): ...         # Optionally override a mixin method
    
    1
    2
    3
    4
    
    issubclass(C, Sequence)
    True
    isinstance(C(), Sequence)
    True
    


  2. existing classesbuilt-in classes의 경우, ABC의 virtual subclasses로 등록될 수 있으므로 등록된 ABC와 비교한다.

    • 모든 abstract methods모든 mixin methods를 포함한 전체 API를 구현해야 한다. 단, API의 나머지 부분에 의해 자동으로 추론될 수 있는 methods는 예외이다.

      아래 예제에서, class D__getitem__, __len__ method를 구현하므로, 본래 Sequence라면 구현해야 할 __contains__, __iter__, __reversed__ method를 구현하지 않아도 된다. (automatically inferred)

    • isinstance()issubclass()full interface가 구현되었는지 여부에 의존한다.

    1
    2
    3
    4
    5
    6
    7
    8
    
    class D:                                 # No inheritance
        def __init__(self): ...              # Extra method not required by the ABC
        def __getitem__(self, index):  ...   # Abstract method
        def __len__(self):  ...              # Abstract method
        def count(self, value): ...          # Mixin method
        def index(self, value): ...          # Mixin method
    
    Sequence.register(D)                     # Register instead of inherit
    
    1
    2
    3
    4
    
    issubclass(D, Sequence)
    True
    isinstance(D(), Sequence)
    True
    


  3. 일부 simple interfaces(ex. Iterable)의 경우, required methods가 정의되어 있고, 그것이 None으로 설정되지 않았다면 directly recognizable 하다.

    interface의 method 간 관계가 method name 만으로 추론될 수 있는 것은 아니기 때문에, complex interface의 경우에는 이 방법이 지원되지 않는다.

    → ex) class 내에 method __getitem__, __len__, __iter__가 존재한다고 해서 SequenceMapping을 구분할 수 있지는 않다.

    1
    2
    3
    
    class E:
        def __iter__(self): ...
        def __next__(next): ...
    
    1
    2
    3
    4
    
    issubclass(E, Iterable)
    True
    isinstance(E(), Iterable)
    True
    


3. 기본 Collection 타입

  • 위 UML의 class들은 ABC(abstract base classes)이다.
  • ABC를 구성하는 method의 종류

    method 종류설명
    abstract methodconcrete subclasses(ex. list, dict)를 통해 구현되어야 한다. (italic으로 작성됨)
    concrete method
    (mixin methods)
    concrete implementation을 가지고 있으므로, subclasses가 상속받아 사용할 수 있다.
  • 각 top ABC들은 single special method를 가지고 있으며, Collection ABC는 다음의 세 가지 essential interfaces를 통합한다. 따라서 모든 collection은 다음을 구현해야 한다.

    essential interface역할
    Iterablefor문, unpacking 및 iteration 관련 지원
    Sizedlen built-in function 지원
    Containerin operator 지원

    concrete class는 실제로 interface를 상속받지 않아도 된다. 내부의 special method를 구현하면 interface를 만족한다고 간주된다.

  • Collection 세 가지 주요 specialization은 다음과 같다.

    specialization설명
    Sequencelist, str과 같은 built-in의 interface를 formalize
    Mappingdict, collections.defaultdict 등으로 구현
    Setbuilt-in setfronzeset의 interface


4. collections.abc 모듈의 UML 클래스 다이어그램

built-in classes는 virtual subclass로 정의되므로, subclass 관계는 collections.abc에서 제공하는 classes에 대해서만 알아보자.


ref: https://github.com/python/cpython/issues/76652 (consistency problem이 있다고 하니 참고용으로만 보기)



[1] Sequence

ABC 이름상속 받는 ABC소스 코드
UserStringSequenceLINK
UserListMutableSequenceLINK


[2] Mapping

ABC / class 이름상속 받는 ABC / built-in class소스 코드
UserDictMutableMappingLINK
ChainMapMutableMappingLINK
CounterdictLINK
OrderedDictdictLINK
defaultdictdictLINK


custom mapping을 구현하고 싶을 때는 위에 나타난 ABC를 subclassing 하는 것보다 collections.UserDict를 확장하거나 dict를 wrap 하는 것이 편리하다.

collections.UserDict나 standard library의 모든 concrete mapping classes는 모두 basic dict를 encapsulate 하고 있으므로 hash table 기반으로 생성된다. 따라서, key가 hashable 해야 한다는 limitation을 공유하게 된다.


[3] Set


mutable 할 필요가 없으면 MutableXXX가 아닌 XXX를 subclassing 하는 것이 정확하다.


References


Additional Keyword

__subclasscheck__, __subclasshook__

This post is licensed under CC BY 4.0 by the author.

[MySQL] 두 테이블의 Cartesian Product를 구하는 세 가지 방법

[Python] 정렬 기준 커스터마이징 하기