写作口译Python编写的。 是isinstance认为是有害的?

我移植过解释,因为我从斯卡拉创建Python这样的领域特定语言。 在这个过程中我试图找到一种方式,这样Python的效仿斯卡拉我广泛使用的情况下,职业特性。 最后,我使出使用isinstance,但留下的感觉,我可能失去了一些东西。

文章像这样的攻击利用isinstance的让我不知道是否有更好的方法来解决我的问题,不涉及一些基本的重写。

我已经建立了一个数字,分别代表不同类型的抽象语法树节点,如对于Python类,同时,打破,返回,声明等

斯卡拉允许这样的运营商评估的处理:

case EOp("==",EInt(l),EInt(r)) => EBool(l==r) case EOp("==",EBool(l),EBool(r)) => EBool(l==r)

到目前为止,对于港口到Python我已经广泛使用的elif块和isinstance调用来达到同样的效果,更详细和非Python的。 有没有更好的办法?

--------------解决方案-------------

摘要 :这是写编译器的常用方法,它就好了这里。

处理这种在其他语言中一个很常见的方式是通过“模式匹配”,这是你所描述什么。 我希望这是该名称case在斯卡拉声明。 它是一种非常常见的成语写编程语言的实现和工具:编译器,解释等。为什么这么好? 因为实现完全从数据分离(通常是坏的,但通常希望在编译器)。

然后的问题是,这种常见的成语编程语言的实现是一个反模式在Python。 嗯哦。 正如你可能会说,这是一个多语言问题是一个政治问题。 如果其他Pythonistas看到了代码,他们会尖叫; 如果其他语言的实现者看见了,他们会立刻理解它。

究其原因,这是一个反模式的Python是因为Python鼓励鸭类型接口:根据类型,你不应该有问题,而是他们应该在运行时,一个对象有可用的方法来定义。 如果你希望它是地道的Python·洛的回答能正常工作,但它增加了一些。

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

Addenum:

模式匹配可能是头号原因,人们喜欢编写编译器等功能性语言。

有经验的Python中的规则,如果你发现自己写的if / elif的语句,用相似的条件(例如一堆isinstance(中...)),那么你很可能解决问题的错误方式的一大块。

更好的方法,包括使用类和多态性,访问者模式,字典查询,等等。在你的情况使得与重载为不同类型的可以工作的运营商级(如上所述),所以可以用(类型,运营商)项目的字典。

是。

实例,而不是,只需使用多态性。 这是简单的。

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

本文不攻击isinstance 它的攻​​击使你的代码测试特定类的想法。

是的,有一个更好的办法。 或几个。 例如,你可以使一种类型的处理成一个函数,然后通过查找每个类型找到正确的功能。 喜欢这个:

def int_function(value):
# Do what you mean to do here

def str_function(value):
# Do what you mean to do here

type_function = {int: int_function, str: str_function, etc, etc}

def handle_value(value):
function = type_function[type(value)]
result = function(value)
print "Oh, lovely", result

如果你不想自己做这个注册表,你可以看一下Zope的组件架构,它可以处理这种通过接口和适配器,它真的很酷。 但是,这可能是矫枉过正。

更妙的是,如果你能以某种方式避免做任何类型的类型检查的,但可能会非常棘手。

在DSL我写了使用Python 3,我用了复合材料的设计模式,使各节点都多态性在他们的使用,因为·洛被推荐。

但是,当我读的输入来创建摆在首位的节点,我没有使用isinstance检查了很多(对像collections.Iterable等,它是由Python 3提供了抽象基类,这是在2.6,以及我相信),以及检查'__call__'因为可调用被允许在我的输入。 这是我发现这样做(格外递归参与),而不是仅仅试图对输入操作和捕获异常,这是我想到的另一种最彻底的方法。 我养自定义异常自己当输入无效让尽可能多的准确的故障信息成为可能。

使用isinstance这样的测试比使用类型()更普遍,因为isinstance将捕获的子类 - 如果你可以测试对抽象基类,这是所有的好。 见http://www.python.org/dev/peps/pep-3119/对抽象基类的信息。

在这种特殊情况下,你似乎有什么要实现的一个操作符重载系统,使用对象的选择机制,您要拨打运营商的类型。 你的节点类型发生相当直接对应于您的语言的类型,但在现实中你写一个解释。 节点的类型仅仅是一个数据片。

我不知道如果人们可以添加自己的类型,你的领域特定语言。 但我会建议一个表驱动的设计不管。

使含有(binary_operator,TYPE1,TYPE2,result_type的,evalfunc)的数据表。 通过搜索该表使用isinstance比赛和有一定的标准,更喜欢一些比赛比其他。 它可能会使用一个较为复杂的数据结构不是一个表来使搜索更快,但现在你基本上使用的ifelse语句一长串做线性搜索,无论如何,所以我敢说一个普通的旧表将比你在做什么,现在稍快。

我不认为isinstance是错误的选择这里主要是因为该型只是一张你的翻译正在与做决定的数据。 双调度和同类的其他技术都只是去掩盖你的程序在做真正的肉。

其中的一个巧妙的事情在Python是,由于操作功能和类型都是一流的对象,你可以直接他们的东西在表中(或任何数据结构,你选择)。

如果你需要多态的参数(除接收器),例如处理类型转换二进制运营商所建议的你的榜样,您可以使用下面的技巧:

class EValue(object):

def __init__(self, v):
self.value = v

def __str__(self):
return str(self.value)

def opequal(self, r):
r.opequal_value(self)

def opequal_int(self, l):
print "(int)", l, "==", "(value)", self

def opequal_bool(self, l):
print "(bool)", l, "==", "(value)", self

def opequal_value(self, l):
print "(value)", l, "==", "(value)", self

class EInt(EValue):

def opequal(self, r):
r.opequal_int(self)

def opequal_int(self, l):
print "(int)", l, "==", "(int)", self

def opequal_bool(self, l):
print "(bool)", l, "==", "(int)", self

def opequal_value(self, l):
print "(value)", l, "==", "(int)", self

class EBool(EValue):

def opequal(self, r):
r.opequal_bool(self)

def opequal_int(self, l):
print "(int)", l, "==", "(bool)", self

def opequal_bool(self, l):
print "(bool)", l, "==", "(bool)", self

def opequal_value(self, l):
print "(value)", l, "==", "(bool)", self

if __name__ == "__main__":

v1 = EBool("true")
v2 = EInt(5)
v1.opequal(v2)

分类:蟒蛇 时间:2012-04-10 人气:0
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 0.352 (s). 10 q(s)