es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Python: TypeError: el objeto ‘TypeVar’ no es subscriptable. ¿Cómo crear un TypeVar con Generic limitado?

Estoy escribiendo una librería tipo ORM y mis instancias de modelo pueden existir en diferentes formas, como esta:

# Pueden tener cualquier atributo
selected_user: User[Selected] = db.select(User, ...)

# Deben tener atributos obligatorios
user_to_insert: User[ToInsert] = User.prepare_insert(...)

# Deben tener clave primaria
user_to_update: User[ToUpdate] = User.prepare_update(...)

Todas estas variables son instancias de la misma clase, comparten la misma lógica y atributos, y el argumento de suscripción describe su contenido. Para mí, parece un buen lugar para usar Generic y TypeVar.

Tengo dos clases base: View y Model:

class View: pass

class Selected(View): pass
class ToInsert(View): pass
class ToUpdate(View): pass

ViewVar = TypeVar("ViewVar", bound=View)

class Model(Generic[ViewVar]): pass

Funcionan bien para definir modelos:

class User(Model[ViewVar]):
    email: Optional[str] = ...
    name: Optional[str] = ...

El problema (TypeError: 'TypeVar' object is not subscriptable) ocurre con la escritura de funciones que procesan mis modelos:

ModelVar = TypeVar("ModelVar", bound=Model)

def insert(model_to_insert: ModelVar[ToInsert]) -> ModelVar[Selected]:
    pass

def prepare_insert(model: Type[ModelVar], description: dict) -> ModelVar[ToInsert]:
    pass

¿Hay alguna manera de usar TypeVar, limitado a un genérico, como genérico? ¿Por qué está prohibido? ¿Existen alternativas?

ACTUALIZADO
Encontré un “truco sucio”:

class GenericTypeVar(TypeVar, _root=True):
    def __getitem__(self, item): pass

Cambié TypeVar por GenericTypeVar. Es ilegible para los analizadores estáticos, pero evita que falle el código.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Desafortunadamente, no es posible utilizar TypeVar acotado a Generic como Generic. Esto se debe a que TypeVar se utiliza para definir variables de tipo y Generic es un protocolo para definir un tipo genérico. Las variables de TypeVar no son en sí mismas tipos genéricos, simplemente te permiten definir un marcador de posición para un tipo que puedes usar en varias definiciones.

    Sin embargo, el truco GenericTypeVar que encontraste puede funcionar como solución temporal en algunos casos. Ten en cuenta que no es una práctica recomendada y podría causar problemas con herramientas de análisis estático u otras partes de tu código. Otra alternativa podría ser definir funciones separadas para cada tipo específico de instancia de modelo que necesitas procesar, en lugar de tratar de crear una sola función que pueda manejar todas las variaciones. Esto te permitiría utilizar anotaciones de tipo normales sin necesidad de depender de TypeVar o Generic.

Comments are closed.