Обычные аргументы против ключевых слов

290

Чем «аргументы ключевых слов» отличаются от обычных аргументов? Не могут ли все аргументы передаваться name=valueвместо использования позиционного синтаксиса?

Mk12
источник
6
Возможно, вы также захотите прочитать PEP 3102 - они приводят в порядок некоторые из этих вещей в Python 3. См .: python.org/dev/peps/pep-3102
Бен Хойт,
И то, есть ли значение по умолчанию, не имеет к этому никакого отношения (кроме того, нужно ли вам передавать значение для него), верно?
mk12
@Ben Hoyt Добавил ответ ниже, охватывающий Python 3, обязательные аргументы для ключевых слов
Кристоф Руссси

Ответы:

347

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

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

Другая концепция находится на стороне определения функции: вы можете определить функцию, которая принимает параметры по имени - и вам даже не нужно указывать, что это за имена. Это чисто ключевые аргументы , и они не могут быть переданы позиционно. Синтаксис

def my_function(arg1, arg2, **kwargs)

Любые ключевые слова , передаваемые в эту функцию, будут помещены в словарь с именем kwargs. Вы можете проверить ключи этого словаря во время выполнения, например так:

def my_function(**kwargs):
    print str(kwargs)

my_function(a=12, b="abc")

{'a': 12, 'b': 'abc'}
Ян Клелланд
источник
5
+1 и согласился: вы единственный, кто говорил об обоих типах аргументов позиционного + ключевого слова, все остальные либо думали, что я говорил о первом или втором (но это были хорошие посты). Спасибо!
mk12
34
Формулировка неясна: обычно вы говорите об аргументах на вызывающей стороне, а параметры на вызываемой стороне.
glglgl
3
Должно ли имя параметра быть kwargsили я могу переименовать его в sth. как options( def my_fuction(arg1, arg2, **options))?
Брюс Сан
1
Имя может быть любым, хотя kwargsэто соглашение, когда нет более подходящего имени
Мэтт Циммерман
Я думаю, что вторая концепция, объясненная здесь, технически называется Аргументами произвольного ключевого слова.
Аншул Дахия
189

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

def foo(*positional, **keywords):
    print "Positional:", positional
    print "Keywords:", keywords

*positionalАргумент будет хранить все позиционные аргументы , передаваемые foo(), без ограничения, сколько вы можете предоставить.

>>> foo('one', 'two', 'three')
Positional: ('one', 'two', 'three')
Keywords: {}

**keywordsАргумент будет хранить любые именованные аргументы:

>>> foo(a='one', b='two', c='three')
Positional: ()
Keywords: {'a': 'one', 'c': 'three', 'b': 'two'}

И, конечно же, вы можете использовать оба одновременно:

>>> foo('one','two',c='three',d='four')
Positional: ('one', 'two')
Keywords: {'c': 'three', 'd': 'four'}

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

слишком много PHP
источник
3
Отличный ответ! Просто обратите внимание, что требуемые позиционные аргументы могут быть переданы раньше, *positionalи **keywordsесли мы изменим определение функции, как def foo(arg1, *positional, **keywords):. Здесь arg1позиционный и обязательный. Обратите внимание, что позиционный в ответе означает необязательное и переменное количество позиционных аргументов.
shaffooo
2
Да, хороший ответ. Еще одно примечание: если вы вызываете свою функцию, foo(bar=True)вы можете получить значения, используя те bar = keywords.pop('bar')же, что и bar = keywords.pop('bar', None). Для значения по умолчанию используйтеbar = keywords.pop('bar', False)
olibre
111

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

def foo(bar, baz):
    pass

foo(1, 2)
foo(baz=2, bar=1)
Эли Грей
источник
3
Спасибо за это. Это невероятно полезно , что я могу и указать ключевое слово аргумент в позиционной ARG, и позиционной арг в качестве ключевого слова аргумент.
Люк Дэвис
47

Позиционные Аргументы

У них нет ключевых слов перед ними. Порядок важен!

func(1,2,3, "foo")

Ключевое слово Аргументы

У них есть ключевые слова в передней части. Они могут быть в любом порядке!

func(foo="bar", baz=5, hello=123)

func(baz=5, foo="bar", hello=123)

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

def func(foo=1, baz=2, hello=3): ...
func("bar", 5, 123)
неизвестный
источник
8
ИМХО, 3-й пример (аргументы по умолчанию) не понятен. Я думаю, что вы говорите о том, что происходит, когда один или несколько параметров объявляют значения по умолчанию, и вызов использует позиционную нотацию, но предоставляет МЕНЬШЕ, чем количество объявленных параметров. Однако в вашем примере объявлено 3 и 3 в вызове, поэтому значения по умолчанию не имеют никакого эффекта! Вы намеревались опустить 3-й аргумент? например func("bar", 5)? А потом скажите, что helloполучает значение по умолчанию 3.
ToolmakerSteve
25

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

  1. По позиции. Позиционные аргументы не имеют ключевых слов и назначаются первыми.

  2. По ключевому слову. Аргументы ключевых слов имеют ключевые слова и назначаются вторыми после позиционных аргументов.

Обратите внимание, что вы есть возможность использовать позиционные аргументы.

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

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

С. Лотт
источник
1
О, я думал о параметрах, когда это на самом деле аргументы (то, что я передаю). Спасибо!
mk12
24

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

>>> def func(a='a', b='b', c='c', **kwargs):
...    print 'a:%s, b:%s, c:%s' % (a, b, c)
... 
>>> func()
a:a, b:b, c:c
>>> func(**{'a' : 'z', 'b':'q', 'c':'v'})
a:z, b:q, c:v
>>> 
Шерман
источник
11
+1 за полезную технику. Ваша точка зрения была бы яснее без , **kwargs. Это продемонстрирует, что даже простой func def с фиксированным числом параметров может быть снабжен словарем. То есть в определении не требуется ничего особенного. Тогда вы можете добавить второй пример, с определением WITH ** kwargs, и показать, как через него доступны ДОПОЛНИТЕЛЬНЫЕ элементы в словаре.
ToolmakerSteve
1
Я видел, как это происходило в исходном коде различных библиотек, и был очень смущен. Спасибо за разъяснение!
Крейг Лабенс,
3
Четвертый формальный параметр выше - ** kwargs необходим, если вы когда-либо вызываете func со словарем, который содержит ключи, отличные от «a», «b» и «c».
Эдуардо
Для меня print 'a:%s, b:%s, c:%s' % (a, b, c)дает синтаксическую ошибку, однако print('a:%s, b:%s, c:%s' % (a, b, c))работает. Что-то с версией Python? В любом случае, спасибо за это понимание, до сих пор я использовал более неуклюжийprint('a:{}, b:{}, c:{}'.format(a, b, c))
Аксель Брегнсбо
17

Используя Python 3, вы можете иметь как обязательные, так и необязательные ключевые аргументы :


Необязательно : (значение по умолчанию определено для параметра 'b')

def func1(a, *, b=42):
    ...
func1(value_for_a) # b is optional and will default to 42

Обязательно (значение по умолчанию для параметра 'b' не определено):

def func2(a, *, b):
    ... 
func2(value_for_a, b=21) # b is set to 21 by the function call
func2(value_for_a) # ERROR: missing 1 required keyword-only argument: 'b'`

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

Кристоф Русси
источник
3
Требуется вариант является весьма полезным. Он призывает давать аргументы по имени без указания значений по умолчанию, что часто не имеет смысла.
TNT
Значения по умолчанию выглядят красиво и могут помочь вам сэкономить время при запуске, но в долгосрочной перспективе значения по умолчанию могут быть PITA.
Кристоф Русси
11

Я удивлен, что никто не упомянул тот факт, что вы можете смешивать позиционные и ключевые аргументы, чтобы делать такие хитрые вещи, используя *argsи **kwargs( с этого сайта ):

def test_var_kwargs(farg, **kwargs):
    print "formal arg:", farg
    for key in kwargs:
        print "another keyword arg: %s: %s" % (key, kwargs[key])

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

Габриэль Херли
источник
0

Я искал пример, который имел kwargs по умолчанию, используя аннотацию типа:

def test_var_kwarg(a: str, b: str='B', c: str='', **kwargs) -> str:
     return ' '.join([a, b, c, str(kwargs)])

пример:

>>> print(test_var_kwarg('A', c='okay'))
A B okay {}
>>> d = {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', c='c', b='b', **d))
a b c {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', 'b', 'c'))
a b c {}
jmunsch
источник
0

Просто добавьте / добавьте способ определения значения аргументов по умолчанию, которое не присваивается в ключевых словах при вызове функции:

def func(**keywargs):
if 'my_word' not in keywargs:
    word = 'default_msg'
else:
    word = keywargs['my_word']
return word

позвоните по этому:

print(func())
print(func(my_word='love'))

ты получишь:

default_msg
love

Узнайте больше о *argsи **kwargsв Python: https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3

sonictl
источник