Ottenere una funzione Python per tornare in modo pulito uno scalare o di lista, a seconda del numero di argomenti

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

Domanda

Disclaimer:. Sto cercando una soluzione Python 2.6, se ce n'è uno

Sto cercando una funzione che restituisce un singolo valore quando viene passato un singolo valore, o che restituisce una sequenza quando viene passato più valori:

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

Per essere chiari, questo è in uno sforzo per fare alcune chiamate di funzione basta guardare più bello di:

a, = foo(1)

o

a = foo(1)[0]

In questo momento, la soluzione poco elegante è qualcosa in queste righe:

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

C'è qualche zucchero sintattico (o funzioni) che renderebbe questo pulitore sensazione? qualcosa di simile al seguente?

def foo(*args):
    return *[a + 1 for a in args]
È stato utile?

Soluzione

Si può facilmente scrivere una funzione scalify che restituisce l'elemento dalla lista se la lista ha un solo elemento, vale a dire si cerca di renderlo uno scalare (da qui il nome).

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

Quindi è possibile utilizzare nelle vostre funzioni in questo modo:

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

Questo farà il trucco, ma sono con coloro che vi consiglio di non farlo. Per una ragione, si esclude l'iterazione sul risultato se non si sa che avete passato in almeno due elementi. Inoltre, se si dispone di un elenco, è necessario decomprimere la lista quando si chiama la funzione, perdendo la sua "listness", e sai che non si può ottenere una lista di nuovo. Questi inconvenienti mi sembrano passare in secondo piano qualsiasi beneficio che può vedere alla tecnica.

Altri suggerimenti

È sempre possibile scrivere un decoratore per elidere che if se questo è più bello a voi:

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

Utilizzo:

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

Vuoi dire che si desidera una tupla con lo stesso numero di argomenti? Non è questa una soluzione?

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]

:-) è l'inferno

Questa gestirà 0 o più argomenti, credo che questo è quello che stai cercando.

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

edit: ho rivisto per aggiungere una lista Nessuno in caso di disimballaggio 0 args

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top