2016-09-21 87 views
1

我正在编写一个脚本来将ColdFusion CFML代码转换为CFScript代码。在许多地方,它会带属性的字典,通过功能的列表中查找,并调用第一个其参数匹配给定的属性与字典作为关键字ARGS:命名位置参数“from”

import inspect 

def invokeFirst(attributes, *handlers): 
    given_args = set(attributes) 

    for handler in handlers: 
     meta = inspect.getargspec(handler) 

     allowed_args = set(meta.args) 
     required_args = set(meta.args[:-len(meta.defaults)]) if meta.defaults else meta.args 

     if required_args <= given_args and (meta.keywords or given_args <= allowed_args): 
      return handler(**attributes) 

    raise TypeError("Can't invoke with arguments {}.".format(str(given_args))) 

使用示例:

def replaceLoop(tag): 
    forIn = 'for (var {item} in {collection}) {{' 

    return invokeFirst(tag.attributes, 
     lambda item, collection: forIn.format(item=bare(item) , collection=collection), 
     lambda index, array : forIn.format(item=bare(index), collection=index), 

     lambda _from, to, index: 
      'for (var {index} = {min}; {index} <= {max}; {index}++) {{'.format(
       index=bare(index), min=_from, max=to, 
      ), 
    ) 

现在,因为from不是有效的参数名称,所以我必须在lambda表达式中加前缀,并向invokeFirst(未显示)添加一堆额外的逻辑。有没有更简单的解决方法,不会在使用时膨胀语法?

回答

1

这对于您的用例来说可能过于简单(或者您甚至可能认为这是“在使用点上膨胀了语法”);但是你能依靠Python的EAFP原则:尝试调用函数,并忽略任何异常?例如:

def invokeFirst(attributes, *handlers): 

    for handler in handlers: 
     try: 
      val = handler(attributes) 
      return val 
     except (KeyError, TypeError): 
      pass 

    raise TypeError("Can't invoke with arguments {}.".format(str(attributes))) 


def replaceLoop(tag): 
    forIn = 'for (var {item} in {collection}) {{' 

    return invokeFirst(tag.attributes, 
     lambda d: forIn.format(item=bare(d['item']) , collection=d['collection']), 
     lambda d: forIn.format(item=bare(d['index']), collection=d['index']), 
     lambda d: 
      'for (var {index} = {min}; {index} <= {max}; {index}++) {{'.format(
       index=bare(d['index']), min=d['from'], max=d['to'], 
      ) 

    ) 

bare = lambda b: b  

class Tag: 
    def __init__(self, dct): 
     self.attributes = dct 

tag = Tag({'item':4}) 
print(replaceLoop(tag)) 

#satisfies 2nd function - outputs: 
for (var 4 in 4) { 
+0

在这种情况下,如果有多余的参数,我也希望一个匹配失败 - 这样,意外的属性就不会被默默地丢失。 –