2016-09-21 136 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

在這種情況下,如果有多餘的參數,我也希望一個匹配失敗 - 這樣,意外的屬性就不會被默默地丟失。 –