Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在python中实现接口?_Python_Oop - Fatal编程技术网

如何在python中实现接口?

如何在python中实现接口?,python,oop,Python,Oop,如何实现与此C#代码相当的Python 这是个好主意吗??请在回答中给出示例。Python接口有第三方实现(最流行的是,也在中使用),但更常见的是,Python程序员更喜欢使用更丰富的概念,称为“抽象基类”(Abstract Base Class,ABC),它将接口与实现方面的可能性结合起来。ABC在Python 2.6及更高版本中得到了很好的支持,请参见,但即使在Python的早期版本中,它们通常也被视为“必经之路”——只需定义一个类,其中一些方法会引发NotImplementedError,

如何实现与此C#代码相当的Python


这是个好主意吗??请在回答中给出示例。

Python接口有第三方实现(最流行的是,也在中使用),但更常见的是,Python程序员更喜欢使用更丰富的概念,称为“抽象基类”(Abstract Base Class,ABC),它将接口与实现方面的可能性结合起来。ABC在Python 2.6及更高版本中得到了很好的支持,请参见,但即使在Python的早期版本中,它们通常也被视为“必经之路”——只需定义一个类,其中一些方法会引发
NotImplementedError
,这样子类就会注意到它们最好重写这些方法!)

类似的内容(可能不起作用,因为我周围没有Python):


我的理解是,在Python这样的动态语言中,接口并不是必需的。在java(或C++中,它具有抽象基类)接口是确保例如传递正确参数、能够执行任务集的手段。p> 例如,如果您有observer和observable,observable对订阅支持IObserver接口的对象感兴趣,而IObserver接口又具有
notify
操作。这是在编译时检查的

在Python中,没有编译时之类的东西,方法查找是在运行时执行的。此外,可以使用uuu getattr_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。换句话说,您可以作为观察者传递任何可以在访问
notify
属性时返回callable的对象


这让我得出结论,Python中的接口确实存在,只是它们的执行被推迟到实际使用的时刻,正如其他人在这里提到的:


Python中不需要接口。这是因为Python有适当的多重继承,还有ducktyping,这意味着在Java中必须有接口的地方,Python中不必有接口

也就是说,接口仍有多种用途。Python 2.6中引入的Python抽象基类涵盖了其中一些抽象基类。如果您希望创建不能实例化的基类,但提供特定接口或实现的一部分,则它们非常有用


另一个用法是,如果您想以某种方式指定一个对象实现一个特定的接口,那么您也可以通过从它们派生子类来使用ABC。另一种方式是zope.interface,它是zope组件体系结构的一部分,是一个非常酷的组件框架。在这里,您不会从接口中创建子类,而是将类(甚至实例)标记为实现接口。这也可用于从组件注册表中查找组件。超级冷

对抽象基类使用abc模块似乎可以做到这一点

class IInterface:
    def show(self): raise NotImplementedError

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

在现代Python3中,使用抽象基类实现接口要简单得多,它们的作用是作为插件扩展的接口契约

创建接口/抽象基类:

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()
创建普通子类并重写所有抽象方法:

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)
您可以选择在抽象方法中使用公共实现,如
create\u sale\u invoice()
中所示,在子类中显式地使用
super()
调用它

实例化未实现所有抽象方法的子类失败:

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)
然后,您可以通过
AccountingSystem
类访问accounting system插件对象:

...
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
(灵感来源于。)

支持Python 2.7和Python 3.4+

要实现接口,您必须

>>> accountingsystem = AccountingSystem.instance()
示例代码:

pip install python-interface

我邀请您以
结构子类型(静态duck类型)

请参阅简短描述

这里的简单示例如下所示:

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
foo(MyOtherClass())
将使静态类型检查失败:

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
此外,还可以显式指定基类,例如:

$ 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)
但是请注意,这使得基类的方法实际上在子类上可用,因此静态检查器不会报告
MyOtherClass
上缺少方法定义。 因此,在本例中,为了获得有用的类型检查,我们希望显式实现的所有方法都应该用
@abstractmethod
修饰:

class MyOtherClass(MyShowProto):

关于构造函数,我应该怎么做?由你决定。由于没有针对从抽象类构造对象的编译时检查,因此在编码/编译期间不会获得任何保护。将继承一个构造函数,因此将创建一个“空”对象。这取决于你自己决定是否让这种情况发生,并在以后抓住失败的机会,从而让你过得更好,或者通过实现一个类似的构造函数抛出一个异常来明确地停止程序。这就是为什么
abc.abc
比引发
NotImplementedError
要好得多-没有实现所有抽象方法的
abc.abc
子类的实例化会提前失败,因此,您可以避免错误。请参阅下面我的答案,了解错误的样子。有Python接口的第三方实现,这意味着什么?你能解释一下ABC公司吗?好吧,我不同意ABC公司“更富有”的说法有些事情zope.interface可以做,ABC做不到,反之亦然。但除此之外,你还是像往常一样对的+1@Alfred:这意味着像zope.interface这样的模块不包括在标准库中,但可以从pypi获得。我仍然很难理解ABC的概念。是否有人可以用ABC的术语重写(IMHO,接口概念的一个很好的解释)。这有意义吗?目的是什么
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
$ 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):
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