Search code examples
pythonpycharmtype-hintingmypy

Type Hinting for variable with inherited classes as value


I have doubts about the pythonic way to do something like this:

from my_package import A, B

class Main:
    def __init__(self) -> None:
        """ Constructor """
        self._var1: Union[A, B]
    
    def set_values(self, value: str) -> None:
    """ Sets the values """
        self._var1.function_caller(value)

class First(Main):
    def __init__(self) -> None:
        """ Constructor """
        self._var1 = A()
        # Super Constructor
        Main.__init__(self)

class Second(Main):
    def __init__(self) -> None:
        """ Constructor """
        self._var1 = B()
        # Super Constructor
        Main.__init__(self)

And then in my main program:

import First, Second

my_class = First() if arg['value'] == 'first' else Second()
my_class.set_values('test')

This way, MyPy does not show any error but PyCharm gives me the following:

Unresolved attribute reference '_var1' for class 'Main'

How this situation should be approached in a correct and pythonic way?


Solution

  • Change it like this:

    from my_package import A, B
    
    class Main:
        _var1: Union[A, B]
    
        def __init__(self) -> None:
            """ Constructor """
            pass
        
        def set_values(self, value: str) -> None:
        """ Sets the values """
            self._var1.function_caller(value)
    

    To improve the code further you may consider making Main an Abstract Base Class, since it is clearly not meant to be instantiated itself (_var1 will not be set), and is there to act as a common base for your 'real' classes First and Second.

    from abc import ABC
    
    from my_package import A, B
    
    class Main(ABC):
        _var1: Union[A, B]
    
        def __init__(self) -> None:
            """ Constructor """
            pass
        
        def set_values(self, value: str) -> None:
        """ Sets the values """
            self._var1.function_caller(value)