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!'
这是一个好主意吗?? 请给你的答案的例子。
如前所述其他位置:
接口是没有必要在Python。 这是因为Python有适当的多重继承,而且鸭子类型,这意味着,你必须在Java接口的地方,你不必让他们在Python。
尽管如此,仍然有多种用途的接口。 他们中的一些是由蟒蛇抽象基类,在Python 2.6引入了覆盖。 他们是有用的,如果你想的是不能被实例化基类,而是提供一个实现的特定接口或部分。
另一种用法是,如果你以某种方式要指定一个对象实现特定的接口,你可以使用ABC的也太由他们继承。 另一种方式是zope.interface,一个模块是Zope的组件架构,一个非常酷赫然组件框架的一部分。 在这里,你不从接口继承,而是标志着类(甚至实例)作为实现一个接口。 这也可以用来从一个单元记录查找组件。 超酷!
使用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目前有接口的第三方实现(最流行的是Zope的 ,在同时使用双绞线 ),但更常见的Python程序员喜欢使用被称为“抽象基类”(ABC),这与融合的接口更丰富的概念有一些执行方面有太多的可能性。 基本知识都特别支持在Python 2.6和更高版本,看到的PEP ,但即使在早期版本的Python他们通常被视为“要走的路” -只是定义一个类,它的一些方法提高NotImplementedError
,这样子会要注意,他们最好覆盖这些方法 - !)
像这样的东西(因为我没有Python的周围可能无法正常工作):
class IInterface:
def show(self): raise NotImplementedError
class MyClass(IInterface):
def show(self): print "Hello World!"
接口支持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的动态语言是必要的。 在Java(或C ++以其抽象基类)接口装置,确保如要传递正确的参数,能够完成一组任务。
例如,如果您有观察者和观察的,观察到的是有意认购支持IObserver接口,这反过来又对象notify
行动。 这是在编译期进行检查。
在Python,没有这样的东西作为compile time
和方法查找在运行时执行。 此外,一个可以与__getattr __()或__getattribute __()魔术方法覆盖的查找。 换句话说,你可以传递,作为观察员,可在访问返回调用任何对象notify
属性。
这使我得出结论,即在Python接口确实存在 -它只是他们的执法推迟到它们被实际使用的那一刻