Форум сайта python.su
0
Необходимо в зависимости от условий создать экземпляр одного из N классов
сейчас реализация такая:
если (условие 1):
Экземпляр = класс1()
если (условие 2):
Экземпляр = класс2()
…
…
если (условие N):
Экземпляр = классN()
Неудобно это очень. Подскажите, есть ли команда, принимающая строку - название класса и создающая его экземпляр?
ЗЫ. все классы имеют одинаковый интерфейс, но очень сильно друг от друга отличаются, и при этом довольно тяжелые, поэтому лепить монстра, который ведет себя как класс K при инициализации с параметром K не представляется возможным.
Офлайн
568
class A(object): def foo(self): print "A" class B(object): def foo(self): print "B" cls_name = "A" instance = locals()[cls_name]() instance.foo()
Офлайн
0
Это именно то, что надо. Спасибо.
Офлайн
43
не понятно каким образом эта команда упростит задачу. Классы такие же объекты как и строки
Офлайн
568
sergeek
не понятно каким образом эта команда упростит задачу. Классы такие же объекты как и строки
role = IntegerField(choices=[(1, "Moderator"), (2, "Member"), (3, "Admin")]
ModeratorForm(forms.ModelForm): .... AdminForm(forms.ModelForm): .... def get_form_by_user(user, *args, **kwargs): form_class_name = user.get_role_display() + "Form" form = locals()[form_class_name](*args, **kwargs) return form
Офлайн
43
FishHookда, это видимо практично (хотя мне все равно кажется это следствием плохой архитектуры самой библиотеки)
trympyrymвозможно все же лучше было решить это каким-нибудь хитрым полиморфизмом или словарем {лямбда : класс}
если (условие 1):
Экземпляр = класс1()
если (условие 2):
Экземпляр = класс2()
Офлайн
568
Что-то типа этого, взято из Википедии
# -*- coding: utf-8 -*- class BaseVehicle(object): def get_message(self): raise NotImplementedError() class Airplane(BaseVehicle): """Самолет""" def __init__(self): self.message = 'I am airplane' def get_message(self): return self.message class Car(BaseVehicle): """Машина""" def __init__(self): self.message = 'I am car' def get_message(self): return self.message class VehicleFactory(object): """Фабрика средств передвижения""" objects = { 'car': Car, 'airplane': Airplane, 'default': Airplane, } def get_vehicle(self, name='default'): return self.objects[name]() factory = VehicleFactory() car = factory.get_vehicle('car') airplane = factory.get_vehicle('airplane') print car.get_message() # I am car print airplane.get_message() # I am airplane
Отредактировано FishHook (Окт. 21, 2013 13:21:16)
Офлайн
43
FishHookда, именно это я и пытался выразить
Это менее академично, зато надёжно и практично

FishHookих не обязательно регистрировать, можно, например добавлять (или даже генерировать из имени класса) атрибут
Минус такого решения паттерна Абстрактная фабрикаи в том, что мы так или иначе должны регистрировать классы, как здесь в objects
class Car(BaseVehicle): """Машина""" name = 'car' def __init__(self): self.message = 'I am car' def get_message(self): return self.message
Офлайн
568
sergeekОтлично! Но мы, (если уж мы решили пойти правильным путем
>>и пройтись по всем потомкам BaseVehicle в поисках нужного.
>>их не обязательно регистрировать, можно, например добавлять (или даже генерировать из имени класса) атрибут
) должны обеспечить уникальность атрибута name у потомков, иначе мы не получим ни ошибки компиляции ни ошибки времени выполнения, и вообще даже можем не предполагать, что программа работает неправильно, если два класса будут иметь одинаковый name. Офлайн
43
FishHookнапишем метакласс-валидатор требующий уникальный атрибут для каждого неабстрактного потомка
Отлично! Но мы, (если уж мы решили пойти правильным путем ) должны обеспечить уникальность атрибута name у потомков, иначе мы не получим ни ошибки компиляции ни ошибки времени выполнения, и вообще даже можем не предполагать, что программа работает неправильно, если два класса будут иметь одинаковый name.

import abc class Vehicle_validator(type): name_set = set() def __new__(cls, clsname, bases, attrs): is_abstract = lambda a : hasattr(a, '__isabstractmethod__') if not any(map(is_abstract, attrs.values())): veh_name = attrs.get('name') assert veh_name, "vehicle name for {} is not provided!!".format(clsname) assert veh_name not in Vehicle_validator.name_set, 'nonunique vehicle name in {}!!1'.format(clsname) Vehicle_validator.name_set.add(veh_name) return super(Vehicle_validator, cls).__new__(cls, clsname, bases, attrs) class Vehicle_meta(Vehicle_validator, abc.ABCMeta): ... class BaseVehicle(metaclass=Vehicle_meta): @abc.abstractmethod def get_message(self): ... class Car(BaseVehicle): """Машина""" name = 'car' def __init__(self): self.message = 'I am car' def get_message(self): return self.message class Airplane(BaseVehicle): #name = 'car' """Самолет""" def __init__(self): self.message = 'I am airplane' def get_message(self): return self.message
Отредактировано sergeek (Окт. 21, 2013 16:43:24)
Офлайн