用什么代替python中的接口/协议

What to use in replacement of an interface/protocol in python

我正在做一个象棋游戏,我想做一个标准的棋子接口/协议。python没有这些语言,那么我应该使用什么呢?我读过一些关于工厂的书,但我不知道它们会有什么帮助。事先谢谢!


简而言之,你可能根本不需要担心。由于python使用duck类型(另请参阅wikipedia文章了解更广泛的定义),如果一个对象有正确的方法,它将简单地工作,否则会引发异常。

您可能有一个Piece基类,其中一些方法会抛出NotImplementedError来表示需要重新实现这些类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Piece(object):

    def move():
        raise NotImplementedError(optional_error_message)

class Queen(Piece):

    def move():
        # Specific implementation for the Queen's movements

# Calling Queen().move() will work as intended but

class Knight(Piece):
    pass

# Knight().move() will raise a NotImplementedError

或者,您可以使用isInstance或isubClass显式验证接收到的对象,以确保它具有所有正确的方法,或者它是Piece的子类。请注意,某些人可能不认为检查类型是"Python式",最好使用NotImplementedError方法或abc模块(如本非常好的答案中所述)。

您的工厂只需要生成对象的实例,这些对象上有正确的方法。


python 3.7中的新功能:

接口和协议的一些好处是在开发过程中使用内置于IDES中的工具和静态类型分析在运行时之前检测错误的类型提示。通过这种方式,静态分析工具可以告诉您何时检查代码,是否试图访问对象上未定义的任何成员,而不仅仅是在运行时发现。

typing.Protocol类将作为"结构子类型"的机制添加到python 3.7中,其背后的力量是它可以用作隐式基类。也就是说,对于静态类型分析而言,具有与Protocol定义的成员匹配的成员的任何类都被视为其子类。

PEP 544中给出的基本示例说明了如何使用它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from typing import Protocol

class SupportsClose(Protocol):
    def close(self) -> None:
        # ...

class Resource:
    # ...
    def close(self) -> None:
        self.file.close()
        self.lock.release()

def close_all(things: Iterable[SupportsClose]) -> None:
    for thing in things:
        thing.close()

file = open('foo.txt')
resource = Resource()
close_all([file, resource])  # OK!
close_all([1])     # Error: 'int' has no 'close' method


我通常不在python中使用接口,但是如果必须这样做,您可以使用zope.interface。然后可以验证类或对象是否实现某些接口。此外,如果类不实现所有方法或属性,它还可能引发错误。Twisted和其他框架使用这个库。


我用python编写了一个国际象棋游戏(用tkinter),我的方法是用piece类、queen/knight/etc.类继承piece类、player类、square类和tkinter主循环的主程序类。每个工件都有一个颜色和位置,以及一个方法来帮助为直线移动直到阻塞的工件生成移动集。每个特定的工件子类都包含一个方法来确定它们的移动集。正方形物体包含一块和正方形在板上的位置。

主程序类有一个__init__,它设置板、放置块、加载块图标和声音效果,并初始化选项。一个draw_board方法重新绘制电路板,重置所有部件并重新绑定热键。然后有各种其他方法来加载新图标、开始新游戏、设置音量、保存、撤消、城堡等等。

我还没有完成版本10,但是您可以在这里获得版本9的源代码和资产。

您还可以查看开源的Shane's Chess信息数据库。我从来没用过,但它看起来很漂亮。


即使Python是动态的,也可以使用鸭子打字,它仍然可以实现Java和C语言调用的"接口"。这是通过声明抽象基类来实现的。https://docs.python.org/2/library/abc.html或https://docs.python.org/3.4/library/abc.html

定义ABC时,将所有类似接口的方法放在其中,并在它们的主体中包含passraise NotImplementedError。子类继承自ABC并重写这些方法,就像任何其他子类重写父类方法一样。(因为python有多个继承,所以它们可以从abc以及您喜欢的任何其他类继承。)