zerkms
zerkms

Reputation: 254944

Typing interfaces

What is the correct way to type an "interface" in python 3?

In the following sample:

class One(object):
    def foo(self) -> int:
        return 42


class Two(object):
    def foo(self) -> int:
        return 142


def factory(a: str):
    if a == "one":
        return One()

    return Two()

what would be the correct way to type the return value of the factory function?

It should be something like "A type with a single method named foo that accepts no arguments and returns an integer".

But not sure I can find how to do that.

UPD: this question is exclusively dedicated to typing.

Upvotes: 11

Views: 2371

Answers (2)

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 95957

You could use a typing.Union but, it sounds like you really want structural typing not nominal. Python supports this using typing.Protocol, which is a supported part of the python type-hinting system, so mypy will understand it, for example:

import typing

class Fooable(typing.Protocol):
    def foo(self) -> int:
        ...

class One(object):
    def foo(self) -> int:
        return 42


class Two(object):
    def foo(self) -> int:
        return 142


def factory(a: str) -> Fooable:
    if a == "one":
        return One()

    return Two()

x = factory('one')
x.foo()

Note, structural typing fits well with Python's duck-typing ethos. Python's typing system supports both structural and nominal forms.

Upvotes: 14

kpie
kpie

Reputation: 11100

The -> doesn't really do much in python.

>>> def foo()->int:
...     return "yeet"
...
>>> foo()
'yeet'

Similarly with denoting types in method signatures:

>>> def bar(a: int):
...     print(a)
...
>>> bar("yeet")
'yeet'

The syntax is really just a means of commenting your code. Conceptually you could implement something of an interface by raising an exception in the constructor.

>>> class foo:
...     def __init__(self):
...             raise()
...     def someFunc(self):
...             return(42)
...
>>> class bar(foo):
...     def __init__(self):
...             self.whatEver = "idk"
...
>>> a = bar()
>>> a.someFunc()
42
>>> baz = foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: exceptions must derive from BaseException

However you will not get the benefits of type stringency that you are looking for because python isn't a strongly typed language. Edit: Python doesn't use static typing.

Upvotes: -4

Related Questions