Conseguir que uma função Python retorne de forma limpa um escalar ou lista, dependendo do número de argumentos

StackOverflow https://stackoverflow.com/questions/4029001

Pergunta

Isenção de responsabilidade:Estou procurando uma solução Python 2.6, se houver.

Estou procurando uma função que retorne um único valor quando passado um único valor ou que retorne uma sequência quando passado vários valores:

>>> a = foo(1)
2
>>> b, c = foo(2, 5)
>>> b
3
>>> c
6

Para ser claro, isso é um esforço para fazer com que algumas chamadas de função pareçam mais bonitas do que:

a, = foo(1)

ou

a = foo(1)[0]

No momento, a solução deselegante é algo assim:

def foo(*args):
    results = [a + 1 for a in args]
    return results if len(results) > 1 else results[0]

Existe algum açúcar sintático (ou funções) que tornaria isso mais limpo?algo parecido com o seguinte?

def foo(*args):
    return *[a + 1 for a in args]
Foi útil?

Solução

Você pode facilmente escrever uma função scalify que retorna o elemento da lista se a lista tiver apenas um elemento, ou seja,ele tenta torná-lo um escalar (daí o nome).

def scalify(l):
    return l if len(l) > 1 else l[0]

Então você pode usá-lo em suas funções assim:

def foo(*args):
    return scalify([a + 1 for a in args])

Isso resolverá o problema, mas estou com aqueles que sugerem que você não faça isso.Por um motivo, exclui a iteração sobre o resultado, a menos que você saiba que passou pelo menos dois itens.Além disso, se você tiver uma lista, precisará descompactá-la ao chamar a função, perdendo sua "listidade" e saberá que poderá não obter uma lista de volta.Essas desvantagens parecem-me ofuscar qualquer benefício que você possa ver na técnica.

Outras dicas

Você sempre pode escrever um decorador para elidir essa instrução if, se isso for melhor para você:

import functools
def unpacked(method):
    @functools.wraps(method)
    def _decorator(*args):
        result = method(*args)
        return results if len(results) != 1 else results[0]
    return _decorator

Uso:

@unpacked
def foo(*args):
    return [arg + 1 for arg in args]

Você quer dizer que deseja uma tupla com o mesmo número de argumentos?Isto não é uma solução?

return tuple([a + 1 for a in args])

def foo(*args):
    return (None, args[0]+1 if args else None, map(lambda a: a + 1, args))[len(args) if len(args) < 3 else 2]

:-) é um inferno

Isso irá lidar com 0 ou mais argumentos, acho que é isso que você está procurando.

def foo(*args):
    return map(lambda x: x + 1, args) or [None]

editar:Eu revisei para adicionar uma lista None no caso de descompactar 0 argumentos

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top