发布
社区首页 >问答首页 >用Python编写解释器。实例被认为是有害的吗?

用Python编写解释器。实例被认为是有害的吗?
EN

Stack Overflow用户
提问于 2009-09-04 22:45:14
回答 7查看 2K关注 0票数 4

我正在将我创建的领域特定语言的解释器从Scala移植到Python。在这个过程中,我试图找到一种方法来模仿我广泛使用的Scala的case类特性。最后,我求助于使用isinstance,但留下的感觉是我可能遗漏了什么。

this one这样抨击isinstance使用的文章让我想知道是否有更好的方法来解决我的问题,而不涉及一些根本性的重写。

我构建了许多Python类,每个类表示一种不同类型的抽象语法树节点,例如For、While、Break、Return、Statement等

Scala允许像这样处理运算符求值:

代码语言:javascript
代码运行次数:0
复制
case EOp("==",EInt(l),EInt(r)) => EBool(l==r)
case EOp("==",EBool(l),EBool(r)) => EBool(l==r)

到目前为止,为了移植到Python,我广泛地使用了elif块和isinstance调用来达到同样的效果,更加冗长和非Python风格。有没有更好的方法?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2009-09-07 16:04:00

总结:这是编写编译器的常用方法,在这里很好。

在其他语言中,处理此问题的一种非常常见的方法是“模式匹配”,这正是您所描述的。我希望这就是Scala中case语句的名称。这是编写编程语言实现和工具的一个非常常见的习惯用法:编译器、解释器等。为什么它这么好?因为实现与数据完全分离(这通常是不好的,但在编译器中通常是可取的)。

因此,问题是这种编程语言实现的通用习惯用法是Python中的反模式。啊哦。正如你可能知道的,这与其说是语言问题,不如说是一个政治问题。如果其他Pythonistas看到代码,他们会尖叫;如果其他语言实现者看到它,他们会立即理解它。

这在Python中是反模式的原因是因为Python鼓励鸭型接口:您不应该有基于类型的行为,而应该由对象在运行时可用的方法来定义它们。如果您希望S. Lott's answer成为惯用的Python,那么它可以很好地工作,但是它添加的东西很少。

我怀疑您的设计并不是真正的鸭子类型--毕竟它是一个编译器,并且使用名称和静态结构定义的类非常常见。如果您愿意,您可以认为您的对象有一个“类型”字段,isinstance用于基于该类型进行模式匹配。

附件:

模式匹配可能是人们喜欢用函数式语言编写编译器等的首要原因。

票数 2
EN

Stack Overflow用户

发布于 2009-09-04 23:22:44

是。

只需使用Polymorphism,而不是实例。这更简单。

代码语言:javascript
代码运行次数:0
复制
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

像这样的需要强制的东西怎么样?

代码语言:javascript
代码运行次数:0
复制
Add( Double(this), Integer(that) )

这仍然是一个多态问题。

代码语言:javascript
代码运行次数:0
复制
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
票数 2
EN

Stack Overflow用户

发布于 2009-09-06 01:15:23

在python中有一条经验法则,如果您发现自己编写了一大块if/elif语句,具有类似的条件(一堆isinstance(...)例如),那么你可能以错误的方式解决了问题。

更好的方法包括使用类和多态性,访问者模式,dict查找,等等。在你的例子中,为不同的类型创建一个具有重载的operator类可以工作(如上所述),所以使用(type,operator)项的dict也可以。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1381845

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档