나무모에 미러 (일반/밝은 화면)
최근 수정 시각 : 2025-03-04 15:14:31

abc(Python)


파일:관련 문서 아이콘.svg   관련 문서: Python/문법/모듈
,
,
,
,
,

1. 개요2. 추상 기저 클래스3. 구성
3.1. ABCMeta
3.1.1. ABCMeta.\subclasshook3.1.2. ABCMeta.register
3.2. ABC3.3. abstractmethod3.4. get_cache_token3.5. update_abstractmethods3.6. 기타

1. 개요

abc — Abstract Base Classes

Python 표준 라이브러리에서 제공하는 추상 기저 클래스 관련 모듈이다.

2. 추상 기저 클래스

추상 기저 클래스(abstract base class, ABC)Python에서 추상 메서드를 이용해 클래스의 인터페이스를 만드는 방법 제공하고, 상속 관계를 직접 정의해 덕 타이핑을 지원하도록 설계된 클래스이다. JavaC#의 인터페이스와의 공통점도 있지만 차이점도 존재한다.

먼저 ABC는 추상 메서드를 이용해 클래스의 인터페이스를 정의하는 데 사용할 수 있다. 추상 메서드[abstract method]는 클래스가 일반 클래스인지 ABC인지 판별하는 기준으로, 클래스에 추상 메서드가 하나라도 존재한다면 ABC로 취급돼 인스턴스를 생성할 수 없다. 따라서 ABC를 상속받아 일반적인 클래스를 구현하려면 모든 추상 메서드를 같은 이름의 메서드로 덮어써야 한다. 반대로 일반적인 경우, 클래스가 특정 ABC의 서브클래스인지 확인함으로써, 사용할 수 있는 속성이나 메서드를 알아낼 수 있다.[1]

예를 들어 tuple, list, str처럼 열(列)을 나타내는 클래스는 모듈 collections.abc에서 정의된 ABC Sequence를 상속받아 구현할 수 있다. 이 경우 추상 메서드 __getitem____len__만 구현해도 앞의 기본 클래스가 가지는 여러 기능을 사용할 수 있다.

#!syntax python
from collections.abc import Sequence

class MySequence(Sequence):

    def __init__(self, sequence, /):
        super().__init__()
        self._items = tuple(sequence)           # tuple에 원소를 저장

    def __len__(self, /):
        return self._items.__len__()            # self._items의 길이

    def __getitem__(self, key, /):
        return self._items.__getitem__(key)     # self._items의 원소

    def __eq__(self, other, /):
        if isinstance(other, self.__class__):
            return self._items == other._items  # 원소가 같으면 같다
        else:
            return NotImplemented

sequence0 = MySequence([0, 1, 2, 3])
sequence1 = MySequence('456')
sequence2 = MySequence((0, 1, '2', '3', 4, 5, '6', '7'))
sequence3 = MySequence([0, 1, 2, 3, 1, 1, 2, 3])

# 다음을 모두 지원하며, 반환값은 모두 True이다.
3 in sequence0
5 not in sequence1
sequence0[2] == 2
sequence1[1:3] == ('5', '6')
sequence2[1:6:2] == (1, '3', 5)
len(sequence3) == 8
min(sequence0) == 0
max(sequence1) == '6'
sequence2.index('6') == 6
sequence3.count(1) == 3


ABC는 또한 상속 관계를 정의하는 기능도 제공한다. 예를 들어 모듈 collections.abc에서 정의된 ABC Hashable해시가능한 클래스에 관한 ABC로, 이를 직접 상속받지 않았어도 클래스에 메서드 __hash__None이 아닌 값으로 정의만 돼 있다면 서브클래스로 취급한다.

#!syntax python
from collections.abc import Hashable

class MyHashable:

    def __hash__(self, /):
        return 0

# MyHashable이 Hashable을 직접 상속받지는 않았으나,
# __hash__가 정의돼 있으므로 Hashable의 서브클래스로 취급된다.
hashable = MyHashable()
issubclass(MyHashable, Hashable)  # True
isinstance(hashable, Hashable)    # True

3. 구성

3.1. ABCMeta

ABCMeta

ABC의 메타클래스이다. 메타클래스는 클래스의 클래스로, type의 서브클래스이다. 만약 어떤 ABC를 구현하고자 한다면 해당 ABC의 메타클래스를 ABCMeta로 설정하면 된다.

#!syntax python
from abc import ABCMeta, abstractmethod

# 메서드 foo를 가지는 클래스에 관한 ABC
class HasFoo(metaclass=ABCMeta):

    @abstractmethod
    def foo(self):
        raise NotImplementedError()

class Foo(HasFoo):

    def foo(self):
        print('Hello, world!')

# HasFoo는 ABC이므로 인스턴스를 생성할 수 없다
# Foo는 HasFoo를 상속받아 메서드 foo를 덮어썼으므로 인스턴스를 생성할 수 있다
foo = Foo()
foo.foo()  # 'Hello, world!' 출력

3.1.1. ABCMeta.\subclasshook

@classmethod __subclasshook__(subclass)

클래스가 ABC의 서브클래스인지 판별하는 클래스 메서드이다. 사용자가 직접 정의할 수 있으며, 이를 통해 상속 관계를 사용자가 자유롭게 변형할 수 있다. 이 메서드를 구현할 때는 꼭 클래스 메서드로 구현해야 한다.

이 메서드의 반환값은 True, False, NotImplemented 중 하나여야 하는데, True는 해당 클래스가 ABC의 서브클래스임을 뜻하고, False는 그렇지 않음을 뜻하며, NotImplemented는 일반적인 상속 관계에 따라 판별해야 하는 경우를 뜻한다.

#!syntax python
from abc import ABCMeta, abstractmethod

# 메서드 foo를 가지는 클래스에 관한 ABC
class HasFoo(metaclass=ABCMeta):

    # 만약 클래스가 foo를 가지고 있고, 이게 None이 아니라면
    # 직접 상속받지 않았어도 HasFoo의 서브클래스로 취급한다
    @classmethod
    def __subclasshook__(cls, subclass):
        for base in subclass.__mro__:
            if 'foo' in base.__dict__:
                if base.__dict__['foo'] is None:
                    return NotImplemented
                else:
                    return True

        return NotImplemented

    @abstractmethod
    def foo(self):
        raise NotImplementedError()

# HasFoo를 상속받지 않았지만 foo가 구현된 클래스
class Foo:

    def foo(self):
        print('Hello, world!')

foo = Foo()
issubclass(Foo, HasFoo)  # True
isinstance(foo, HasFoo)  # True

3.1.2. ABCMeta.register

register(subclass)

특정 클래스를 ABC의 서브클래스로 등록하는 메서드이다. 기본 내장 자료형처럼 이미 구현된 클래스를 ABC의 서브클래스로 만들고 싶을 때 사용한다. 예를 들어, int는 모듈 numbers에서 정의된 ABC Integral을 직접 상속받지 않았지만 이의 서브클래스로 취급되는데, 이와 같은 경우에 사용할 수 있다. 이렇게 추가된 서브클래스를 가상 서브클래스[virtual subclass]라고 한다.

#!syntax python
from abc import ABCMeta, abstractmethod

# HasFoo가 구현되기 전에 구현된 클래스
class Foo:

    def foo(self):
        print('Hello, world!')

# 메서드 foo를 가지는 클래스에 관한 ABC
class HasFoo(metaclass=ABCMeta):

    @abstractmethod
    def foo(self):
        raise NotImplementedError()

HasFoo.register(Foo)  # Foo를 HasFoo의 서브클래스로 등록

foo = Foo()
issubclass(Foo, HasFoo)  # True
isinstance(foo, HasFoo)  # True

3.2. ABC

ABC

상속만으로 편하게 추상 ABC를 구현할 수 있도록 하는 ABC이다. ABCMeta를 이용해 ABC를 구현하려면 메타클래스를 설정해야 하지만, 단순히 ABC를 상속받는 방법으로도 ABC를 구현할 수 있다.

#!syntax python
from abc import ABC, abstractmethod

# 메서드 foo를 가지는 클래스에 관한 ABC
# ABC를 상속받아 구현
class HasFoo(ABC):

    @abstractmethod
    def foo(self):
        raise NotImplementedError()

class Foo(HasFoo):

    def foo(self):
        print('Hello, world!')

3.3. abstractmethod

@abstractmethod

추상 메서드를 생성하는 데커레이터(decorator)이다. 추상 메서드를 하나라도 가지는 클래스는 ABC로 취급된다. classmethod 등의 다른 데커레이터와 사용하는 경우에는 무조건 abstractmethod가 가장 안쪽에 위치해야 한다.

#!syntax python
from abc import ABCMeta, abstractmethod

class HasFoo(metaclass=ABCMeta):

    @abstractmethod
    def foo(self):
        raise NotImplementedError()

    # 다른 데커레이터와 사용하는 경우에는
    # abstractmethod가 가장 안쪽에 위치해야 한다

    @classmethod
    @abstractmethod
    def class_foo(cls):
        raise NotImplementedError()

    @staticmethod
    @abstractmethod
    def static_foo():
        raise NotImplementedError()

    @property
    @abstractmethod
    def property_foo(self):
        raise NotImplementedError()

3.4. get_cache_token

get_cache_token()

함수 ABCMeta.register로 등록된 가상 서브클래스 용 캐시를 식별하기 위한 토큰을 반환하는 함수이다.

3.5. update_abstractmethods

update_abstractmethods(cls)

클래스의 추상 메서드 현황을 다시 계산하는 함수이다. 클래스 생성 후 데커레이터 등의 방법을 통해 클래스의 추상 메서드가 구현됐거나 변경된 경우에 이 함수를 호출해야 한다. 이를 호출하지 않는다면 클래스의 추상 메서드가 클래스 생성 이후 모두 구현되더라도 인스턴스 생성이 불가능할 수도 있다.

3.6. 기타

@abstractclassmethod
@abstractstaticmethod
@abstractproperty

과거에 데커레이터 abstractmethod가 다른 데커레이터와 함께 사용할 수 없었을 때 사용했던 데커레이터이다. 현재는 다른 데터레이터와 함께 사용할 수 있으므로 사용하지 않는 것을 권장한다.
[1] 후술할 메서드 ABCMeta.register를 통해 필요한 기능을 구현하지 않은 클래스를 추상 기저 클래스의 서브클래스로 등록할 수 있지만, 권장되지는 않는다.

분류