2010-10-27 37 views
4

Avertissement: Je suis à la recherche d'une solution Python 2.6, s'il y en a une.Obtenir une fonction Python pour retourner proprement un scalaire ou une liste, en fonction du nombre d'arguments

Je suis à la recherche d'une fonction qui retourne une valeur unique lorsqu'il est passé une seule valeur, ou qui retourne une séquence lorsqu'il est passé plusieurs valeurs:

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

Pour être clair, cela est dans le but de faire certains appels de fonctions semblent simplement plus agréable que:

a, = foo(1) 

ou

a = foo(1)[0] 

En ce moment, la solution inélégante est quelque chose le long de ces lignes:

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

Y at-il du sucre syntaxique (ou fonctions) qui en ferait sentir plus propre? quelque chose comme le suivant?

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

Pourquoi? Il semble que vous voulez juste des listes de compréhension. – JoshD

+5

il semble que quelque chose ne va pas avec votre design parce que vous voulez une fonction pour retourner une liste ou un int en fonction du nombre d'arguments, pff !! pourquoi ne pas rendre votre fonction toujours retourner une liste et utiliser cette notation pour votre premier exemple: a, = foo (1) – mouad

+0

C'est surtout une chose syntaxique de sucre et de lisibilité dans mon esprit.a = foo (1) est beaucoup plus clair (surtout quand les entrées et les sorties ont des arguments et des noms de variables plus complexes) – Nevir

Répondre

4

Vous pouvez facilement écrire une fonction scalify qui renvoie l'élément de la liste si la liste ne comporte qu'un seul élément, à savoir qu'il essaie pour en faire un scalaire (d'où le nom).

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

Ensuite, vous pouvez l'utiliser dans vos fonctions comme ceci:

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

Cela fera l'affaire, mais je suis avec ceux qui vous suggère de ne pas le faire. Pour une raison, elle exclut l'itération sur le résultat sauf si vous savez que vous avez passé au moins deux éléments. En outre, si vous avez une liste, vous devez décompresser la liste lors de l'appel de la fonction, en perdant son "listness", et vous savez que vous ne pouvez pas récupérer une liste. Ces inconvénients me semblent éclipser tous les avantages que vous pouvez voir à la technique.

+0

Ce n'est pas assez, essayez de ne passer aucun args. – dcolish

+0

Même problème dans l'original, le comportement souhaité est donc indéfini. Mais si vous insérez un 'if l:' avant le corps 'scalify' que j'ai donné, vous obtiendrez' None' s'il n'y a pas de résultat. – kindall

6

Vous pouvez toujours écrire un décorateur à elide que si la déclaration si cela est plus agréable pour vous:

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 

Utilisation:

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

Bonne réponse à la mauvaise question;) – aaronasterling

+0

Jusqu'à présent, c'est définitivement la solution la plus propre: P – Nevir

+0

Vous pensez vraiment que c'est la solution la plus propre? – Falmarri

1

Voulez-vous dire que vous voulez un tuple avec le même nombre d'arguments? Est-ce que ce n'est pas une solution?

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

+0

Non car alors a = foo (1), l'impression a serait (2), pas 2. –

+0

Pas si vous le décompressez comme un, = foo (1) – dcolish

+0

il suffit de taper sur le python promt ceci: '2 == (2) 'et il vous dira si c'est le même ou pas (c'est) – knitti

0
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] 

:-) il est l'enfer

0

Cela traitera 0 ou plus args, je pense que c'est ce que vous cherchez.

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

modifier: Je révisé pour ajouter une liste Aucun Incase de déballage 0 args