Before you dive in, here is my question: how can I use type hints in a subclass to specify a different type on an instance attribute?
If you are unclear on what that means, read below, where I have drawn up an example to clarify things.
Full Explanation
I have an abstract class Foo
, and a subclass of Foo
called SubclassOfFoo
.
Foo
has an abstract method get_something
that returns an object of type Something
.
Something
has a subclass called SubclassOfSomething
. SubclassOfSomething
has an additional method something_special
.
SubclassOfFoo
overrides get_something
to return an object of type SubclassOfSomething
. Then, SubclassOfFoo
tries to use SubclassOfSomething
's method something_special
.
However, currently my PyCharm's inspections are reporting Unresolved attribute reference 'something_special' for class 'Something'
. I am trying to figure out the correct way to fix this.
This is all very confusing, so I have made a nice little code snippet to help here:
from abc import ABC, abstractmethod
class Something:
def __init__(self):
self.attr = 0
class SubclassOfSomething(Something):
def __init__(self):
Something.__init__(self)
def something_special(self):
self.attr = 1
class Foo(ABC):
def __init__(self):
self.my_class = self.get_something()
@abstractmethod
def get_something(self) -> Something:
pass
class SubclassOfFoo(Foo):
def __init__(self):
Foo.__init__(self)
def get_something(self) -> SubclassOfSomething:
return SubclassOfSomething()
def do_something_special(self):
self.my_class.something_special()
Basically, in order to get everything to work out, I can do one of several things:
get_something
within Foo
SubclassOfFoo
for self.my_class
to clear things upOption 1. is what I am trying to avoid
Option 2. is not bad, but I can't figure it out
Option 3. is also an option.
I am also open to other options, as I am sure there is a better way.
Can you please help me figure out the correct way to handle this?
What I Have Tried
To emulate option 2., I tried using typing.Type
as suggested here: Subclass in type hinting
However, this was not working for me.
Class & Instance Attributes in Python. Class attributes. Class attributes belong to the class itself they will be shared by all the instances. Such attributes are defined in the class body parts usually at the top, for legibility.
In a type hint, if we specify a type (class), then we mark the variable as containing an instance of that type. To specify that a variable instead contains a type, we need to use type [Cls] (or the old syntax typing.Type ). We need to add type hints for make_animal ().
When a method in a subclass has the same name, same parameters or signature and same return type (or sub-type) as a method in its super-class, then the method in the subclass is said to override the method in the super-class. Attention geek! Strengthen your foundations with the Python Programming Foundation Course and learn the basics.
Prerequisite: Inheritance in Python Method overriding is an ability of any object-oriented programming language that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its super-classes or parent classes.
Using generics:
from abc import ABC, abstractmethod
from typing import Generic, TypeVar
SomethingT = TypeVar('SomethingT', bound='Something')
...
class Foo(ABC, Generic[SomethingT]):
my_class: SomethingT
def __init__(self):
self.my_class = self.get_something()
@abstractmethod
def get_something(self) -> SomethingT:
pass
class SubclassOfFoo(Foo[SubclassOfSomething]):
def __init__(self):
super().__init__()
def get_something(self) -> SubclassOfSomething:
return SubclassOfSomething()
def do_something_special(self):
# inferred type of `self.my_class` will be `SubclassOfSomething`
self.my_class.something_special()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With