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
)을 상속받아 구현해도 된다.
2. isinstance()
와 issubclass()
가 동작하는 세 가지 방법
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
existing classes나 built-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
일부 simple interfaces(ex.
Iterable
)의 경우, required methods가 정의되어 있고, 그것이None
으로 설정되지 않았다면 directly recognizable 하다.interface의 method 간 관계가 method name 만으로 추론될 수 있는 것은 아니기 때문에, complex interface의 경우에는 이 방법이 지원되지 않는다.
→ ex) class 내에 method
__getitem__
,__len__
,__iter__
가 존재한다고 해서Sequence
와Mapping
을 구분할 수 있지는 않다.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 method concrete subclasses(ex. list, dict)를 통해 구현되어야 한다. (italic으로 작성됨) concrete method
(mixin methods)concrete implementation을 가지고 있으므로, subclasses가 상속받아 사용할 수 있다. 각 top ABC들은 single special method를 가지고 있으며,
Collection
ABC는 다음의 세 가지 essential interfaces를 통합한다. 따라서 모든 collection은 다음을 구현해야 한다.essential interface 역할 Iterable
for문
, unpacking 및 iteration 관련 지원Sized
len
built-in function 지원Container
in
operator 지원concrete class는 실제로 interface를 상속받지 않아도 된다. 내부의 special method를 구현하면 interface를 만족한다고 간주된다.
Collection
의 세 가지 주요 specialization은 다음과 같다.specialization 설명 Sequence
list
,str과
같은 built-in의 interface를 formalizeMapping
dict
,collections.defaultdict
등으로 구현Set
built-in set
과fronzeset
의 interface
4. collections.abc
모듈의 UML 클래스 다이어그램
built-in classes는 virtual subclass로 정의되므로, subclass 관계는
collections.abc
에서 제공하는 classes에 대해서만 알아보자.
document
source code
ref: https://github.com/python/cpython/issues/76652 (consistency problem이 있다고 하니 참고용으로만 보기)
[1] Sequence
[2] Mapping
ABC / class 이름 | 상속 받는 ABC / built-in class | 소스 코드 |
---|---|---|
UserDict | MutableMapping | LINK |
ChainMap | MutableMapping | LINK |
Counter | dict | LINK |
OrderedDict | dict | LINK |
defaultdict | dict | LINK |
custom mapping을 구현하고 싶을 때는 위에 나타난 ABC를 subclassing 하는 것보다
collections.UserDict
를 확장하거나dict
를 wrap 하는 것이 편리하다.
collections.UserDict
나 standard library의 모든 concrete mapping classes는 모두 basicdict
를 encapsulate 하고 있으므로 hash table 기반으로 생성된다. 따라서, key가 hashable 해야 한다는 limitation을 공유하게 된다.
[3] Set
mutable 할 필요가 없으면
MutableXXX
가 아닌XXX
를 subclassing 하는 것이 정확하다.
References
- https://dongjunlee.github.io/code%20reading/CodeReading-3_ABC/#collectionsabc
- https://github.com/python/cpython/issues/76652
- https://sangmoonoh.medium.com/just-class-diagram-for-python-3-collections-abstract-base-classes-e1eafde6ad25
Additional Keyword
__subclasscheck__
, __subclasshook__
- https://www.geeksforgeeks.org/__subclasscheck__-and-__subclasshook__-in-python/
- https://docs.python.org/3/library/abc.html#abc.ABCMeta.__subclasshook__
- https://github.com/python/cpython/blob/e57ecf6bbc59f999d27b125ea51b042c24a07bd9/Lib/_py_abc.py#L108
- https://github.com/python/cpython/blob/e57ecf6bbc59f999d27b125ea51b042c24a07bd9/Lib/abc.py#L121