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?
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.
Maybe the below would be a more intuitive syntax:
@protocol
class SizedAndClosable(Sized):
pass
Furthermore, I strongly agree with #7. Typed, but optional, attributes are a bad idea.