Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider allowing @final methods in Protocols #13310

Open
tmke8 opened this issue Aug 2, 2022 · 4 comments
Open

Consider allowing @final methods in Protocols #13310

tmke8 opened this issue Aug 2, 2022 · 4 comments

Comments

@tmke8
Copy link
Contributor

tmke8 commented Aug 2, 2022

Feature

Allow this:

from typing import Protocol, final

class Sized(Protocol):
    len: int
    @final
    def __len__(self) -> int:
        return self.len

Pitch

I get that this is a bit unusual, but I don’t really see any harm that could come from this (as an aside, pyright allows it). My use case is that I’m using Protocols for mixins, and sometimes I want to make sure my mixed-in methods don’t get overwritten.

@A5rocks
Copy link
Contributor

A5rocks commented Aug 3, 2022

If you are using protocols for mixins, why not ABCs? To me, @final and non-inheritance subtyping (meaning you can provide a different implementation) feels like it's just asking for trouble although I can't think of any cases negatively impacted by this.

OTOH ABCs also offer virtual registering and I didn't check mypy for whether @final is allowed so the "bad" behavior might already be there (if mypy were to support that registering, that is :-).

@tmke8
Copy link
Contributor Author

tmke8 commented Aug 7, 2022

If you are using protocols for mixins, why not ABCs?

With ABCs, there is the problem that I can't define abstract attributes, like the len: int in the example code above. I raised the question of abstract attributes in ABCs on typing-sig: https://mail.python.org/archives/list/typing-sig@python.org/thread/UAL6LMKDLUNFXSR7HGOXPK2KUFIROJES/ but there wasn't much interest for it.

Yeah, virtual registering really is a strange feature. I feel like most people just pretend it doesn't exist.

@sobolevn
Copy link
Member

sobolevn commented Aug 9, 2022

I feel like this should be separated into two parts:

from typing import Protocol, final

class MySized(Protocol):
    len: int
    def __len__(self) -> int: ...

class _MyImpl:
   def __len__(self) -> int:
       return self.len

class MyClass(_MyImpl):
   def __init__(self, len: int) -> None:
       self.len = len

I would prefer to keep Protocols free of implementation. They are signature declarations to me (just pure structure).

@zhukovgreen
Copy link

zhukovgreen commented Jan 11, 2024

If I'd like to share the default implementation across protocol implementations, does it mean I have to do something like this:

import abc
from typing import Protocol, final

class MySized(Protocol):
    len: int
    def __len__(self) -> int: ...

class _MyDefaultImpl(abc.ABC, MySized):
   @final
   def __len__(self) -> int:
       return self.len

class MyClass(_MyDefaultImpl):
   def __init__(self, len: int) -> None:
       self.len = len

MyClass(15)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants