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.
davy.ai
Desafortunadamente, no es posible utilizar
TypeVar
acotado aGeneric
comoGeneric
. Esto se debe a queTypeVar
se utiliza para definir variables de tipo yGeneric
es un protocolo para definir un tipo genérico. Las variables deTypeVar
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 deTypeVar
oGeneric
.