Как реализовать декоратор с нелокальным равенством? - PullRequest
2 голосов
/ 24 сентября 2008

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

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

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

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

Судя по первым пяти пунктам, это звучит как чистый декоратор с базовым переходом и двумя декораторами: Labeled и Condition. Однако у этого подхода есть проблема: два перехода считаются равными, если их начальное состояние и конечное состояние одинаковы, метки на обоих переходах равны (или не существуют), и оба условия одинаковы (или не существуют) , С помощью декоратора у меня может быть два перехода с метками ("foo", Conditional ("bar", Transition ("baz", "qux"))) и Conditional ("bar", Labeled ("foo", Transition ("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.

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

EDIT : Добавлен ConditionalTransition-класс. По сути, этот вид ведет себя как декоратор, за исключением порядка, созданного порядком создания декораторов, переходы проверяют правильность начала и конца, класс LabeledTransition проверяет правильность метки и проверяет ConditionalTransition условие правильное.

Ответы [ 2 ]

2 голосов
/ 20 октября 2008

Я думаю, ясно, что никто не понимает ваш вопрос. Я бы предложил поместить это в контекст и сделать его короче. Например, вот одна из возможных реализаций шаблона состояния в 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
0 голосов
/ 24 сентября 2008

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

return self.label is not None

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...