I’m attempting to write a generic class in Python 3.11 that should be able to process a list of elements using different processing classes (A
or B
in this example). My goal is to use the type variable T
to specify the processing class that should be used.
Clarification: Each element x
within the list X
requires an individual initialization of the subclass A
or B
, so initializing is only possible withing the process()
method.
Here’s my code:
from typing import List, Self, TypeVar, Generic
class A:
def __init__(self):
pass
def process(self, x):
return x + 1
class B:
def __init__(self):
pass
def process(self, x):
return x + 2
T = TypeVar("T", A, B)
class ListProcessor(Generic[T]):
"""Apply a Transformer to the individual list elements."""
def __init__(self, processor: T):
self.processor_class = processor
self.processors: List[T] = [] # <- Pylance complains! see error message (1)
def process(self, X) -> List:
x_processed = []
for x in X:
proc: T = self.processor_class() # <- Pylance complains! see error message (2)
result = proc.process(x)
x_processed.append(result)
self.processors.append(proc)
return x_processed
lp = ListProcessor(B)
lp.process([1, 2, 3])
The output of the above is:
[3, 4, 5]
which is what I expect. But while the code runs, Pylance type checker complains in VSCode.
-
For the line
self.processors: List[T] = []
, I get:Variable not allowed in type expression PylancereportGeneralTypeIssues
T: ~T
(constant) T: Unknown -
For the line
proc: T = self.processor_class()
, I get:Object of type "A*" is not callablePylancereportGeneralTypeIssues
Object of type "B*" is not callablePylancereportGeneralTypeIssues
I’m struggling to understand these error messages. Could someone help clarify why these errors occur and how I can fix them?
2
Answers
The line
self.processors: List[T] = []
should beself.processors: List[T] = []
becauseself.processors
is alist
that will contain instances of typeT
.The line
proc: T = self.processor_class()
should beproc: T = self.processor_class
because we are assigning the class itself, not an instance of the class.Finnaly, in the line,
lp = ListProcessor(B)
, you need to instantiate theB
class by usingB()
because you want to pass an instance of classB
to theListProcessor
constructor.Inded I totaly miss read
self.processors: List[T] = []
, sorry :’)Though it seems like vscode is not complaining about anything here, I think changing the
processor: T
byprocessor: Type[T]
and the process function toproc: T = self.processor_class()
toproc = self.processor_type()
should do the job.