Как создать один из многих унаследованных классов без
Скажем, например, у меня есть несколько классов, которые все принадлежат одному и тому же родительскому классу и имеют одинаковые параметры. Общий пример;
class Pet():
...
class Cat(Pet):
__init__(self,name,colour):
Pet.__init__(self,name,colour)
....
class Cactus(Pet):
__init__(self,name,colour):
Pet.__init__(self,name,colour)
....
А потом скажите, что я хочу использовать питомца в программе на основе пользовательского ввода. Сначала я подумал бы о том, чтобы делать;
if(pet_type == 'Cat'):
animal = Cat(name,colour)
elif(pet_type == 'Cactus'):
animal = Cactus(name,colour)
etc...
Но есть ли лучший способ, который не требует, если? Например, если бы программа была разработана, чтобы включать более 1000 животных, которые все происходят от домашних животных, то это не было бы осуществимо.
3 ответа
Создайте словарь допустимых классов:
classes = {
'Cat': Cat,
'Cactus': Cactus,
}
try:
cls = classes[pet_type]
except KeyError:
# handle invalid pet_type here
else:
animal = cls(name, colour)
В зависимости от вашего ответа на KeyError
вы можете использовать finally
пункт вместо else
или просто использовать get
метод dict
например,
animal = classes.get(pet_type, Pet)(name, colour)
То, что вы ищете, известно как фабричный образец. Существует множество способов достижения этого, от явных каскадов if, как вы их показываете, до магии метаклассов.
Довольно простой способ - класс-декоратор:
PET_CLASSES = {}
def pet_class(cls):
PET_CLASSES[cls.__name__.lower()] = cls
def create_pet(name):
return PET_CLASSES[name.lower()]()
@pet_class
class Cat:
pass
@pet_class
class Dog:
pass
print(create_pet("dog"))
Вы можете получить класс по его строковому имени с помощью getattr()
my_class = getattr(module, "class_name")
а потом
my_object = my_class(...)
Объект модуля может быть доступен module = __import__("module_name")