【问题标题】:Name a positional parameter "from"将位置参数命名为“from”
【发布时间】:2016-09-21 23:54:23
【问题描述】:

我正在编写一个脚本来将 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 添加一堆额外的逻辑(未显示)。有没有更简单的解决方法不会在使用时使语法膨胀?

【问题讨论】:

    标签: python-3.x parameter-passing


    【解决方案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) {
    

    【讨论】:

    • 在这种情况下,如果有多余的参数,我也希望匹配失败——这样,意外的属性就不会被静默丢失。
    猜你喜欢
    • 1970-01-01
    • 2016-01-08
    • 2015-11-16
    • 2016-11-14
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    相关资源
    最近更新 更多