Python - передавать только аргументы, если существует переменная

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

color = request.GET.get ('color')
size = request.GET.get ('size')

Теперь я хочу передать эти переменные функции, но только если они существуют. Если они не существуют, я хочу просто запустить функцию без аргументов.

функция без аргументов:

apicall = search ()

с цветом только это

apicall = search (color)

и с цветом и размером

apicall = search (color, size)

Если аргумент определен, я хочу передать его функции, но если это не так, я не хочу его передавать.

Каков наиболее эффективный способ сделать это? Есть ли у python встроенные методы для этого?

Ответ 1

Предполагая, что стандартный вызов get (например, в словаре), это должно быть легко. Определите свою функцию с помощью None для параметров по умолчанию для ваших параметров, а затем передайте color и size, не утруждая себя проверкой!

def apicall(color=None, size=None):
    pass # Do stuff

color = request.GET.get('color')
size = request.GET.get('size')
apicall(color, size)

Таким образом, вы проверяете только аргументы None в одном месте (внутри вызова функции, где вам все равно нужно проверить, может ли функция вызываться несколькими способами). Все остается красивым и чистым. Конечно, это предполагает (как я сказал вверху), что ваш вызов get похож на обычный метод словаря Python get, который возвращает None, если значение не найдено.

Наконец, я заметил, что ваше имя функции apicall: есть шанс, что у вас фактически нет доступа к самому коду функции. В этом случае, поскольку вы можете ничего не знать о значениях по умолчанию для сигнатуры функции, а None может быть неправильным, я, вероятно, просто напишу простую оболочку для проверки аргументов. Затем вы можете вызвать оболочку, как указано выше.

def wrapped_apicall(color=None, size=None):
    if color is None and size is None:
        return apicall()
    # At least one argument is not None, so...
    if size is None:
        # color is not None
        return apicall(color)
    if color is None: 
        # size is not None
        return apicall(size)
    # Neither argument is None
    return apicall(color, size)

ПРИМЕЧАНИЕ.. Эта вторая версия не нужна, если вы не видите код, который вы вызываете, и у вас нет документации! Использование None в качестве аргумента по умолчанию очень распространено, поэтому есть вероятность, что вы можете просто использовать первый способ. Я бы использовал только метод обертки, если вы не можете изменить вызываемую вами функцию, и вы не знаете, каковы ее аргументы по умолчанию (или его аргументы по умолчанию являются модульными константами или чем-то, но это довольно редко).

Ответ 2

Как бы мне ни нравилось @HenryKeiterрешение, Python предоставляет НАМНОГО более простой способ проверки параметров. На самом деле есть несколько разных решений.

  1. Например, если search() является автономной функцией и вы хотите просмотреть аргументы, вы можете использовать модуль inspect, как показано в этом решении.

Пример кода 1

>>> import inspect
>>> print(inspect.getfullargspec(search))

ArgSpec(args=['size', 'color'], varargs=None, keywords=None, defaults=(None, None))
  1. Однако, если search() является методом класса (мы назовем его Search), то вы можете просто использовать встроенную функцию vars, чтобы увидеть все методы класса и их параметры:

Пример кода 2

>>> import Search
>>> print(vars(Search))

mappingproxy({'__init__': <function Search.__init__(self, size, color)>,
                  'search': <function Search.search(self, size, color)})

Единственное предостережение, связанное со вторым методом, заключается в том, что он более полезен в качестве инструмента визуального контроля, чем программного, хотя технически можно сказать if 'size' in vars(Search)['search']: do something. Это просто не было бы очень надежно. Проще и прочнее сказать if 'size' in inspect.getfullargspec(Search.search).args: do something или for arg in inspect.getfullargsspec(Search.search).args: do something

Ответ 3

meybe вы можете использовать что-то вроде этого:

try:
    apicall = search (color, size)
else:
    apicall = search(color)

Ответ 4

В Python 3 вы можете упаковать их в список, отфильтровать его и использовать * -operator, чтобы распаковать список в качестве аргументов для search:

color = request.GET.get ('color')
size = request.GET.get ('size')
args = [ arg for arg in [color, size] if arg ]
search(*args)

Обратите внимание, однако, что если color ложный, а size верный, вы бы вызывали search с 1 аргументом, равным значению size, что, вероятно, было бы неправильно, но в исходном вопросе не упоминается желаемое поведение в этом случае.

(некромант, так как я искал лучшее решение, чем мое, но нашел этот вопрос)

Ответ 5

Когда вы определяете свой метод, если вы задаете аргумент по умолчанию, вы можете указать аргумент или нет.

def search(color=None, size=None):
    pass

Затем, когда вы его вызываете, вы можете указать аргумент ключевого слова по своему усмотрению. Оба они были бы действительны:

apicall = search(color=color)
apicall = search(size=size)