Как реализовать декоратор с нелокальным равенством?

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

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

Мне нужны следующие операции:

  • проверьте, есть ли у перехода метка
  • получить этот лейбл
  • добавить метку к переходу
  • проверьте, есть ли у перехода условие
  • получить это условие
  • проверка на равенство

Судя по первым пяти пунктам, это звучит как чистый декоратор с базовым переходом и двумя декораторами: Labeled и Condition. Однако у этого подхода есть проблема: два перехода считаются равными, если их начальное и конечное состояние одинаковы, метки на обоих переходах равны (или не существуют) и оба условия одинаковы (или не существуют). . С помощью декоратора у меня может быть два перехода с пометкой («foo», «условный» («bar», «переход» («baz», «qux»))) и «условный» («bar», «помеченный» («foo», «переход» («baz "," qux "))), для которых требуется нелокальное равенство, то есть декораторы должны будут собрать все данные, а переход должен сравнить эти собранные данные на основе набора:

class Transition(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
    def get_label(self):
        return None
    def has_label(self):
        return False
    def collect_decorations(self, decorations):
        return decorations
    def internal_equality(self, my_decorations, other):
        try:
            return (self.start == other.start
                    and self.end == other.end
                    and my_decorations = other.collect_decorations())
    def __eq__(self, other):
        return self.internal_equality(self.collect_decorations({}), other)

class Labeled(object):
    def __init__(self, label, base):
        self.base = base
        self.label = label
    def has_label(self):
        return True
    def get_label(self):
        return self.label
    def collect_decorations(self, decorations):
        assert 'label' not in decorations
        decorations['label'] = self.label
        return self.base.collect_decorations(decorations)
    def __getattr__(self, attribute):
        return self.base.__getattr(attribute)

Это чистый подход? Я что-то упускаю?

Я в основном смущен, потому что я могу решить эту проблему - с более длинными именами классов - с помощью кооперативного множественного наследования:

class Transition(object):
    def __init__(self, **kwargs):
        # init is pythons MI-madness ;-)
        super(Transition, self).__init__(**kwargs)
        self.start = kwargs['start']
        self.end = kwargs['end']
    def get_label(self):
        return None
    def get_condition(self):
        return None
    def __eq__(self, other):
        try:
            return self.start == other.start and self.end == other.end
        except AttributeError:
            return False

class LabeledTransition(Transition):
    def __init__(self, **kwargs):
        super(LabeledTransition).__init__(**kwargs)
        self.label = kwargs['label']
    def get_label(self):
        return self.label
    def __eq__(self):
        super_result = super(LabeledTransition, self).__eq__(other)
        try:
            return super_result and self.label == other.label
        except AttributeError:
            return False

class ConditionalTransition(Transition):
    def __init__(self, **kwargs):
        super(ConditionalTransition, self).__init__(**kwargs)
        self.condition = kwargs['condition']

    def get_condition(self):
        return self.condition

    def __eq__(self, other):
        super_result = super(ConditionalTransition, self).__eq__(other)
        try:
            return super_result and self.condition = other.condition
        except AttributeError:
            return False

# ConditionalTransition about the same, with get_condition
class LabeledConditionalTransition(LabeledTransition, ConditionalTransition):
    pass

класс LabledConditionalTransition ведет себя именно так, как ожидалось, и отсутствие кода привлекательно, и я не думаю, что MI сбивает с толку при таком размере.

Конечно, третий вариант - просто объединить все в один переходный класс с кучей has_label / has_transition.

Итак ... я в замешательстве. Я что-то упускаю? Какая реализация выглядит лучше? Как вы справляетесь с подобными случаями, то есть объекты, которые выглядят как декоратор, могут справиться с ними, но затем появляется такой нелокальный метод?

РЕДАКТИРОВАТЬ: Добавлен класс ConditionalTransition. По сути, этот вид ведет себя как декоратор, за вычетом порядка, созданного порядком создания декораторов, переход проверяет правильность начала и конца, класс LabeledTransition проверяет правильность метки, а ConditionalTransition проверяет правильность условия.

мне кажется, что вы пытаетесь написать Java-код на Python.

user3850 01.10.2008 02:43
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
579
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Из опубликованного кода единственная разница между переходом и помеченным переходом - это возврат get_lable () и has_label (). В этом случае вы можете сжать эти два одного класса, который устанавливает для атрибута label значение None и

return self.label is not None

в функции has_label ().

Можете выложить код для класса ConditionalTransition? Думаю, это прояснит.

Ответ принят как подходящий

Думаю, ясно, что никто толком не понимает вашего вопроса. Я бы посоветовал поместить его в контекст и сделать его короче. В качестве примера, вот одна из возможных реализаций паттерна состояний в Python. Изучите ее, чтобы получить представление.

class State(object):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return self.name

class Automaton(object):
    def __init__(self, instance, start):
        self._state = start
        self.transitions = instance.transitions()

    def get_state(self):
        return self._state

    def set_state(self, target):
        transition = self.transitions.get((self.state, target))
        if transition:
            action, condition = transition
            if condition:
                if condition():
                    if action:
                        action()
                    self._state = target
            else:
                self._state = target
        else:
            self._state = target

    state = property(get_state, set_state)

class Door(object):
    open = State('open')
    closed = State('closed')

    def __init__(self, blocked=False):
        self.blocked = blocked

    def close(self):
        print 'closing door'

    def do_open(self):
        print 'opening door'

    def not_blocked(self):
        return not self.blocked

    def transitions(self):
        return {
            (self.open, self.closed):(self.close, self.not_blocked),
            (self.closed, self.open):(self.do_open, self.not_blocked),
        }

if __name__ == '__main__':
    door = Door()
    automaton = Automaton(door, door.open)

    print 'door is', automaton.state
    automaton.state = door.closed
    print 'door is', automaton.state
    automaton.state = door.open
    print 'door is', automaton.state
    door.blocked = True
    automaton.state = door.closed
    print 'door is', automaton.state

вывод этой программы будет:

door is open
closing door
door is closed
opening door
door is open
door is open

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