Open ydirson opened 1 year ago
If it's final, it means it cannot be changed
class Base:
toto: str = NotImplemented
def change_toto(self) -> None:
self.toto = "spam"
class CmdA(Base):
toto: Final[str] = "toto"
c = CmdA()
c.change_toto() # changes `c.toto` even though it's final :(
What are you trying to achieve with Final
?
@ikonst you're right, base.toto
should not be mutable, this was not the best of those attempts :)
What I'd like is to ensure all concrete subclasses of Base
have final strings for their .toto
.
This doesn't require all subclasses to have final strings (I'm not sure how you could ensure that) but you can make your original example work with a readonly property!
from typing import Final
from abc import ABC, abstractmethod
class Base(ABC):
@property
@abstractmethod
def toto(self) -> str:
...
def access_toto(self) -> str:
return self.toto
class CmdA(Base):
toto: Final[str] = "toto"
Should we close this, or do we consider this a usability problem with the current error "Cannot override writable attribute "{name}" with a final one'"?
For example, do we need treatment similar to this? https://github.com/python/mypy/blob/267d37685a35e25eb985d56b6c6881ba574fcc7f/mypy/messages.py#L1194-L1205
My original point was more about:
@A5rocks yes this answers point 1, though I prefer avoiding ABC
when stuff like ABC.register()
is not needed (it's a PITA when you start to have other metaclasses), so I prefer this slightly modified version:
from typing import Final
class Base:
@property
def toto(self) -> str:
raise NotImplementedError()
def access_toto(self) -> str:
return self.toto
class CmdA(Base):
toto: Final[str] = "toto"
For point 2 I still don't have any idea. I'd think the final annotation in superclass without an assignment could have a use here, it would just declare an "abstract attribute" -- assigning NotImplemented
could likely not be interpreted in another way, but going that way creates a special case which the first option avoids. Would there be any problem going that way ?
@ikonst: yes I'd tend to think similar treatment would help, but it's not the whole of this ticket ;)
Hm I just re-read this and I think typing-wise a property setter that has a NoReturn return type might work for point 2, but I'm not sure if mypy supports that and I'm on mobile so can't test.
In the following code it would be useful to mark
toto
as final to make sure no code modifies it by error. However this triggersCannot override writable attribute "toto" with a final one
In fact I tend to agree with that error, in that what I'd really like to do is to annotate
toto
as "abstract final", which is not possible either as the use oftoto: Final[str]
triggersFinal name must be initialized with a value
, andtoto: Final[str] = NotImplemented
still gets theCannot override final attribute "toto" (previously declared in base class "Base")
the previous attempt also showed.