我是python的新手(〜一个月),我希望我能早点切换到它(经过多年的perl)。
问题:我希望对象根据其类型对同一方法调用具有不同的功能。这些方法是在运行时根据加载的模块(组成所有对象)分配的。
问题:我想知道是否有一种流行的设计模式,我可以使用而不是下面的,或者如果这已经有一个设计模式名称(我遗憾地没有正式的CS背景,并且知道这将有助于我的文档)?
我有一个类层次结构(截至目前,其中26个具有3个基类)。只有基类有一些简单的方法(例如:add_child),每个派生类只使用新的数据属性(特定于派生类)扩展基类,必要时覆盖方法(例如:__str __)。
我正在处理节点属于不同类的树。然而,节点应该具有相同的特定方法名称(stringify
,print_tree
,emit
,eval
,transform_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
编辑:删除了令人分心的信息,为单个模块上下文做了示例
答案 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。这总是糟糕的设计。