Obtener instancias de subclases con métodos abstractos en Python MyPy
Estoy tratando de obtener una lista de instancias de clase para clases que heredan de una clase padre en Python mientras uso MyPy. Tengo las siguientes clases de Python:
animal.py
from abc import abstractmethod
from typing import Dict
class Animal():
@property
@abstractmethod
def id(self) -> str:
pass
@property
@abstractmethod
def sound(self) -> str:
pass
def get_all_animals(cls) -> Dict[str, 'Animal']:
animals: Dict[str, Animal] = {}
for _class in Animal.__subclasses__():
animal = _class()
animals[animal.id] = animal
return animals
cat.py
from test.animal import Animal
class Cat(Animal):
@property
def id(self) -> str:
return "Cat"
@property
def sound(self) -> str:
return "Meow"
dog.py
from test.animal import Animal
class Dog(Animal):
@property
def id(self) -> str:
return "Dog"
@property
def sound(self) -> str:
return "Woof"
Sin embargo, en animal.py
en la línea animal = _class()
, estoy obteniendo el siguiente error:
No se puede instanciar la clase abstracta "Animal" con los atributos abstractos "id" y "sound"
Por lo que entiendo, no puedo instanciar instancias de Animal
porque hay métodos abstractos. Pero en este caso particular, solo estoy instanciando instancias de clases hijas que tienen esos métodos abstractos. ¿Hay alguna manera de decirle a MyPy que Animal.__subclasses__()
devuelve tipos con sus métodos abstractos implementados?
davy.ai
Para indicarle a MyPy que
Animal.__subclasses__()
devuelve tipos con sus métodos abstractos implementados, puedes utilizar anotaciones de tipo y sugerencias de tipo enanimal.py
. Específicamente, puedes modificar el métodoget_all_animals
de la siguiente manera:Los cambios realizados incluyen:
cls
del métodoget_all_animals
, lo cual indica que espera un objetoType
para la clase (en este caso,Animal
).get_all_animals
, lo cual indica que devuelve un diccionario con claves de tipostr
y valores de tipoAnimal
.animal
instanciado sea una instancia deAnimal
utilizando la funciónisinstance
.NotImplementedError
en lugar de utilizar la palabra clavepass
. Esto hace más claro que los métodos deben ser implementados por las clases derivadas.Al hacer esto, MyPy podrá inferir correctamente los tipos de las instancias devueltas por
get_all_animals
y no generará elTypeError
en la líneaanimal = _class()
.