[Python-ideas] Structural type checking for PEP 484

Jukka Lehtosalo jlehtosalo at gmail.com
Fri Sep 11 08:38:24 CEST 2015


On Thu, Sep 10, 2015 at 11:57 AM, Matthias Kramm via Python-ideas <
python-ideas at python.org> wrote:

> On Wednesday, September 9, 2015 at 1:19:12 PM UTC-7, Guido van Rossum
> wrote:
>>
>> Jukka wrote up a proposal for structural subtyping. It's pretty good.
>> Please discuss.
>>
>> https://github.com/ambv/typehinting/issues/11#issuecomment-138133867
>>
>
> I like this proposal; given Python's flat nominal type hierarchy, it will
> be useful to have a parallel subtyping mechanism to give things finer
> granularity without having to resort to ABCs.
>
> Are the return types of methods invariant or variant under this proposal?
>
> I.e. if I have
>
>   class A(Protocol):
>     def f() -> int: ...
>
> does
>
>   class B:
>     def f() -> bool:
>       return True
>
> implicitly implement the protocol A?
>

The proposal doesn't spell out the rules for subtyping, but we should
follow the ordinary rules for subtyping for functions, and return types
would behave covariantly. So the answer is yes.


> Also, marking Protocols using subclassing seems confusing and error-prone.
> In your examples above, one would think that you could define a new
> protocol using
>
> class SizedAndClosable(Sized):
>     pass
>
> instead of
>
> class SizedAndClosable(Sized, Protocol):
>     pass
>
> because Sized is already a protocol.
>

The proposal also lets you define the protocols implemented by your class
explicitly, and without having the explicit Protocol base class or some
other marker these would be impossible to distinguish in general. Example:

class MyList(Sized):   #  I want this to be a normal class, not a protocol.
    def __len__(self) -> int:
        return self.num_items

class DerivedProtocol(Sized):  # This should actually be a protocol.
    def foo(self) -> int: ...


> Maybe the below would be a more intuitive syntax:
>
>   @protocol
>   class SizedAndClosable(Sized):
>       pass
>
>
We could use that. The tradeoff it that then we'd have some inconsistency
depending on whether a protocol is generic or not:

@protocol
class A(metaclass=ProtocolMeta):   # Non-generic protocol
    ...

@protocol
class B(Generic[T]):   # Generic protocol. But this has a different
metaclass than the above?
    ...

I'm not sure if we can use ABCMeta for protocols as protocols may need some
additional metaclass functionality. Anyway, any proposal should consider
all these possible ways of defining protocols:

1. Basic protocol, no protocol inheritance
2. Generic protocol, no protocol inheritance
3. Basic protocol that inherits one or more protocols
4. Generic protocol that inherits one or more protocols

My approach seems to deal with all of these reasonable well in my opinion
(but I haven't implemented it yet!), but the tradeoff is that the Protocol
base class needs to be present for all protocols.

Jukka
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150910/f39328ec/attachment.html>


More information about the Python-ideas mailing list