从"中命名一个位置参数"

时间:2016-09-21 23:54:23

标签: python-3.x parameter-passing

我正在编写一个脚本来将ColdFusion CFML代码转换为CFScript代码。在许多地方,它将采用属性字典,查看函数列表,并调用第一个参数与给定属性匹配的字典作为关键字args:

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 个答案:

答案 0 :(得分:1)

这可能对您的用例来说太简单了(或者您甚至可能会考虑这个&#34;在使用时膨胀语法&#34;);但是你能依靠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) {