Правильный способ использования * * kwargs в Python
что такое правильный способ, чтобы использовать **kwargs
в Python, когда дело доходит до значений по умолчанию?
kwargs
возвращает словарь, но каков наилучший способ установить значения по умолчанию, или есть один? Должен ли я просто получить доступ к нему как к словарю? Использовать функции get?
class ExampleClass:
def __init__(self, **kwargs):
self.val = kwargs['val']
self.val2 = kwargs.get('val2')
простой вопрос, но я не могу найти хорошие ресурсы. Люди делают это по-разному в коде, который я видел, и трудно знать, что использовать.
13 ответов:
вы можете передать значение по умолчанию
get()
для ключей, которых нет в словаре:, Если вы планируете использовать конкретный аргумент с определенным значением по умолчанию, почему бы не использовать именованные аргументы в первую очередь?self.val2 = kwargs.get('val2',"default value")
def __init__(self, val2="default value", **kwargs):
в то время как большинство ответов говорят, что, например,
def f(**kwargs): foo = kwargs.pop('foo') bar = kwargs.pop('bar') ...etc...
это "то же самое, что"
def f(foo=None, bar=None, **kwargs): ...etc...
это не правда. В последнем случае
f
можно назватьf(23, 42)
, в то время как первый случай принимает именованные аргументы только -- нет позиционных вызовов. Часто вы хотите предоставить вызывающему максимальную гибкость, и поэтому вторая форма, как утверждают большинство ответов, предпочтительнее: но это не всегда так. Когда вы принимаете много опционных параметров которые, как правило, только несколько передаются, это может быть отличная идея (во избежание несчастных случаев и нечитаемый код на ваших сайтах вызовов!) для принудительного использования именованных аргументов --threading.Thread
пример. Первая форма - это то, как вы реализуете это в Python 2.идиома настолько важна, что в Python 3 она теперь имеет специальный поддерживающий синтаксис: каждый аргумент после одного
*
наdef
подпись-только ключевое слово, то есть не может быть передана как позиционный аргумент, а только как именованный один. Так что в Python 3 Вы можете закодировать выше как:def f(*, foo=None, bar=None, **kwargs): ...etc...
действительно, в Python 3 Вы даже можете иметь только ключевые слова аргументы, которые не необязательно (без значения по умолчанию).
тем не менее, Python 2 все еще имеет долгие годы продуктивной жизни впереди, так что лучше не забудьте о методах и идиомах, которые позволяют реализовать в Python 2 важные дизайнерские идеи, которые непосредственно поддерживаются на языке Python 3!
Я предлагаю что-то вроде этого
def testFunc( **kwargs ): options = { 'option1' : 'default_value1', 'option2' : 'default_value2', 'option3' : 'default_value3', } options.update(kwargs) print options testFunc( option1='new_value1', option3='new_value3' ) # {'option2': 'default_value2', 'option3': 'new_value3', 'option1': 'new_value1'} testFunc( option2='new_value2' ) # {'option1': 'default_value1', 'option3': 'default_value3', 'option2': 'new_value2'}
а затем использовать значения так, как вы хотите
dictionaryA.update(dictionaryB)
добавляет содержимоеdictionaryB
доdictionaryA
перезапись любых дубликатов ключей.
ты
self.attribute = kwargs.pop('name', default_value)
или
self.attribute = kwargs.get('name', default_value)
Если вы используете
pop
, то вы можете проверить, если есть какие-либо ложные значения отправлены, и принять соответствующие меры (если таковые имеются).
использовать **kwargs и значения по умолчанию легко. Иногда, однако, вы не должны использовать **kwargs в первую очередь.
в этом случае мы не очень хорошо используем * * кварги.
class ExampleClass( object ): def __init__(self, **kwargs): self.val = kwargs.get('val',"default1") self.val2 = kwargs.get('val2',"default2")
выше-это "зачем?" декларация. Это то же самое, что
class ExampleClass( object ): def __init__(self, val="default1", val2="default2"): self.val = val self.val2 = val2
когда вы используете * * kwargs, вы имеете в виду, что ключевое слово не просто необязательно, но условно. Существуют более сложные правила, чем простые значения по умолчанию.
когда ты используя * * kwargs, вы обычно имеете в виду что-то вроде следующего, где простые значения по умолчанию не применяются.
class ExampleClass( object ): def __init__(self, **kwargs): self.val = "default1" self.val2 = "default2" if "val" in kwargs: self.val = kwargs["val"] self.val2 = 2*self.val elif "val2" in kwargs: self.val2 = kwargs["val2"] self.val = self.val2 / 2 else: raise TypeError( "must provide val= or val2= parameter values" )
С
**kwargs
используется, когда количество аргументов неизвестно, почему бы не сделать это?class Exampleclass(object): def __init__(self, **kwargs): for k in kwargs.keys(): if k in [acceptable_keys_list]: self.__setattr__(k, kwargs[k])
вот еще один подход:
def my_func(arg1, arg2, arg3): ... so something ... kwargs = {'arg1': 'Value One', 'arg2': 'Value Two', 'arg3': 'Value Three'} # Now you can call the function with kwargs like this: my_func(**kwargs)
Я думаю, что правильный способ использовать
**kwargs
в Python, когда речь заходит о значениях по умолчанию, следует использовать метод словаряsetdefault
, как указано ниже:class ExampleClass: def __init__(self, **kwargs): kwargs.setdefault('val', value1) kwargs.setdefault('val2', value2)
таким образом, если пользователь передает 'val' или 'val2' в Ключевое слово
args
, они будут использоваться; в противном случае будут использоваться значения по умолчанию, которые были установлены.
вы могли бы сделать что-то подобное
class ExampleClass: def __init__(self, **kwargs): arguments = {'val':1, 'val2':2} arguments.update(kwargs) self.val = arguments['val'] self.val2 = arguments['val2']
на @srhegde предложение использовать setattr:
class ExampleClass(object): __acceptable_keys_list = ['foo', 'bar'] def __init__(self, **kwargs): [self.__setattr__(key, kwargs.get(key)) for key in self.__acceptable_keys_list]
этот вариант полезен, когда класс должен иметь все элементы в нашем
acceptable
список.
Если вы хотите объединить это с *args, вы должны сохранить *args и * * kwargs в конце определения.
Так:
def method(foo, bar=None, *args, **kwargs): do_something_with(foo, bar) some_other_function(*args, **kwargs)
@AbhinavGupta и @Steef предложили использовать
update()
, который я нашел очень полезным для обработки больших списков аргументов:args.update(kwargs)
что делать, если мы хотим проверить, что пользователь не передал никаких ложных/неподдерживаемых аргументов? @VinaySajip указал, что
pop()
может использоваться для итеративной обработки списка аргументов. Тогда любые оставшиеся аргументы являются ложными. Милый.вот еще один возможный способ сделать это, который держит простой синтаксис использования
update()
:# kwargs = dictionary of user-supplied arguments # args = dictionary containing default arguments # Check that user hasn't given spurious arguments unknown_args = user_args.keys() - default_args.keys() if unknown_args: raise TypeError('Unknown arguments: {}'.format(unknown_args)) # Update args to contain user-supplied arguments args.update(kwargs)
unknown_args
этоset
содержит имена аргументов, которые не встречаются в настройках по умолчанию.