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