问题:如何在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!'
这是一个好主意吗??请在您的答案中举例说明。
回答 0
正如其他人在这里提到的:
在Python中不需要接口。这是因为Python具有适当的多重继承,还具有鸭式输入法,这意味着必须在Java中具有接口的地方,而不必在Python中具有接口。
也就是说,接口还有多种用途。其中一些被Python 2.6中引入的Pythons抽象基类覆盖。如果要创建无法实例化但提供特定接口或实现的一部分的基类,则它们很有用。
另一种用法是,如果您以某种方式想要指定一个对象实现特定的接口,并且可以通过从它们的子类中使用ABC来实现。另一种方法是zope.interface,它是Zope组件体系结构(一个非常酷的组件框架)的一部分的模块。在这里,您不是从接口子类化,而是将类(甚至实例)标记为实现接口。这也可以用于从组件注册表中查找组件。超酷!
回答 1
将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()
回答 2
介面支援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
回答 3
在现代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帖子启发。)
回答 4
有用于Python的第三方接口实现(最受欢迎的是Zope’s,也用于Twisted中),但是更常见的是,Python编码人员更喜欢使用称为“抽象基类”(ABC)的更丰富的概念,该概念将接口与那里也有一些实施方面的可能性。在2.6和更高版本的Python 中,特别好地支持ABC,请参阅PEP,但即使在早期版本的Python中,它们也通常被视为“前进的道路”-只需定义一个类,某些类的方法将引发,NotImplementedError
这样子类将成为注意,他们最好重写这些方法!-)
回答 5
像这样的东西(可能无法正常工作,因为我没有Python):
class IInterface:
def show(self): raise NotImplementedError
class MyClass(IInterface):
def show(self): print "Hello World!"
回答 6
我的理解是,在像Python这样的动态语言中,接口不是必需的。在Java(或带有抽象基类的C ++)中,接口是用于确保例如传递正确的参数,能够执行一组任务的方法。
例如,如果您具有观察者并且是可观察的,那么可观察的对象就是订阅支持IObserver接口的对象,而该对象又会起作用notify
。这是在编译时检查的。
在Python中,没有这样的事情,compile time
并且在运行时执行方法查找。而且,可以使用__getattr __()或__getattribute __()魔术方法覆盖查找。换句话说,您可以作为观察者传递可以在访问notify
属性时返回可调用对象的任何对象。
这使我得出结论,Python中的接口确实存在 -只是它们的执行被推迟到实际使用它们的那一刻