I am making a chess game and wanted to make a standard piece interface/protocol. Python does not have those in the language, so what am I supposed to use? I read a bit about factories, but I'm not sure how they would help. Thanks in advance!
-
1What would be the point of interfaces in Python, as it could not force you to implement all the methods? – Malik Brahimi Mar 13 '15 at 00:30
-
Interfaces are important for languages that are statically typed and you want to enforce that inheriting classes implement the interfaces. For dynamic languages like python, a class or a client of a class can look for functions. If the class has one, it can execute it, whether it inherited it or not. – Fred Mitchell Mar 13 '15 at 02:36
-
@MalikBrahimi Yes, in python it cannot be enforced but interfaces also serve a way to document what methods shall be implemented. More like a gentleman's agreement. With ABC, this is exactly what python did. – mahoriR Jan 20 '20 at 05:35
-
Related: https://stackoverflow.com/questions/4714136/how-to-implement-virtual-methods-in-python – Ciro Santilli OurBigBook.com Feb 15 '23 at 08:31
8 Answers
New in Python 3.8:
Some of the benefits of interfaces and protocols are type hinting during the development process using tools built into IDEs and static type analysis for detection of errors before runtime. This way, a static analysis tool can tell you when you check your code if you're trying to access any members that are not defined on an object, instead of only finding out at runtime.
The typing.Protocol
class was added to Python 3.8 as a mechanism for "structural subtyping." The power behind this is that it can be used as an implicit base class. That is, any class that has members that match the Protocol
's defined members is considered to be a subclass of it for purposes of static type analysis.
The basic example given in PEP 544 shows how this can be used.
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
Note: The typing-extensions
package backports typing.Protocol
for Python 3.5+.

- 864
- 1
- 9
- 16
-
1well... what misses here is to directly tell the reader of your code, that Resource implements the interface called SupportsClose. Is that possible in python? yes yes, some program maybe can figure that out, but when I read Resource I want to directly see "ahh resource implements the interface called supportsclose"... is that possible in python? – Toskan Sep 12 '19 at 06:47
-
4Yes, it is possible to explicitly declare an implementation, [as shown later in PEP 544](https://www.python.org/dev/peps/pep-0544/#explicitly-declaring-implementation). – gooberwonder Sep 13 '19 at 18:44
-
then please include that in your example, or at least mention it that both is possible. Because the example that you give is an anti pattern. I was literally thinking "python is trash" when I saw this. Now explicitly declaring is what you should do in your own code. The example you gave is probably what one should do, if "Resource" comes from a 3rd party library that you dont want to fork yourself. – Toskan Sep 14 '19 at 22:54
-
3Well, the example PEP 544 gives shows how `typing.Protocol` can be used to support static type analysis and type hinting. To those ends, whether a class explicitly or implicitly implements the `Protocol` is irrelevant. I actually prefer not to inherit a `Protocol` explicitly, because this can undermine its usefulness. If the subclass's explicit implementation of the method defined on the protocol were deliberately removed as part of a refactor, then consumers of it could still call this method, without being warned by static type hinting tools that the method was no longer present. – gooberwonder Nov 05 '19 at 21:28
-
2yeah its great: define a protocol, and implement it, and make it really hard to figure out what you just did, with the excuse that "the interface might be removed by mistake by someone else". Your example and answer isnt related to the question by OP, as you urself would be the consumer. – Toskan Nov 05 '19 at 21:40
-
@gooberwonder, I tried your example---on colab using typing_extensions. Then I ran `print(isinstance(resource, SupportsClose)` and got this error message: `Instance and class checks can only be used with @runtime protocols`. What went wrong? – RussAbbott Sep 23 '20 at 00:42
-
1`Because the example that you give is an anti pattern.`. That's not really true. A protocol allows you to let your typechecker do the duck-typing validation for you. It's similar to Go, in which [interfaces are implicitly implemented](https://tour.golang.org/methods/10). – Rushy Panchal Oct 27 '20 at 17:23
-
@RussAbbott You must decorate the class with `@runtime_checkable` to be able to use it with runtime checks, *even if* you inherit from it directly. – ktb Jun 22 '21 at 15:33
-
Also note that mypy does not currently check to see if a class that inherits from a Protocol even satisfies that Protocol. – ktb Jun 22 '21 at 15:35
In short, you probably don't need to worry about it at all. Since Python uses duck typing - see also the Wikipedia article for a broader definition - if an object has the right methods, it will simply work, otherwise exceptions will be raised.
You could possibly have a Piece
base class with some methods throwing NotImplementedError
to indicate they need to be re-implemented:
class Piece(object):
def move(<args>):
raise NotImplementedError(optional_error_message)
class Queen(Piece):
def move(<args>):
# Specific implementation for the Queen's movements
# Calling Queen().move(<args>) will work as intended but
class Knight(Piece):
pass
# Knight().move() will raise a NotImplementedError
Alternatively, you could explicitly validate an object you receive to make sure it has all the right methods, or that it is a subclass of Piece
by using isinstance or isubclass.
Note that checking the type may not be considered "Pythonic" by some and using the NotImplementedError
approach or the abc
module - as mentioned in this very good answer - could be preferable.
Your factory just has to produce instances of objects having the right methods on them.
I don't usually use interfaces in Python, but if you have to do it you can use zope.interface
. You can then verify whether classes or objects implement certain interfaces. Also, it can also raise errors if classes don't implement all methods or attributes. Twisted and other frameworks use this library.

- 2,958
- 1
- 28
- 36

- 2,994
- 3
- 17
- 20
-
The latest release was 2014 for py 3.4, and the homepage and CI page are both 404 – cowlinator Jun 29 '22 at 06:38
I wrote a chess game in Python (with tkinter), and the way I did it was to have a Piece class, Queen/Knight/etc. classes that inherit from the Piece class, a Player class, a Square class, and a main program class for tkinter's main loop. Each Piece has a color and location, and a method to help generate move sets for pieces that move in straight lines until blocked. Specific Piece subclasses each contain a method to determine their move set. A Square object contains a Piece and the square's location on the board.
The main program class has an __init__
that sets up the board, places the pieces, loads piece icons and sound effects, and initializes options. A draw_board
method redraws the board, resetting all pieces and rebinding the hotkeys. Then there are various other methods to load new icons, start a new game, set the volume, save, undo, castle, and so on.
I'm not done with version 10 yet, but you can get the source code and assets for version 9 here.
You can also check out the open source Shane's Chess Information Database. I've never used it, but it looks pretty nice.

- 48,464
- 6
- 60
- 97
Even though Python, being dynamic, can use duck-typing, it is still possible to implement what Java and C# call "interfaces". This is done by declaring an Abstract Base Class. https://docs.python.org/2/library/abc.html or https://docs.python.org/3.4/library/abc.html
When you define the ABC, put all of the Interface-like methods in it and have in their body either pass
or raise NotImplementedError
. The child classes inherit from your ABC and override these methods just like any other child class overrides parent class methods. (Since Python has multiple inheritance, they can inherit from your ABC plus any other class you like.)

- 2,093
- 4
- 19
- 35
The beauty of Python is that interfaces aren't necessary. Due to duck typing, you can just create several classes that all have the same method signature:
class Queen:
def move(self, x, y):
#do stuff
class Pawn:
def move(self, x, y):
# do stuff
Instances of these classes can be used interchangeably:
def make_move(piece, x, y):
piece.move(x, y)
q = Queen()
make_move(q, 0, 0)
p = Pawn()
make_move(p, 4, 5)
Note the above is by no means a good design for a fully fledged chess game. It is only for illustration purposes.

- 81,660
- 23
- 145
- 268
-
2but interfaces would allow you to check at edit time that you've remembered to implement all the required methods. Also if you had a loop like `board.pieces.move( .. )` that everything you add to `pieces` implements the required stuff. Imagine each piece being unique but having multiple methods like `take, retreat, ...` – dcsan Sep 13 '21 at 16:18
-
@dcsan I agree that an interface can help if you are implementing a new "piece" class that needs to conform to the correct protocol. Alternatively, you can use type annotations on parameters, variables, etc. I'm not sure what you are getting at with "also if you had a loop...". Duck typing would allow you to have implement the theorietical `board.pieces.move()` if `board.pieces` is an object with a `move()` method that loops over a collection of pieces that can be instances of any class that implements the methods that are called on it. – Code-Apprentice Sep 13 '21 at 20:05
-
but duck typing doesn't give you any of the dev time niceties that a modern IDE will help with. It makes coding tedious, esp refactoring. – dcsan Sep 13 '21 at 20:41
-
@dcsan Yes, that is the trade off. Type annotations help, but feel like a hack where an interface or abstract base class would be more appropriate. – Code-Apprentice Sep 14 '21 at 15:34
There is a good way to mimick Interfaces in Python.
Use metaclass=ABCMeta
when generating an "Interface" class in Python
and the @abstractmethod
decorator for all the methods which have to be implemented for this interface. Both are from abc
class. (If not implementing any of such @abstractmethod
-decorated methods, while inheriting, thus implementing the "Interface" class, a NotImplementedError
will be raised, as soon as one generates an instance from such a concrete class.)
As a naming convention, begin all such classes with a capital I
(for Interface).
from abc import ABCMeta, abstractmethod
class IPiece(metaclass=ABCMeta):
"The Piece Interface"
@abstractmethod
def move(<args>):
"NotImplementedError is superfluous, instead, one can use this space"
"To write some remarks, comments, annotations..."
class Queen(Piece):
def move(<args>):
# Specific implementation for the Queen's movements

- 9,303
- 17
- 30
typing.Protocol
concrete mypy
example (static type checking)
https://stackoverflow.com/a/50255847/895245 provided an example, but here's a slightly more concrete one with sample mypy
output. Related: How to implement virtual methods in Python?
protocol.py
from typing import Protocol
class CanFly(Protocol):
def fly(self) -> str:
pass
def fly_fast(self) -> str:
return 'CanFly.fly_fast'
class Bird(CanFly):
def fly(self):
return 'Bird.fly'
def fly_fast(self):
return 'Bird.fly_fast'
class FakeBird(CanFly):
pass
assert Bird().fly() == 'Bird.fly'
assert Bird().fly_fast() == 'Bird.fly_fast'
# mypy error
assert FakeBird().fly() is None
# mypy error
assert FakeBird().fly_fast() == 'CanFly.fly_fast'
If we run this file, the asserts pass, as we didn't add any dynamic typechecking:
python protocol.py
but if we typecheck if mypy
:
python -m pip install --user mypy
mypy protocol.py
we get an error as expected:
protocol.py:22: error: Cannot instantiate abstract class "FakeBird" with abstract attribute "fly"
protocol.py:24: error: Cannot instantiate abstract class "FakeBird" with abstract attribute "fly"
It is a bit unfortunate however that the error checking only picks up the error on instantiation, and not at class definition.
typing.Protocol
counts methods as abstract when their body is "empty"
I'm not sure what they count as empty, but both all of the following count as empty:
pass
...
ellipsis objectraise NotImplementedError()
So the best possibility is likely:
protocol_empty.py
from typing import Protocol
class CanFly(Protocol):
def fly(self) -> None:
raise NotImplementedError()
class Bird(CanFly):
def fly(self):
return None
class FakeBird(CanFly):
pass
Bird().fly()
FakeBird().fly()
which fails as desired:
protocol_empty.py:15: error: Cannot instantiate abstract class "FakeBird" with abstract attribute "fly"
protocol_empty.py:15: note: The following method was marked implicitly abstract because it has an empty function body: "fly". If it is not meant to be abstract, explicitly return None.
but if e.g. we replace the:
raise NotImplementedError()
with some random "non-empty" statement such as:
x = 1
then mypy
does not count them as virtual and gives no errors.
Tested on Python 3.10.7, mypy 0.982, Ubuntu 21.10.

- 347,512
- 102
- 1,199
- 985