Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

131
Views
Anotar variable de clase de clase de datos con valor de tipo

Tenemos varias clases de datos que representan varios resultados con un ancestro común Result . Luego, cada resultado proporciona sus datos utilizando su propia subclase de ResultData . Pero tenemos problemas para anotar el caso correctamente.

Se nos ocurrió la siguiente solución:

 from dataclasses import dataclass from typing import ClassVar, Generic, Optional, Sequence, Type, TypeVar class ResultData: ... T = TypeVar('T', bound=ResultData) @dataclass class Result(Generic[T]): _data_cls: ClassVar[Type[T]] data: Sequence[T] @classmethod def parse(cls, ...) -> T: self = cls() self.data = [self._data_cls.parse(...)] return self class FooResultData(ResultData): ... class FooResult(Result): _data_cls = FooResultData

pero dejó de funcionar últimamente con el error ClassVar cannot contain type variables [misc] . También va en contra de PEP 526, consulte https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations , que nos perdimos anteriormente.

¿Hay alguna manera de anotar este caso correctamente?

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Como se insinuó en los comentarios, el atributo _data_cls podría eliminarse, suponiendo que se use para fines de sugerencia de tipo. La forma correcta de anotar una clase genérica definida como class MyClass[Generic[T]) es usar MyClass[MyType] en las anotaciones de tipo.

Por ejemplo, es de esperar que lo siguiente funcione en mypy. Solo probé en Pycharm y parece inferir el tipo lo suficientemente bien al menos.

 from dataclasses import dataclass from functools import cached_property from typing import Generic, Sequence, TypeVar, Any, Type T = TypeVar('T', bound='ResultData') class ResultData: ... @dataclass class Result(Generic[T]): data: Sequence[T] @cached_property def data_cls(self) -> Type[T]: """Get generic type arg to Generic[T] using `__orig_class__` attribute""" # noinspection PyUnresolvedReferences return self.__orig_class__.__args__[0] def parse(self): print(self.data_cls) @dataclass class FooResultData(ResultData): # can be removed this_is_a_test: Any = 'testing' class AnotherResultData(ResultData): ... # indicates `data` is a list of `FooResultData` objects FooResult = Result[FooResultData] # indicates `data` is a list of `AnotherResultData` objects AnotherResult = Result[AnotherResultData] f: FooResult = FooResult([FooResultData()]) f.parse() _ = f.data[0].this_is_a_test # no warnings f: AnotherResult = AnotherResult([AnotherResultData()]) f.parse()

Producción:

 <class '__main__.FooResultData'> <class '__main__.AnotherResultData'>

Y, por supuesto, aquí hay una prueba de que parece estar funcionando de mi parte:

ingrese la descripción de la imagen aquí

over 4 years ago · Santiago Trujillo Report

0

Al final, simplemente reemplacé la variable en la anotación _data_cls con la clase base y arreglé la anotación de subclases como lo señaló @ rv.kvetch en su respuesta .

La desventaja es la necesidad de definir la clase de resultado dos veces en cada subclase, pero en mi opinión es más legible que extraer la clase en propiedad.

La solución completa:

 from dataclasses import dataclass from typing import ClassVar, Generic, Optional, Sequence, Type, TypeVar class ResultData: ... T = TypeVar('T', bound=ResultData) @dataclass class Result(Generic[T]): _data_cls: ClassVar[Type[ResultData]] # Fixed annotation here data: Sequence[T] @classmethod def parse(cls, ...) -> T: self = cls() self.data = [self._data_cls.parse(...)] return self class FooResultData(ResultData): ... class FooResult(Result[FooResultData]): # Fixed annotation here _data_cls = FooResultData
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!