파이썬에서 인터페이스를 어떻게 구현합니까?


182
public interface IInterface
{
    void show();
}

 public class MyClass : IInterface
{

    #region IInterface Members

    public void show()
    {
        Console.WriteLine("Hello World!");
    }

    #endregion
}

이 C # 코드와 동등한 Python을 어떻게 구현합니까?

class IInterface(object):
    def __init__(self):
        pass

    def show(self):
        raise Exception("NotImplementedException")


class MyClass(IInterface):
   def __init__(self):
       IInterface.__init__(self)

   def show(self):
       print 'Hello World!'

이것이 좋은 생각입니까? 답변에 예를 들어주십시오.


귀하의 경우에 인터페이스를 사용하는 목적은 무엇입니까?
Bandi-T

23
솔직히 아무 목적도 없다! 파이썬에서 인터페이스가 필요할 때해야 할 일을 배우고 싶습니까?
Pratik Deoghare

18
raise NotImplementedError무엇인가 show의 몸이되어야합니다 - 완전히 일반적인 인상 말도 안돼 Exception파이썬은 완벽하게 특정 정의 할 때 내장 된 한 -!)
알렉스 마르 텔리

2
초기화하기 는 IInterface에 전화 쇼 () (또는 예외 자체를 인상)이 추상 인터페이스를 인스턴스화 할 수 있습니다?
Katastic Voyage

1
이것에 대한 사용을 볼 수 있습니다 ... 특정 서명을 가지고 싶은 객체가 있다고 가정 해 봅시다. 오리 타이핑을 사용하면 개체가 예상 한 서명을 보장 할 수 없습니다. 때로는 동적으로 유형이 지정된 속성에 일부 타이핑을 적용하는 것이 유용 할 수 있습니다.
Prime By Design

답변:


150

다른 여기에서 언급했듯이 :

파이썬에서는 인터페이스가 필요하지 않습니다. 파이썬에는 적절한 다중 상속과 덕 타이핑이 있기 때문에 자바에서 인터페이스가 있어야 하는 곳 은 파이썬에서 인터페이스를 가질 필요가 없습니다.

그러나 인터페이스에는 여전히 몇 가지 용도가 있습니다. 그중 일부는 Python 2.6에 도입 된 Pythons Abstract Base Classes로 덮여 있습니다. 인스턴스화 할 수 없지만 특정 인터페이스 또는 구현의 일부를 제공하는 기본 클래스를 만들려는 경우 유용합니다.

또 다른 사용법은 객체가 특정 인터페이스를 구현하도록 지정하려는 경우 서브 클래스를 사용하여 ABC를 사용할 수도 있습니다. 또 다른 방법은 zope.interface로, 정말 멋진 컴포넌트 프레임 워크 인 Zope Component Architecture의 일부인 모듈입니다. 여기서는 인터페이스에서 서브 클래스가 아니라 클래스 (또는 인스턴스)를 인터페이스 구현으로 표시합니다. 구성 요소 레지스트리에서 구성 요소를 조회하는 데에도 사용할 수 있습니다. 슈퍼 쿨!


11
이것에 대해 자세히 설명해 주시겠습니까? 1. 그러한 인터페이스를 어떻게 구현합니까? 2. 구성 요소를 찾는 데 어떻게 사용할 수 있습니까?
geoidesic

42
"파이썬에서는 인터페이스가 필요하지 않습니다. 인터페이스는 예외입니다."
Baptiste Candellier

8
인터페이스는 주로 개체를 전달할 때 예측 가능한 결과를 얻거나 구성원의 정확성을 강화하는 데 사용됩니다. 파이썬이 이것을 옵션으로 지원한다면 좋을 것입니다. 그것은 또한 개발 도구가 더 나은
Sonic Soul

1
예를 들어이 답변을 크게 개선 할 수 있습니다.
bob

5
"이것은 파이썬이 적절한 다중 상속을 가지고 있기 때문"이라고 누가 인터페이스가 다중 상속을위한 것이라고 말했습니까?
adnanmuttaleb 2014

76

추상 기본 클래스에 abc 모듈을 사용하면 트릭을 수행하는 것 같습니다.

from abc import ABCMeta, abstractmethod

class IInterface:
    __metaclass__ = ABCMeta

    @classmethod
    def version(self): return "1.0"
    @abstractmethod
    def show(self): raise NotImplementedError

class MyServer(IInterface):
    def show(self):
        print 'Hello, World 2!'

class MyBadServer(object):
    def show(self):
        print 'Damn you, world!'


class MyClient(object):

    def __init__(self, server):
        if not isinstance(server, IInterface): raise Exception('Bad interface')
        if not IInterface.version() == '1.0': raise Exception('Bad revision')

        self._server = server


    def client_show(self):
        self._server.show()


# This call will fail with an exception
try:
    x = MyClient(MyBadServer)
except Exception as exc:
    print 'Failed as it should!'

# This will pass with glory
MyClient(MyServer()).client_show()

11
언어 자체의 일부이거나 전혀 사용되지 않는 IMO에 대한 모듈이 필요합니다.
Mike de Klerk

당신은 의미 if not server.version() == '1.0': raise ...합니까? 나는이 줄을 정말로 얻지 못한다. 설명을 환영합니다.
Skandix

1
@MikedeKlerk 나는 더 이상 동의 할 수 없었다. 타이핑에 대한 파이썬의 대답처럼; 유형을 유형으로 선언한다고 선언하기 위해 모듈을 가져올 필요는 없습니다. 이것에 대한 응답은 일반적으로 "잘 파이썬은 동적으로 입력됩니다"지만 변명은 아닙니다. Java + Groovy는이 문제를 해결합니다. 정적 콘텐츠의 경우 Java, 동적 콘텐츠의 경우 Groovy
ubiquibacon

6
@MikedeKlerk, abc 모듈은 실제로 파이썬에 내장되어 있습니다. 이러한 패턴 중 일부는 '더 Pythonic'으로 간주되는 대체 패턴으로 인해 Python에서 필요하지 않기 때문에 약간 더 많은 작업이 필요합니다. 대다수의 개발자에게는 '전혀 사용하지 않는 것'과 같습니다. 그러나 이러한 인터페이스 기능을 실제로 요구하는 틈새 사례가 있음을 인정하면서 Python 제작자는 사용하기 쉬운 API를 제공했습니다.
David Culbreth

39

인터페이스 는 Python 2.7 및 Python 3.4+를 지원합니다.

인터페이스 를 설치 하려면

pip install python-interface

예제 코드 :

from interface import implements, Interface

class MyInterface(Interface):

    def method1(self, x):
        pass

    def method2(self, x, y):
        pass


class MyClass(implements(MyInterface)):

    def method1(self, x):
        return x * 2

    def method2(self, x, y):
        return x + y

7
이 라이브러리의 주요 이점 인 IMHO는 초기 오류로 인해 사용자에게 제공하는 초기 오류입니다. 클래스가 지정된 인터페이스를 올바르게 구현하지 않으면 클래스를 읽 자마자 예외가 발생하므로 사용하지 않아도됩니다. . 파이썬 자체의 추상 기본 클래스를 사용하면 클래스를 처음 인스턴스화 할 때 예외가 발생합니다.
Hans

ABC는 유사한 내장 기능을 제공합니다.
다니엘

@DanielCasares ABC는 실제 인터페이스를 제공합니까, 아니면 상태 나 구현이없는 추상 클래스가 ABC가 제공하는 솔루션이라는 것을 의미합니까?
asaf92

36

현대의 Python 3에서는 추상 기본 클래스로 인터페이스를 구현하는 것이 훨씬 간단하며 플러그인 확장을위한 인터페이스 계약의 목적으로 사용됩니다.

인터페이스 / 추상 기본 클래스를 만듭니다.

from abc import ABC, abstractmethod

class AccountingSystem(ABC):

    @abstractmethod
    def create_purchase_invoice(self, purchase):
        pass

    @abstractmethod
    def create_sale_invoice(self, sale):
        log.debug('Creating sale invoice', sale)

일반 서브 클래스를 작성하고 모든 추상 메소드를 대체하십시오.

class GizmoAccountingSystem(AccountingSystem):

    def create_purchase_invoice(self, purchase):
        submit_to_gizmo_purchase_service(purchase)

    def create_sale_invoice(self, sale):
        super().create_sale_invoice(sale)
        submit_to_gizmo_sale_service(sale)

위와 같이 서브 클래스에서 명시 적으로 create_sale_invoice()호출하여에서와 같이 추상 메소드에서 공통 구현을 선택적으로 가질 수 있습니다 super().

모든 추상 메소드를 구현하지 않는 서브 클래스 인스턴스화가 실패합니다.

class IncompleteAccountingSystem(AccountingSystem):
    pass

>>> accounting = IncompleteAccountingSystem()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class IncompleteAccountingSystem with abstract methods
create_purchase_invoice, create_sale_invoice

해당 주석을와 결합하여 추상 속성, 정적 및 클래스 메서드를 가질 수도 있습니다 @abstractmethod.

추상 기본 클래스는 플러그인 기반 시스템을 구현하는 데 적합합니다. 클래스의 모든 가져온 서브 클래스는를 통해 액세스 할 수 __subclasses__()있으므로 플러그인 디렉토리에서 모든 클래스를로드 importlib.import_module()하고 기본 클래스를 서브 클래스로로드하는 경우 클래스를 통해 직접 액세스 __subclasses__()할 수 있으며 모든 클래스 에 대해 인터페이스 계약이 시행되도록 할 수 있습니다. 인스턴스화하는 동안.

AccountingSystem위 예제에 대한 플러그인 로딩 구현은 다음과 같습니다 .

...
from importlib import import_module

class AccountingSystem(ABC):

    ...
    _instance = None

    @classmethod
    def instance(cls):
        if not cls._instance:
            module_name = settings.ACCOUNTING_SYSTEM_MODULE_NAME
            import_module(module_name)
            subclasses = cls.__subclasses__()
            if len(subclasses) > 1:
                raise InvalidAccountingSystemError('More than one '
                        f'accounting module: {subclasses}')
            if not subclasses or module_name not in str(subclasses[0]):
                raise InvalidAccountingSystemError('Accounting module '
                        f'{module_name} does not exist or does not '
                        'subclass AccountingSystem')
            cls._instance = subclasses[0]()
        return cls._instance

그런 다음 AccountingSystem클래스를 통해 계정 시스템 플러그인 오브젝트에 액세스 할 수 있습니다 .

>>> accountingsystem = AccountingSystem.instance()

( 이 PyMOTW-3 게시물에서 영감을 얻었 습니다 .)


질문 : 모듈 이름 "ABC"는 무엇을 의미합니까?
Sebastian Nielsen

"ABC"는 "Abstract Base Classes"를 나타냅니다. 공식 문서
mrts

31

Python에 대한 타사 인터페이스 구현 ( Twisted 에서도 사용되는 Zope 's )이 있지만, 일반적으로 Python 코더는 "ABC (Abstract Base Class)"라는 더 풍부한 개념을 사용하는 것을 선호합니다. 구현 측면도있을 수 있습니다. ABC는 특히 Python 2.6 이상에서 잘 지원됩니다 . PEP를 참조하십시오 . 그러나 이전 버전의 Python에서도 일반적으로 "가는 길"로 간주 됩니다. 그들이 그 방법을 재정의하는 것이 더 좋습니다!-)NotImplementedError


3
파이썬을위한 타사 인터페이스 구현이 있습니다. 무슨 의미입니까? ABC를 설명해 주시겠습니까?
Pratik Deoghare

2
글쎄요, 저는 ABC가 "풍부하게"되는 문제를 다루겠습니다. ;) zope.interface가 ABC가 할 수없는 일과 다른 방법이 있습니다. 그러나 그렇지 않으면 평소와 같습니다. +1
Lennart Regebro

1
@Alfred : zope.interface와 같은 모듈은 표준 라이브러리에 포함되어 있지 않지만 pypi에서 사용할 수 있음을 의미합니다.
Lennart Regebro

나는 ABC의 개념을 이해하기가 여전히 어렵다. 누군가 ABC의 관점에서 twistedmatrix.com/documents/current/core/howto/components.html (인터페이스 개념에 대한 훌륭한 설명) 을 다시 쓸 수 있을까요 ? 말이 되나요?
mcepl

21

이와 같은 것 (파이썬이 없기 때문에 작동하지 않을 수 있음) :

class IInterface:
    def show(self): raise NotImplementedError

class MyClass(IInterface):
    def show(self): print "Hello World!"

2
__init__(self)생성자 에 대해 어떻게해야 합니까?
Pratik Deoghare

1
당신에게 달려 있습니다. 추상 클래스에서 객체를 구성하는 것에 대한 컴파일 타임 검사가 없으므로 코딩 / 컴파일 중에는 보호 할 수 없습니다. 상속 된 생성자가 있으므로 개체 만들어지고 "빈"것입니다. 이 문제가 발생하여 나중에 실패를 포착하거나 예외를 던지는 비슷한 생성자를 구현하여 프로그램을 명시 적으로 중지함으로써 더 나은지 여부를 결정하는 것은 귀하의 몫입니다.
Bandi-T

1
이유 abc.ABC훨씬 더 높여보다 NotImplementedError의 인스턴스 - abc.ABC모든 추상 메소드를 구현하지 않는 서브 클래스를 초기에 실패하면 오류로부터 보호되도록. 오류가 어떻게 나타나는지 아래 답변을 참조하십시오.
mrts

8

내 이해는 파이썬과 같은 동적 언어에서는 인터페이스가 필요하지 않다는 것입니다. Java (또는 추상 기본 클래스가있는 C ++)에서 인터페이스는 예를 들어 올바른 매개 변수를 전달하여 일련의 작업을 수행 할 수 있도록 보장하는 수단입니다.

예를 들어 옵저버 블과 옵저버 블이있는 경우 옵저버 블은 IObserver 인터페이스를 지원하는 객체를 구독하는 데 관심이 있으며 그 결과 notify동작 이 있습니다. 이것은 컴파일 타임에 확인됩니다.

파이썬에서는 compile time런타임에 메소드 조회가 수행 되지 않습니다 . 또한 __getattr __ () 또는 __getattribute __ () 매직 메서드를 사용하여 조회를 재정의 할 수 있습니다. 즉, notify속성 에 액세스 할 때 호출 가능을 반환 할 수있는 모든 개체를 관찰자로서 전달할 수 있습니다 .

이것은 파이썬의 인터페이스 가 존재 한다는 결론에 이르게합니다. 실제로 사용되는 순간에 집행이 연기됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.