如何实现非局部平等的装饰器?
-
02-07-2019 - |
题
您好,目前我正在重构我的一个程序,我发现了一个有趣的问题。
我在自动机中有转换。转换始终具有开始状态和结束状态。有些转换有一个标签,它对遍历时必须执行的某个操作进行编码。没有标签就意味着没有行动。有些转换有一个条件,必须满足该条件才能遍历该条件,如果没有条件,则转换基本上是 NFA 中的 epsilon 转换,并且将在不消耗输入符号的情况下进行遍历。
我需要进行以下操作:
- 检查过渡是否有标签
- 得到这个标签
- 为过渡添加标签
- 检查转换是否有条件
- 得到这个条件
- 检查是否相等
从前五点来看,这听起来像是一个清晰的装饰器,有一个基本过渡和两个装饰器:标签和状况。然而,这种方法有一个问题:如果两个转换的开始状态和结束状态相同,两个转换的标签相等(或不存在)并且两个条件相同(或不存在),则认为两个转换相等。使用装饰器,我可能有两个转换 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)
这是一种干净的方法吗?我错过了什么吗?
我很困惑,因为我可以使用更长的类名使用协作多重继承来解决这个问题:
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 检查条件是否正确。
解决方案
我认为很明显没有人真正理解你的问题。我建议将其放在上下文中并使其更短。作为一个例子,这里是 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
其他提示
从发布的代码来看,Transition 和 Labeled Transition 之间的唯一区别是 get_lable() 和 has_label() 的返回。在这种情况下,您可以将这两个压缩为一个类,将标签属性设置为 None 和
return self.label is not None
在 has_label() 函数中。
你能发布代码吗 ConditionalTransition
班级?我认为这会让事情变得更清楚。