在Python

时间:2016-09-30 20:56:49

标签: python design-patterns visitor

我是python的新手(〜一个月),我希望我能早点切换到它(经过多年的perl)。

问题:我希望对象根据其类型对同一方法调用具有不同的功能。这些方法是在运行时根据加载的模块(组成所有对象)分配的。

问题:我想知道是否有一种流行的设计模式,我可以使用而不是下面的,或者如果这已经有一个设计模式名称(我遗憾地没有正式的CS背景,并且知道这将有助于我的文档)

我有一个类层次结构(截至目前,其中26个具有3个基类)。只有基类有一些简单的方法(例如:add_child),每个派生类只使用新的数据属性(特定于派生类)扩展基类,必要时覆盖方法(例如:__str __)。

我正在处理节点属于不同类的树。然而,节点应该具有相同的特定方法名称(stringifyprint_treeemitevaltransform_X等,从而允许简单/盲目迭代器操作。每种方法可能会做一些不同的事情,但方法具有相同的调用名称(如 polymorphism )。

我主要想根据节点的类型向节点授予特定的能力(方法)。最初,我使用Visitor Pattern实现了这一点。但是,考虑到我在Python工作,我意识到自己并没有真正做到这一点。

在下面的示例中,我有动态分配给类的方法。注意,在下面的示例中,迭代/递归方法调用名称(print_tree)与函数名称(generic__print_tree)不同。

#astmethods.py
def generic__print_tree(self, level=1):
    """
    Desc: print nodes with indentation
    Target: Any tree node
    """
    print("{}> {}".format('-' * level, self))
    for child in self.children:
            child.print_tree((level + 1))


def ASTNode__stringify(self):
    """
    Desc: Return string representation of the tree under this node
    Target: AST/CFG nodes
    """
    text = str(self)
    for child in self.children:
            text += ", { " + child.stringify() + " }"
    return text

最后,模块具有此功能, extend_types()在模块init期间被调用。期望节点在此模块的上下文中根据其类型(而不是值)执行不同的操作。除非被覆盖,否则分配的方法是继承的。

# mainModule1.py
def extend_types():
    """
    Upgrade the AST node classes with neat functions for use within this module's context
    """
    # same simple functions across class hierarchies
    # I should just derive them both from a common base class to avoid this
    ASTNode.print_tree = generic__print_tree
    SimpleNode.print_tree = generic__print_tree

    # ASTNode and all derived class get this method
    ASTNode.stringify = ASTNode__stringify

    # All AST nodes get the base method, except for Ignore and Arraysel type nodes
    # traversal looks the same with child.tidy()
    ASTNode.tidy = ASTNode__tidy
    ASTIgnore.tidy = ASTIgnore__tidy
    ASTArraySel.tidy = ASTArraySel__tidy

    # All AST nodes get the base method, except for the Coverage and If type nodes
    ASTNode.transform_controlFlow = ASTNode__transform_controlFlow
    ASTCoverage.transform_controlFlow = ASTCoverage__transform_controlFlow
    ASTIf.transform_controlFlow = ASTIf__transform_controlFlow

编辑:删除了令人分心的信息,为单个模块上下文做了示例

1 个答案:

答案 0 :(得分:0)

问题摘要

忽略不相关的细节,这里的问题可归纳如下:

有一个基类和许多派生类。有一些功能应该适用于所有派生类,但取决于一些外部开关(在问题中:选择" 主要模块" )。

问题的想法是根据交换机对基类进行monkeypatch。

解决方案

取而代之的是,依赖于外部开关的功能应该分开。

例如:

Manager

现在使用的方法与原始代码略有不同:# There is a base class: class ASTNode(object): pass # There are many derived classes, e.g.: class ASTVar(ASTNode): pass # One implementation of function stringify or another # should be defined for all objects, depending on some external factor def stringify1(node): # something def stringify2(node): # something else # Depending on whatever, choose one of them: stringify = stringify1 的intead,现在有node.stringify()。但这并没有错。

... BTW

使用课程可能会更令人赏心悦目:

类NodeHandler1(对象):     def print_tree(node):         #做点什么

stringify(node)

但这根本不需要。

道德

不要monkeypatch。这总是糟糕的设计。