Simplified Example
class A:
def __init__(self): ...
class BBuilder:
# To make this simpler, we won't have any arguments
def build(self): # -> WhatTypeHintDoIPutHere
class B(A):
def __init__(self):
super().__init__()
return B
my_b_builder: BBuilder = BBuilder()
BBuilt = my_b_builder.build() # BBuilt: WhatTypeHintDoIPutHere
my_b = BBuilt() # my_b: WhatTypeHintDoIPutHere
Question
How do I correctly type hint my_b and BBuilt? Without removing the BBuilder and without replacing the BBuilder with static subclass definitions.
What I tried
Tried typehinting my_b as:
Type[A] - incorrect because my_b is an instance
Type[B] - incorrect because my_b is an instance
BBuilt - mypy complained - you cannot use variables in typehints
Using TypeAliases
BBuiltAlias: TypeAlias = BBuilt; my_b: BBuiltAlias- you cannot use variables in typehintsUsing
typekeywordtype BBuiltAlias = BBuilt; my_b: BBuiltAlias- you cannot use variables in typehints
Editing the BBuilder to not be a dataclass doesn't change anything
Also experimented with TypeVars - no success. Attempts: 1 2 3
Also tried asking ChatGPT - no success
Afterword
If you really need it here is the original code along with some example usage of the classes. As a side question: Is it a bad coding practice to do this? The original code is easy to edit and easy to use.
Off-topic: My failed attempt of working around this problem here
Even though this is possible, dynamically creating classes (according to many people) may bring some nasty problems. There probably are other ways to solve your problem without dynamic class definitions!
The answer turned out to be extremely simple.
Example
Explanation
I don't think much explanation is necessary due to the number of comments in the example. I will give a short explanation of what is happening:
First we define the class we want to subclass as
ABaseThen we statically create a subclass of
ABasenamedBReal('real' because this is really the part where you write the code). Our dynamically created class will simply subclass the BReal and therefore inherit all of its methods and whatever else.In the example now we add some means of dynamically defining a class. I chose a Class Builder (this is probably not a real term, nor a professional term).
Defining that dynamically created subclass of A is very simple. Let's name it B.
class B(BReal): ...We use ... on purpose because there is no real code we should write here.Note for people newer to python who want B to support arguments in its init:
Since the way we defined B makes it a 100% subclass of BReal without any differences, it also inherits BReal's
init! So if you want B to support arguments, edit BReal'sinit. Leave B'sinitundefined!Please read the code of the Example if you want to see how to typehint that variable and an instance of B.
Even though this is possible, dynamically creating classes (according to many people) may bring some nasty problems. There probably are other ways to solve your problem without dynamic class definitions!
As an off-topic: I decided to remove dynamic class definitions in favour of something much simpler from my code: code