public interface IInterface
{
void show();
}
public class MyClass : IInterface
{
#region IInterface Members
public void show()
{
Console.WriteLine("Hello World!");
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
如何实现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!'
Run Code Online (Sandbox Code Playgroud)
这是一个好主意吗??请在答案中举例说明.
Len*_*bro 125
正如其他人所说:
Python中不需要接口.这是因为Python具有适当的多重继承,并且还具有类型,这意味着在Java中必须具有接口的位置,您不必在Python中使用它们.
也就是说,接口仍然有几种用途.其中一些被Python 2.6中引入的Pythons Abstract Base Classes所涵盖.如果要创建无法实例化的基类,但提供特定接口或实现的一部分,它们很有用.
另一种用法是,如果你想以某种方式指定一个对象实现一个特定的接口,你也可以通过子类化来使用ABC.另一种方式是zope.interface,这是一个模块,是Zope组件架构的一部分,是一个非常酷的组件框架.在这里,您不是从接口继承,而是将类(甚至实例)标记为实现接口.这也可用于从组件注册表中查找组件.超酷!
小智 57
使用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()
Run Code Online (Sandbox Code Playgroud)
Ale*_*lli 29
Python的接口有第三方实现(最流行的是Zope,也用于Twisted),但更常见的是Python编码器更喜欢使用更丰富的概念,称为"抽象基类"(ABC),它将接口与也有可能在那里有一些实施方面.ABCs在Python 2.6及更高版本中得到了特别好的支持,请参阅PEP,但即使在Python的早期版本中,它们通常被视为"要走的路" - 只需定义一个类,其中某些方法会引发,NotImplementedError
以便子类将成为注意他们最好覆盖那些方法! - )
blu*_*ray 28
接口支持Python 2.7和Python 3.4+.
要安装必须的接口
pip install python-interface
Run Code Online (Sandbox Code Playgroud)
示例代码:
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
Run Code Online (Sandbox Code Playgroud)
Pet*_*olf 22
我邀请您以(PEP 544) 的形式探索 Python 3.8 为主题提供的内容Structural subtyping (static duck typing)
请参阅简短说明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
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
此外,您可以显式指定基类,例如:
class MyOtherClass(MyShowProto):
Run Code Online (Sandbox Code Playgroud)
但请注意,这使得基类的方法在子类上实际可用,因此静态检查器不会报告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
Run Code Online (Sandbox Code Playgroud)
Ban*_*i-T 20
像这样的东西(可能不起作用,因为我没有Python):
class IInterface:
def show(self): raise NotImplementedError
class MyClass(IInterface):
def show(self): print "Hello World!"
Run Code Online (Sandbox Code Playgroud)
mrt*_*rts 16
在现代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)
Run Code Online (Sandbox Code Playgroud)
创建一个普通的子类并覆盖所有抽象方法:
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)
Run Code Online (Sandbox Code Playgroud)
您可以选择在抽象方法中使用通用实现,如上所述在子类中显式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
Run Code Online (Sandbox Code Playgroud)
您还可以通过组合相应的注释来使用抽象属性,静态和类方法@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
Run Code Online (Sandbox Code Playgroud)
然后,您可以通过AccountingSystem
类访问会计系统插件对象:
>>> accountingsystem = AccountingSystem.instance()
Run Code Online (Sandbox Code Playgroud)
(灵感来自这篇PyMOTW-3帖子.)
我的理解是接口在像Python这样的动态语言中并不是必需的.在Java(或带有抽象基类的C++)中,接口是确保例如您传递正确参数,能够执行一组任务的手段.
例如,如果您有观察者和可观察者,则observable对订阅支持IObserver接口的对象感兴趣,而IObserver接口又具有notify
动作.这在编译时检查.
在Python中,没有这样的东西,compile time
并且在运行时执行方法查找.此外,可以使用__getattr __()或__getattribute __()魔术方法覆盖查找.换句话说,您可以作为观察者传递任何可以在访问notify
属性时返回可调用对象的对象.
这导致我得出结论,Python中的接口确实存在 - 只是它们的执行被推迟到它们实际使用的那一刻
归档时间: |
|
查看次数: |
199000 次 |
最近记录: |