Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 21, 2013 11:25:37

trympyrym
Зарегистрирован: 2013-08-13
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

Необходимо в зависимости от условий создать экземпляр одного из N классов

сейчас реализация такая:

если (условие 1):
Экземпляр = класс1()
если (условие 2):
Экземпляр = класс2()


если (условие N):
Экземпляр = классN()

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

ЗЫ. все классы имеют одинаковый интерфейс, но очень сильно друг от друга отличаются, и при этом довольно тяжелые, поэтому лепить монстра, который ведет себя как класс K при инициализации с параметром K не представляется возможным.

Офлайн

#2 Окт. 21, 2013 11:37:34

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

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



Офлайн

#3 Окт. 21, 2013 11:49:49

trympyrym
Зарегистрирован: 2013-08-13
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

Это именно то, что надо. Спасибо.

Офлайн

#4 Окт. 21, 2013 11:51:17

sergeek
Зарегистрирован: 2012-06-26
Сообщения: 470
Репутация: +  43  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

не понятно каким образом эта команда упростит задачу. Классы такие же объекты как и строки

Офлайн

#5 Окт. 21, 2013 12:06:42

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

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



Офлайн

#6 Окт. 21, 2013 12:35:45

sergeek
Зарегистрирован: 2012-06-26
Сообщения: 470
Репутация: +  43  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

FishHook
да, это видимо практично (хотя мне все равно кажется это следствием плохой архитектуры самой библиотеки)
но тсу ведь не нравилась простыня из условий
trympyrym
если (условие 1):
Экземпляр = класс1()
если (условие 2):
Экземпляр = класс2()
возможно все же лучше было решить это каким-нибудь хитрым полиморфизмом или словарем {лямбда : класс}


Офлайн

#7 Окт. 21, 2013 13:20:30

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

Что-то типа этого, взято из Википедии

# -*- 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

Я бы с Вами согласился, если бы мы имели дело со строготипизированным языком. Минус такого решения паттерна Абстрактная фабрикаи в том, что мы так или иначе должны регистрировать классы, как здесь в objects. А можем сделать проще, если примем некоторое соглашение об именовании классов. Тогда добавление нового класса в модуль автоматически делает его возможным результатом фабрики. Это менее академично, зато надёжно и практично.



Отредактировано FishHook (Окт. 21, 2013 13:21:16)

Офлайн

#8 Окт. 21, 2013 13:43:21

sergeek
Зарегистрирован: 2012-06-26
Сообщения: 470
Репутация: +  43  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

FishHook
Это менее академично, зато надёжно и практично
да, именно это я и пытался выразить
FishHook
Минус такого решения паттерна Абстрактная фабрикаи в том, что мы так или иначе должны регистрировать классы, как здесь в objects
их не обязательно регистрировать, можно, например добавлять (или даже генерировать из имени класса) атрибут
class Car(BaseVehicle):
    """Машина"""
    name = 'car'
    def __init__(self):
        self.message = 'I am car'
 
    def get_message(self):
        return self.message
и пройтись по всем потомкам BaseVehicle в поисках нужного.

Офлайн

#9 Окт. 21, 2013 14:39:44

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

sergeek
>>и пройтись по всем потомкам BaseVehicle в поисках нужного.
>>их не обязательно регистрировать, можно, например добавлять (или даже генерировать из имени класса) атрибут
Отлично! Но мы, (если уж мы решили пойти правильным путем ) должны обеспечить уникальность атрибута name у потомков, иначе мы не получим ни ошибки компиляции ни ошибки времени выполнения, и вообще даже можем не предполагать, что программа работает неправильно, если два класса будут иметь одинаковый name.
Экстраполируя, мы придем к Hello Word с применением тридцати паттернов, компонентным архитектурам, внедрению зависимостей и прочим страшным модным словам, хотя можно всё сделать проще.



Офлайн

#10 Окт. 21, 2013 16:39:08

sergeek
Зарегистрирован: 2012-06-26
Сообщения: 470
Репутация: +  43  -
Профиль   Отправить e-mail  

как создать экземпляр класса, если имя класса задано строкой

FishHook
Отлично! Но мы, (если уж мы решили пойти правильным путем ) должны обеспечить уникальность атрибута name у потомков, иначе мы не получим ни ошибки компиляции ни ошибки времени выполнения, и вообще даже можем не предполагать, что программа работает неправильно, если два класса будут иметь одинаковый name.
напишем метакласс-валидатор требующий уникальный атрибут для каждого неабстрактного потомка
(3 питон)
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)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version