Условная передача произвольного числа именованных аргументов по умолчанию в функцию - PullRequest
10 голосов
/ 12 января 2011

Можно ли условно передать произвольное количество именованных аргументов по умолчанию в функцию Python?

Например, есть функция:

def func(arg, arg2='', arg3='def')

Теперь логика заключается в том, что у меня есть условие, которое определяет, нужно ли передавать arg3, я могу сделать это так:

if condition == True:
    func('arg', arg2='arg2', arg3='some value')
else:
    func('arg', arg2='arg2')

Вопрос в том, можно ли записать сокращение:

func('arg', 'arg2', 'some value' if condition == True else # nothing so default gets picked
)

Ответы [ 4 ]

9 голосов
/ 12 января 2011

Это не будет действительным синтаксисом Python, вы должны иметь что-то после else.Обычно выполняется:

func('arg', 'arg2', 'some value' if condition else None)

, и определение функции изменяется соответственно:

def func(arg, arg2='', arg3=None):
    arg3 = 'def' if arg3 is None else arg3
7 голосов
/ 12 января 2011

Единственный способ, которым я могу думать, будет

func("arg", "arg2", **({"arg3": "some value"} if condition == True else {}))

или

func("arg", "arg2", *(("some value",) if condition == True else ()))

но, пожалуйста, не делай этого. Используйте предоставленный вами код или что-то вроде этого:

if condition:
   arg3 = "some value",
else:
   arg3 = ()
func("arg", "arg2", *arg3)
2 голосов
/ 12 января 2011

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

def lots_of_defaults(arg1 = "foo", arg2 = "bar", arg3 = "baz", arg4 = "blah"):
    pass

и вы хотите передать различные значения некоторым из них, основываясь на том, что происходит в вашей программе, простым способом является использование ** для распаковки словаря имен аргументов и значений, которые вы создали на основе вашей программы логика.

different_than_defaults = {}
if foobar:
    different_than_defaults["arg1"] = "baaaz"
if barblah:
    different_than_defaults["arg4"] = "bleck"

lots_of_defaults(**different_than_defaults)

Преимущество этого состоит в том, что вы не засоряете ваш код в момент вызова вашей функции, если существует много логики, определяющей, что входит в ваш вызов. Вам нужно быть осторожным, если у вас есть какие-либо аргументы, которые не имеют значений по умолчанию, чтобы включить значения, которые вы передаете для них перед передачей словаря.

0 голосов
/ 02 февраля 2015

Вы можете написать вспомогательную функцию

def caller(func, *args, **kwargs):
    return func(*args, **{k:v for k,v in kwargs.items() if v != caller.DONT_PASS})
caller.DONT_PASS = object()

Используйте эту функцию для вызова другой функции и используйте caller.DONT_PASS для указания аргументов, которые вы не хотите передавать.

caller(func, 'arg', 'arg2', arg3 = 'some value' if condition else caller.DONT_PASS)

Обратите внимание, что caller() поддерживает только условную передачу аргументов ключевых слов.Для поддержки позиционных аргументов вам может понадобиться использовать модуль inspect для проверки функции.

...