"abc" --- 추상 베이스 클래스
****************************

**소스 코드:** Lib/abc.py

======================================================================

이 모듈은, **PEP 3119**에서 설명된 대로, 파이썬에서 *추상 베이스 클래
스* (ABC) 를 정의하기 위한 기반 구조를 제공합니다; 이것이 왜 파이썬에
추가되었는지는 PEP를 참조하십시오. (ABC를 기반으로 하는 숫자의 형 계층
구조에 관해서는 **PEP 3141**과 "numbers" 모듈을 참고하십시오.)

"collections" 모듈은 ABC로부터 파생된 몇 가지 구상(concrete) 클래스를
가지고 있습니다; 이것은 물론 더 파생될 수 있습니다. 또한,
"collections.abc" 서브 모듈에는 클래스나 인스턴스가 특정 인터페이스를
(예를 들어, 해시 가능이거나 매핑이면) 제공하는지 검사하는 데 사용할 수
있는 ABC가 있습니다.

이 모듈은 ABC를 정의하기 위한 메타 클래스 "ABCMeta"와 상속을 통해 ABC
를 정의하는 대안적 방법을 제공하는 도우미 클래스 "ABC"를 제공합니다:

class abc.ABC

   "ABCMeta"를 메타 클래스로 가지는 도우미 클래스. 이 클래스를 사용하
   면, 때로 혼란스러운 메타 클래스를 사용하지 않고, 추상 베이스 클래스
   를 간단히 "ABC"에서 파생시켜서 만들 수 있습니다. 예를 들어:

      from abc import ABC

      class MyABC(ABC):
          pass

   "ABC" 의 형은 여전히 "ABCMeta" 이므로, "ABC"를 상속할 때는 메타 클
   래스 사용에 관한 일반적인 주의가 필요한데, 다중 상속이 메타 클래스
   충돌을 일으킬 수 있기 때문입니다. metaclass 키워드를 전달하고
   "ABCMeta"를 직접 사용해서 추상 베이스 클래스를 정의할 수도 있습니다
   , 예를 들어:

      from abc import ABCMeta

      class MyABC(metaclass=ABCMeta):
          pass

   버전 3.4에 추가.

class abc.ABCMeta

   추상 베이스 클래스 (ABC)를 정의하기 위한 메타 클래스.

   이 메타 클래스를 사용하여 ABC를 만듭니다. ABC는 직접 서브 클래싱 될
   수 있으며 믹스 인 클래스의 역할을 합니다. 관련 없는 구상 클래스(심
   지어 내장 클래스도)와 관련 없는 ABC를 "가상 서브 클래스"로 등록 할
   수 있습니다 -- 이들과 이들의 서브 클래스는 내장 "issubclass()" 함수
   에 의해 등록하는 ABC의 서브 클래스로 간주합니다. 하지만 등록하는
   ABC는 그들의 MRO (메서드 결정 순서)에 나타나지 않을 것이고, 등록하
   는 ABC가 정의한 메서드 구현도 호출할 수 없을 것입니다 ("super()"를
   통해서도 가능하지 않습니다). [1]

   "ABCMeta"를 메타 클래스로 생성된 클래스는 다음과 같은 메서드를 가집
   니다:

   register(subclass)

      이 ABC의 "가상 서브 클래스"로 *subclass* 를 등록합니다. 예를 들
      면:

         from abc import ABC

         class MyABC(ABC):
             pass

         MyABC.register(tuple)

         assert issubclass(tuple, MyABC)
         assert isinstance((), MyABC)

      버전 3.3에서 변경: 클래스 데코레이터로 사용할 수 있도록, 등록된
      subclass 돌려줍니다.

      버전 3.4에서 변경: "register()" 호출을 감지하려면,
      "get_cache_token()" 함수를 사용할 수 있습니다.

   추상 베이스 클래스에서 다음 메서드를 재정의할 수도 있습니다:

   __subclasshook__(subclass)

      (반드시 클래스 메서드로 정의되어야 합니다.)

      *subclass* 를 이 ABC의 서브 클래스로 간주할지를 검사합니다. 이것
      은, ABC의 서브 클래스로 취급하고 싶은 클래스마다 "register()"를
      호출할 필요 없이, "issubclass" 의 행동을 더 사용자 정의할 수 있
      음을 의미합니다. (이 클래스 메서드는 ABC의 "__subclasscheck__()"
      메서드에서 호출됩니다.)

      이 메서드는 "True", "False" 또는 "NotImplemented" 를 반환해야 합
      니다. "True" 를 반환하면, *subclass* 를 이 ABC의 서브 클래스로
      간주합니다. "False" 를 반환하면, *subclass* 를 ABC의 서브 클래스
      로 간주하지 않습니다. "NotImplemented" 를 반환하면, 서브 클래스
      검사가 일반적인 메커니즘으로 계속됩니다.

   이러한 개념들의 시연으로, 이 예제 ABC 정의를 보십시오:

      class Foo:
          def __getitem__(self, index):
              ...
          def __len__(self):
              ...
          def get_iterator(self):
              return iter(self)

      class MyIterable(ABC):

          @abstractmethod
          def __iter__(self):
              while False:
                  yield None

          def get_iterator(self):
              return self.__iter__()

          @classmethod
          def __subclasshook__(cls, C):
              if cls is MyIterable:
                  if any("__iter__" in B.__dict__ for B in C.__mro__):
                      return True
              return NotImplemented

      MyIterable.register(Foo)

   ABC "MyIterable" 은 추상 메서드로 "__iter__()" 라는 표준 이터러블
   메서드를 정의합니다. 여기에 제공된 구현은 여전히 서브 클래스에서 호
   출 할 수 있습니다. "get_iterator()" 메서드 또한 "MyIterable" 추상
   베이스 클래스의 일부이지만, 추상이 아닌 파생 클래스에서 재정의될 필
   요는 없습니다.

   여기에 정의된 "__subclasshook__()" 클래스 메서드는 자신의 (또는 그
   것의 "__mro__" 리스트를 통해 액세스 되는 베이스 클래스 중 하나의)
   "__dict__" 에 "__iter__()" 메서드를 가진 모든 클래스도 "MyIterable"
   로 간주한다고 말합니다.

   마지막으로, 마지막 줄은, "Foo" 가 "__iter__()" 메서드를 정의하지는
   않았음에도 불구하고 (이것은 "__len__()" 과 "__getitem__()" 로 정의
   되는 이전 스타일의 이터러블 프로토콜을 사용합니다), "MyIterable" 의
   가상 서브 클래스로 만듭니다. 이렇게 하면 "get_iterator" 가 "Foo" 의
   메서드로 사용할 수 있지 않으므로, 별도로 제공됩니다.

"abc" 모듈은 다음 데코레이터도 제공합니다:

@abc.abstractmethod

   추상 메서드를 나타내는 데코레이터.

   이 데코레이터를 사용하려면 클래스의 메타 클래스가 "ABCMeta" 이거나
   여기에서 파생된 것이어야 합니다. "ABCMeta" 에서 파생된 메타 클래스
   를 가진 클래스는 모든 추상 메서드와 프로퍼티가 재정의되지 않는 한
   인스턴스로 만들 수 없습니다. 추상 메서드는 일반적인 'super' 호출 메
   커니즘을 사용하여 호출 할 수 있습니다. "abstractmethod()" 는 프로퍼
   티와 디스크립터에 대한 추상 메서드를 선언하는 데 사용될 수 있습니다
   .

   클래스에 추상 메서드를 동적으로 추가하거나, 메서드나 클래스가 작성
   된 후에 추상화 상태를 수정하려고 시도하는 것은 지원되지 않습니다.
   "abstractmethod()" 는 정규 상속을 사용하여 파생된 서브 클래스에만
   영향을 줍니다; ABC의 "register()" 메서드로 등록된 "가상 서브 클래스
   " 는 영향을 받지 않습니다.

   "abstractmethod()" 가 다른 메서드 디스크립터와 함께 적용될 때, 다음
   사용 예제와 같이 가장 안쪽의 데코레이터로 적용되어야 합니다:

      class C(ABC):
          @abstractmethod
          def my_abstract_method(self, ...):
              ...
          @classmethod
          @abstractmethod
          def my_abstract_classmethod(cls, ...):
              ...
          @staticmethod
          @abstractmethod
          def my_abstract_staticmethod(...):
              ...

          @property
          @abstractmethod
          def my_abstract_property(self):
              ...
          @my_abstract_property.setter
          @abstractmethod
          def my_abstract_property(self, val):
              ...

          @abstractmethod
          def _get_x(self):
              ...
          @abstractmethod
          def _set_x(self, val):
              ...
          x = property(_get_x, _set_x)

   추상 베이스 클래스 장치와 정확하게 상호 작용하기 위해서, 디스크립터
   는 "__isabstractmethod__" 를 사용하여 자신을 추상으로 식별해야 합니
   다. 일반적으로 이 어트리뷰트는 디스크립터를 구성하는 데 사용된 메서
   드 중 어느 하나라도 추상이면 "True" 여야 합니다. 예를 들어, 파이썬
   의 내장 "property"는 다음과 동등한 일을 합니다:

      class Descriptor:
          ...
          @property
          def __isabstractmethod__(self):
              return any(getattr(f, '__isabstractmethod__', False) for
                         f in (self._fget, self._fset, self._fdel))

   참고:

     자바 추상 메서드와 달리, 이 추상 메서드는 구현을 가질 수 있습니다
     . 이 구현은 그것을 재정의하는 클래스에서 "super()" 메커니즘을 통
     해 호출 할 수 있습니다. 이는 협업적 다중 상속을 사용하는 프레임워
     크에서 super-호출의 종점으로 유용 할 수 있습니다.

"abc" 모듈은 다음 레거시 데코레이터도 지원합니다:

@abc.abstractclassmethod

   버전 3.2에 추가.

   버전 3.3부터 폐지: 이제 "classmethod" 와 "abstractmethod()" 를 함께
   사용할 수 있어서, 이 데코레이터는 필요 없습니다.

   내장 "classmethod()" 의 서브 클래스로, 추상 classmethod를 나타냅니
   다. 그 외에는 "abstractmethod()" 와 유사합니다.

   "classmethod()" 데코레이터가 이제 추상 메서드에 적용될 때 추상으로
   정확하게 식별되기 때문에, 이 특별한 경우는 폐지되었습니다.:

      class C(ABC):
          @classmethod
          @abstractmethod
          def my_abstract_classmethod(cls, ...):
              ...

@abc.abstractstaticmethod

   버전 3.2에 추가.

   버전 3.3부터 폐지: 이제 "staticmethod" 와 "abstractmethod()" 를 함
   께 사용할 수 있어서, 이 데코레이터는 필요 없습니다.

   내장 "staticmethod()" 의 서브 클래스로, 추상 staticmethod를 나타냅
   니다. 그 외에는 "abstractmethod()" 와 유사합니다.

   "staticmethod()" 데코레이터가 이제 추상 메서드에 적용될 때 추상으로
   정확하게 식별되기 때문에, 이 특별한 경우는 폐지되었습니다.:

      class C(ABC):
          @staticmethod
          @abstractmethod
          def my_abstract_staticmethod(...):
              ...

@abc.abstractproperty

   버전 3.3부터 폐지: 이제 "property", "property.getter()",
   "property.setter()", "property.deleter()" 와 "abstractmethod()" 를
   함께 사용할 수 있어서, 이 데코레이터는 필요 없습니다.

   내장 "property()" 의 서브 클래스로, 추상 property를 나타냅니다.

   "property()" 데코레이터가 이제 추상 메서드에 적용될 때 추상으로 정
   확하게 식별되기 때문에, 이 특별한 경우는 폐지되었습니다.:

      class C(ABC):
          @property
          @abstractmethod
          def my_abstract_property(self):
              ...

   위의 예제는 읽기 전용 프로퍼티를 정의합니다; 하나나 그 이상의 하부
   메서드를 추상으로 적절하게 표시하여 읽기-쓰기 추상 프로퍼티를 정의
   할 수도 있습니다:

      class C(ABC):
          @property
          def x(self):
              ...

          @x.setter
          @abstractmethod
          def x(self, val):
              ...

   일부 구성 요소만 추상인 경우, 서브 클래스에서 구상 프로퍼티를 만들
   기 위해서는 해당 구성 요소만 갱신하면 됩니다:

      class D(C):
          @C.x.setter
          def x(self, val):
              ...

"abc" 모듈은 또한 다음과 같은 기능을 제공합니다 :

abc.get_cache_token()

   현재의 추상 베이스 클래스 캐시 토큰을 반환합니다.

   토큰은 가상 서브 클래스를 위한 추상 베이스 클래스 캐시의 현재 버전
   을 식별하는 (동등성 검사를 지원하는) 불투명 객체입니다. 임의의 ABC
   에서 "ABCMeta.register()" 가 호출될 때마다 토큰이 변경됩니다.

   버전 3.4에 추가.

-[ 각주 ]-

[1] C++ 프로그래머는 파이썬의 가상 베이스 클래스 개념이 C++과 다르다는
    것을 알아야 합니다.
