如何实现具有非本地相等性的Decorator?
问候语,目前我正在重构其中一个程序,但发现了一个有趣的问题。
我在自动机中有转场。过渡始终具有开始状态和结束状态。某些转换具有标签,该标签编码必须在遍历时执行的特定操作。没有标签意味着没有动作。某些转换具有条件,以便遍历此条件,如果没有条件,则该过渡基本上是NFA中的epsilon过渡,并且无需消耗输入符号即可遍历。
我需要执行以下操作:
- 检查过渡是否有标签
- 得到这个标签
- 为过渡添加标签
- 检查过渡是否有条件
- 得到这个条件
- 检查是否平等
从前五个点来看,这听起来像是一个清晰的装饰器,带有一个基本过渡和两个装饰器:Labeled和Condition。但是,此方法有一个问题:如果两个过渡的开始状态和结束状态相同,则两个过渡被视为相等,两个过渡处的标签相等(或者不存在),并且两个条件相同(或者不存在) 。使用装饰器,我可能会有两个过渡Labeled(" foo",Conditional(" bar",Transition(" baz"," qux"))))和Conditional(" bar",Labeled(" foo",Transition(" baz "," qux")))),它需要一个非本地的相等性,也就是说,装饰者将需要收集所有数据,并且Transition必须在集合基础上比较此收集的数据:
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中的所有内容将所有内容锤击成一个过渡类。
所以...我很困惑。我想念什么吗?哪种实施看起来更好?我们如何处理类似的情况,也就是说,看起来像Decorator的对象可以处理它们,但是随后出现了这样的非本地方法?
编辑:
添加了ConditionalTransition类。基本上,这种行为类似于装饰器,减去由创建装饰器的顺序创建的顺序,开始和结束的过渡检查正确,LabeledTransition-class检查标签正确,而ConditionalTransition检查条件正确。
解决方案
从发布的代码来看,Transition和Labeled Transition之间的唯一区别是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