2008-09-24 6 views
2

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

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

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

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

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

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

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

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.

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

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

+0

смотрит на меня, как вы пытаетесь писать код Java в Python. – hop

ответ

2

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

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

return self.label is not None 

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

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