Python: как использовать значение, хранящееся в переменной, чтобы решить, какой экземпляр класса инициировать? - PullRequest
1 голос
/ 03 октября 2010

Я создаю сайт Django. Мне нужно моделировать различные категории продуктов, такие как телевизоры, ноутбуки, женская одежда, мужская обувь и т. Д.

Поскольку разные категории продуктов имеют разные атрибуты, каждая категория имеет свою отдельную модель: TV, Laptop, WomensApparel, MensShoes, и т. Д.

И для каждой модели я создал ModelForm. Следовательно, у меня есть TVForm, LaptopForm, WomensApparelForm, MensShoesForm и т. Д.

Пользователи могут вводить сведения о продукте, выбирая категорию продукта через многоуровневые раскрывающиеся списки. После того, как пользователь выбрал категорию продукта, мне нужно отобразить соответствующую форму продукта.

Очевидный способ сделать это - использовать гигантскую if-elif структуру:

# category is the product category selected by the user

if category == "TV":
    form = TVForm()
elif category == "Laptop":
    form = LaptopForm()
elif category == "WomensApparel":
    form = WomensApparelForm()
...

К сожалению, может быть сотни, если не больше категорий. Таким образом, вышеописанный метод будет подвержен ошибкам и утомителен.

Можно ли каким-либо образом использовать значение переменной category для непосредственного выбора и инициализации соответствующего ModelForm, не прибегая к гигантскому if-elif выражению?

Что-то вроде:

# This doesn't work

model_form_name = category + "Form"
form = model_form_name()

Есть ли способ сделать это?

Ответы [ 3 ]

10 голосов
/ 03 октября 2010

Если все ваши *Form классы находятся в одном модуле (назовем его forms), вы можете сделать это:

import forms

form = getattr(forms, category + "Form")()

(Очевидно, добавьте любую необходимую проверку, такую ​​как перехват AttributeError. С точки зрения безопасности, если вы используете именованный модуль, а не глобальное пространство имен, кому-то немного сложнее ввести новый *Form класс.)

9 голосов
/ 03 октября 2010

Один простой способ сделать это - сохранить словарь названий категорий для формирования классов. Например,

categories_and_classes = dict(TV = TVForm, Laptop = LaptopForm, ...)

И затем вы можете использовать категорию для поиска класса формы:

form = categories_and_classes.get(category, DefaultForm)

В качестве альтернативы вы можете использовать соглашение, как сказал @Zooba в его ответ . Это будет работать, если ваши формы имеют одинаковое имя, скажем <category name> + Form.

1 голос
/ 03 октября 2010

Похоже, что вам нужно это отображение или словарь в Python. Например, создайте словарь, который отображает имена категорий моделей в классы ModelForm. Вы можете иметь другой, который сопоставляет их с классами модели. В любом случае вы можете сопоставить строку с именем модели в ней, что вы хотите.

Более "объектно-ориентированный" подход состоял бы в том, чтобы просто использовать словарь класса Model и добавить (возможно, статический) метод (ы) к каждому, который возвращает или делает то, что вам нужно, например, возвращает соответствующую ModelForm. Я имею в виду что-то вроде этого:

class TV:
    @staticmethod
    def getform():
        return TVForm
...
class Laptop:
    @staticmethod
    def getform():
        return LaptopForm
...
class WomensApparel:
...etc...

Models = { 'TV':TV, 'Laptop':Laptop, 'WomensApparel':WomensApparel, ...etc }

form = Models[category].getform()

С этими двумя методами вам не нужно будет писать такие гигантские if-elif структуры - и если вы когда-нибудь начнете, это признак того, что пришло время переосмыслить ваш дизайн.

...