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

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!'

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



답변

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

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

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

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


답변

추상 기본 클래스에 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()


답변

인터페이스 는 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


답변

현대의 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 게시물에서 영감을 얻었 습니다 .)


답변

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


답변

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

class IInterface:
    def show(self): raise NotImplementedError

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


답변

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

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

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

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