繁体   English   中英

如何实现具有非本地相等性的装饰器?

[英]How to implement a Decorator with non-local equality?

您好,目前我正在重构我的一个程序,我发现了一个有趣的问题。

我在自动机中有转换。 转换总是有一个开始状态和一个结束状态。 一些转换有一个标签,它对遍历时必须执行的某个动作进行编码。 没有标签意味着没有行动。 某些转换有一个条件,必须满足该条件才能遍历此条件,如果没有条件,则转换基本上是 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 在这种规模下会令人困惑。

当然,第三种选择是将所有东西都锤成一个带有一堆 inhas_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类的代码吗? 我想这会让它更清楚。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM