I have some machine learning model classes subclassed from XGBoost, Sklearn and TF and I have a factory method that takes a model name and returns a specific implementation and to have a correct return type from the factory I defined a TypeVar. Here MinXGBModel, MinRandomForestModel, MinDenseModel and MinMLPModel are my task-specific subclasses :
from typing import TypeVar
PredictiveModel = TypeVar('PredictiveModel',
MinXGBModel,
MinRandomForestModel,
MinDenseModel,
MinMLPModel)
def predictive_model_factory(model_type: str) -> PredictiveModel:
if model_type == "XGB":
return MinXGBModel
elif model_type == "TF":
return MinDenseModel
elif model_type == "RF":
return MinRandomForestModel
elif model_type == "MLP":
return MinMLPModel
else:
raise NotImplementedError(f'Unknown model type {model_type}. '
'Allowed model types are ("XGB", "RF", "TF", "MLP")')
This works fine but when I actually go to get the model class from a factory:
model_cls: PredictiveModel = predictive_model_factory(model_type=model_type)
the linter highlights reference to PredictiveModel and says that "Type variable PredictiveModel has no meaning in this context".
I don't use TypeVars very often so probably I'm doing something incorrectly but not sure what exactly. I had a look but couldn't find explanation for this message.
A
TypeVaris used for genetic types, eg. if a function can take an argument of any type and return the same type, you would annotate it as:It means that the return type is the same as the type of argument
x. Note that although the function can return any type, this is not the same as annotating it withAny.On the other hand, doing this would have no meaning (there is no way to tell what the type
Tis).The question contains similar code, where the type of the returned value cannot be determined.
If the idea is that it can return any of a several types, it should be annotated as a union of types:
Additionally
BTW, there's is an additional problem in the question. That function's return type is actually
type, because it returns a class and not an instance of a class. So it actually would be correctly annotated asUnion[Type[MinXGBModel], Type[MinRandomForestModel], Type[MinDenseModel], Type[MinMLPModel]]. Now, that is a long type annotation!This raises other questions: Why don't those classes all inherit from a base class (let's call it
Model), so that the function can simply returnType[Model]?Also, the function could be the factory, instead of just returning a factory. It could instantiate the model and then it's return type would be just
Model.