public interface IInterface
{
    void show();
}

 public class MyClass : IInterface
{

    #region IInterface Members

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

    #endregion
}

我如何实现Python等效的这个c#代码?

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

这是个好主意吗?请在回答中举例。


当前回答

对抽象基类使用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()

其他回答

对抽象基类使用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中不是必需的。这是因为Python有适当的多重继承,还有鸭子类型,这意味着在Java中必须有接口的地方,在Python中不必有它们。

也就是说,接口仍然有多种用途。其中一些由Python 2.6中引入的Python抽象基类覆盖。如果你想让基类不能被实例化,但是提供了一个特定的接口或者实现的一部分,它们是很有用的。

另一种用法是如果你想指定一个对象实现一个特定的接口,你也可以通过子类化它们来使用ABC。另一种方法是Zope .interface,它是Zope组件体系结构(一个非常酷的组件框架)的一部分。这里不需要从接口继承子类,而是将类(甚至实例)标记为实现接口。这也可以用于从组件注册表中查找组件。过冷!

我邀请您探索Python 3.8以结构子类型(静态鸭子类型)(PEP 544)的形式为主题提供了什么。

参见简短说明https://docs.python.org/3/library/typing.html#typing.Protocol

下面这个简单的例子是这样的:

from typing import Protocol

class MyShowProto(Protocol):
    def show(self):
        ...


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


class MyOtherClass:
    pass


def foo(o: MyShowProto):
    return o.show()

foo(MyClass())  # ok
foo(MyOtherClass())  # fails

foo(MyOtherClass())将失败的静态类型检查:

$ mypy proto-experiment.py 
proto-experiment.py:21: error: Argument 1 to "foo" has incompatible type "MyOtherClass"; expected "MyShowProto"
Found 1 error in 1 file (checked 1 source file)

此外,你可以显式地指定基类,例如:

class MyOtherClass(MyShowProto):

但请注意,这使得基类的方法实际上在子类上可用,因此静态检查器将不会报告MyOtherClass上缺少方法定义。 因此,在这种情况下,为了获得有用的类型检查,我们希望显式实现的所有方法都应该使用@abstractmethod来装饰:

from typing import Protocol
from abc import abstractmethod

class MyShowProto(Protocol):
    @abstractmethod
    def show(self): raise NotImplementedError


class MyOtherClass(MyShowProto):
    pass


MyOtherClass()  # error in type checker

接口支持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这样的动态语言中,接口并不是那么必要。在Java(或具有抽象基类的c++)中,接口是确保传递正确参数,能够执行一组任务的手段。

例如,如果你有观察者和可观察对象,可观察对象对订阅支持IObserver接口的对象感兴趣,而IObserver接口又具有通知操作。在编译时进行检查。

在Python中,没有编译时这样的东西,方法查找是在运行时执行的。此外,可以使用__getattr__()或__getattribute__()魔术方法覆盖查找。换句话说,你可以传递,作为观察者,任何对象,可以返回可调用的访问notify属性。

这让我得出结论,Python中的接口确实存在——只是它们的实施被推迟到了实际使用的时候