Considering this abstract class and a class implementing it:
from abc import ABC
class FooBase(ABC):
foo: str
bar: str
baz: int
def __init__(self):
self.bar = "bar"
self.baz = "baz"
class Foo(FooBase):
foo: str = "hello"
The idea here is that a Foo
class that implements FooBase
would be required to specify the value of the foo
attribute, but the other attributes (bar
and baz
) would not need to be overwritten, as they're already handle by a method provided by the abstract class.
From a MyPy type-checking perspective, is it possible to force Foo
to declare the attribute foo
and raise a type-checking error otherwise?
EDIT:
The rationale is that FooBase
is part of a library, and the client code should be prevented from implementing it without specifying a value for foo
. For bar
and baz
however, these are entirely managed by the library and the client doesn't care about them.
This is a partial answer. You can use
class FooBase(ABC):
@property
@classmethod
@abstractmethod
def foo(cls) -> str:
...
class Foo(FooBase):
foo = "hi"
def go(f: FooBase) -> str:
return f.foo
It's only partial because you'll only get a mypy error if you try to instantiate Foo
without an initialized foo
, like
class Foo(FooBase):
...
Foo() # error: Cannot instantiate abstract class "Foo" with abstract attribute "foo"
This is the same behaviour as when you have a simple @abstractmethod
. Only when instantiating it is the error raised. This is expected because Foo
might not be intended as a concrete class, and may itself be subclassed. You can mitigate this somewhat by stating it is a concrete class with typing.final
. The following will raise an error on the class itself.
@final
class Foo(FooBase): # error: Final class __main__.Foo has abstract attributes "foo"
...