Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Feature proposal: Golang style interfaces #497
I love mypy and think it's a great addition to every Python developers toolkit. One thing I think could be a nice addition is lightweight interfaces such as exist in Go:
For those unfamiliar with that language, the salient part (IMO) is that in Go you can declare an interface, and use it in place of a type declaration, and any object that implements all methods (with the right type signature) that make up the interface will be a valid value for arguments with that type declaration, so as an example:
from typing import Interface class StringJoiner(Interface): def join_two_strings(self, string1: str, string2: str) -> str: """Join two strings together.""" pass class ImplementsStringJoiner(object): """Implicitly implements the interface.""" def join_two_strings(self, string1: str, string2: str) -> str: """Join two strings together.""" return string1 + string2 class DoesNotImplementStringJoiner(object): """Does not have the required method.""" pass def some_function(joiner: StringJoiner, string1: str, string2: str) -> str: return joiner.join_two_strings(string1, string2) # this should be fine some_function(ImplementsStringJoiner(), 'foo', 'bar') # this should not some_function(DoesNotImplementStringJoiner(), 'foo', 'bar')
What I like about these is that they really embody a static version of Python's ducktyping, where it matters what the object does, rather than what type it is, or what it inherits from.
Here is a very naive first stab, definitely not ready for a PR, (really just a proof of concept, no tests, likely some broken edge cases, and less than pretty code):
If you think these are a good idea at all, I would love to hear feedback on what these interfaces could look like (a base class works, but they could also be class decorators,) and where in mypy the best place to implement them would be.
This is definitely a good idea and I've been thinking about something like this for a long time. There's already
So your example could be written like this:
from typing import Protocol class StringJoiner(Protocol): def join_two_strings(self, string1: str, string2: str) -> str: """Join two strings together.""" pass ... # The rest would be identical
This could be implemented in a few phases. In the first phase, we wouldn't have generic protocols (such as
Some ideas about a basic implementation:
Awesome, I will start digging into Protocols, and will probably have a lot
On Sat, Nov 8, 2014 at 5:22 PM, Jukka Lehtosalo firstname.lastname@example.org
I recently did a project in Go and fell in love with its implicit interfaces. They're the greatest idea in OOP in recent history. @thisfred really nailed it when he said,
To work properly, it requires subclassing:
>>> import abc >>> class Foo(metaclass=abc.ABCMeta): ... @abc.abstractmethod ... def do_something(): ... return NotImplemented ... >>> class Bar(Foo): ... pass ... >>> class Baz(Foo): ... def do_something(): ... return True ... >>> bar = Bar() Traceback (most recent call last): File "<ipython-input-24-482989d4cfb5>", line 1, in <module> bar = Bar() TypeError: Can't instantiate abstract class Bar with abstract methods do_something >>> baz = Baz() >>>
Alternatively, one can use the
Riffing on the example above:
>>> import abc >>> class Foo(metaclass=abc.ABCMeta): ... @abc.abstractmethod ... def do_something(): ... return NotImplemented ... >>> class Bar: ... pass ... >>> Foo.register(Bar) <class '__main__.Bar'> >>> bar = Bar() >>> bar.do_something() Traceback (most recent call last): File "<ipython-input-29-2015a90099fc>", line 1, in <module> bar.do_something() AttributeError: 'Bar' object has no attribute 'do_something'
I'm curious if there's been any more discussion in this project on the idea of implicit interfaces. Issue #552 indicates maybe it's become even more difficult.