Как создать один из многих унаследованных классов без

Скажем, например, у меня есть несколько классов, которые все принадлежат одному и тому же родительскому классу и имеют одинаковые параметры. Общий пример;

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")

Другие вопросы по тегам