我正在将我创建的领域特定语言的解释器从Scala移植到Python。在这个过程中,我试图找到一种方法来模仿我广泛使用的Scala的case类特性。最后,我求助于使用isinstance,但留下的感觉是我可能遗漏了什么。
像this one这样抨击isinstance使用的文章让我想知道是否有更好的方法来解决我的问题,而不涉及一些根本性的重写。
我构建了许多Python类,每个类表示一种不同类型的抽象语法树节点,例如For、While、Break、Return、Statement等
Scala允许像这样处理运算符求值:
case EOp("==",EInt(l),EInt(r)) => EBool(l==r)
case EOp("==",EBool(l),EBool(r)) => EBool(l==r)
到目前为止,为了移植到Python,我广泛地使用了elif块和isinstance调用来达到同样的效果,更加冗长和非Python风格。有没有更好的方法?
发布于 2009-09-07 16:04:00
总结:这是编写编译器的常用方法,在这里很好。
在其他语言中,处理此问题的一种非常常见的方法是“模式匹配”,这正是您所描述的。我希望这就是Scala中case
语句的名称。这是编写编程语言实现和工具的一个非常常见的习惯用法:编译器、解释器等。为什么它这么好?因为实现与数据完全分离(这通常是不好的,但在编译器中通常是可取的)。
因此,问题是这种编程语言实现的通用习惯用法是Python中的反模式。啊哦。正如你可能知道的,这与其说是语言问题,不如说是一个政治问题。如果其他Pythonistas看到代码,他们会尖叫;如果其他语言实现者看到它,他们会立即理解它。
这在Python中是反模式的原因是因为Python鼓励鸭型接口:您不应该有基于类型的行为,而应该由对象在运行时可用的方法来定义它们。如果您希望S. Lott's answer成为惯用的Python,那么它可以很好地工作,但是它添加的东西很少。
我怀疑您的设计并不是真正的鸭子类型--毕竟它是一个编译器,并且使用名称和静态结构定义的类非常常见。如果您愿意,您可以认为您的对象有一个“类型”字段,isinstance
用于基于该类型进行模式匹配。
附件:
模式匹配可能是人们喜欢用函数式语言编写编译器等的首要原因。
发布于 2009-09-04 23:22:44
是。
只需使用Polymorphism,而不是实例。这更简单。
class Node( object ):
def eval( self, context ):
raise NotImplementedError
class Add( object ):
def eval( self, context ):
return self.arg1.eval( context ) + self.arg2.eval( context )
这种方式非常简单,而且不需要isinstance
。
像这样的需要强制的东西怎么样?
Add( Double(this), Integer(that) )
这仍然是一个多态问题。
class MyType( object ):
rank= None
def coerce( self, another ):
return NotImplemented
class Double( object ):
rank = 2
def coerce( self, another ):
return another.toDouble()
def toDouble( self ):
return self
def toInteger( self ):
return int(self)
class Integer( object ):
rank = 1
def coerce( self, another ):
return another.toInteger()
def toDouble( self ):
return float(self)
def toInteger( self ):
return self
class Operation( Node ):
def conform( self, another ):
if self.rank > another.rank:
this, that = self, self.coerce( another )
else:
this, that = another.coerce( self ), another
return this, that
def add( self, another ):
this, that = self.coerce( another )
return this + that
发布于 2009-09-06 01:15:23
在python中有一条经验法则,如果您发现自己编写了一大块if/elif语句,具有类似的条件(一堆isinstance(...)例如),那么你可能以错误的方式解决了问题。
更好的方法包括使用类和多态性,访问者模式,dict查找,等等。在你的例子中,为不同的类型创建一个具有重载的operator类可以工作(如上所述),所以使用(type,operator)项的dict也可以。
https://stackoverflow.com/questions/1381845
复制相似问题