Получение функции Python для чистого возврата скаляра или списка, в зависимости от количества аргументов - PullRequest
4 голосов
/ 27 октября 2010

Отказ от ответственности: я ищу решение Python 2.6, если оно есть.

Я ищу функцию, которая возвращает одно значение при передаче одного значения или возвращает последовательность при передаче нескольких значений:

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

Для ясности, это попытка заставить некоторые вызовы функций выглядеть просто лучше, чем:

a, = foo(1)

или

a = foo(1)[0]

Прямо сейчас, не элегантное решение - что-то вроде этого:

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

Есть ли какой-нибудь синтаксический сахар (или функции), который бы чувствовал себя чище? что-нибудь вроде следующего?

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

Ответы [ 5 ]

6 голосов
/ 27 октября 2010

Вы можете легко написать функцию scalify, которая возвращает элемент из списка, если список содержит только один элемент, то есть он пытается сделать его скалярным (отсюда и имя).

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

Тогда вы можете использовать его в своих функциях следующим образом:

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

Это поможет, но я с теми, кто предлагает тебе не делать этого. По одной причине он исключает итерацию по результату, если только вы не знаете, что передали хотя бы два элемента. Кроме того, если у вас есть список, вы должны распаковать список при вызове функции, потеряв ее «списанность», и вы знаете, что вы не сможете получить список обратно. Мне кажется, что эти недостатки затмевают любую пользу, которую вы можете видеть в технике.

6 голосов
/ 27 октября 2010

Вы всегда можете написать декоратор, чтобы исключить оператор if, если вам это нравится:

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

Использование:

@unpacked
def foo(*args):
    return [arg + 1 for arg in args]
1 голос
/ 27 октября 2010

Вы хотите сказать, что хотите кортеж с таким же количеством аргументов? Разве это не решение?

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

0 голосов
/ 27 октября 2010

Это будет обрабатывать 0 или более аргументов, я думаю, это то, что вы ищете.

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

edit: я исправил добавление списка None в случае распаковки 0 аргументов

0 голосов
/ 27 октября 2010
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]

:-) это ад

...