Я создал функцию (send_to_api), которая принимает три аргумента. user_id и event_type принимают строки, а event_properties - словарь, который я передаю в качестве позиционного аргумента. Это формат, который требуется для внешнего API. Вот упрощенная версия функции:
def send_to_api(user_id, event_type, *args):
event_args = {"user_id": user_id,
"event_type": event_type,
"event_properties": args}
data = json.dumps(event_args)
r = requests.post(url=url, data=data)
В другом месте функция вызывается так:
event_properties = {"property_1": "a", "property_whatever": "b"}
send_to_api("my_user_id", "my_event", event_properties)
После ознакомления с * args и ** kwargs я все еще, кажется, делаю что-то не так, потому что dict event_properties не проходит.
Думаю, причина в том, что я пытаюсь передать словарь в качестве позиционного аргумента? Или любой другой указатель на то, где здесь что-то не так?






с одним * это будет кортеж, но с двумя ** будет словарь
def send_to_api(user_id, event_type, **args):
...
...
send_to_api("my_user_id", "my_event", **event_properties)
какой-нибудь полезный документы
Выход
{
"user_id": "my_user_id",
"event_type": "my_event",
"event_properties": {
"property_1": "a",
"property_whatever": "b"
}
}
Вы должны использовать распаковку dict следующим образом:
send_to_api("my_user_id", "my_event", **event_properties)
Подробнее об этом здесь.
Для лучшего понимания вы можете просто отладить свою функцию send_to_api. Но вкратце:
* args используется для отправки в функцию списка аргументов переменной длины без ключевых слов.
def send_to_api(param1, param2, *args):
print(param1, param2, args)
Если вы вызываете свою функцию и передаете после param1, param2 любое количество позиционных аргументов, вы можете получить к ним доступ внутри функции в кортеже аргументы. Итак, в вашем примере вопроса ваш dict находится внутри переменной аргументы.
send_to_api(1,2, {"a":1, "b":2})
...
1 2 ({'a': 1, 'b': 2},)
И вы можете получить к нему доступ как аргументы [0], поэтому ваш код может выглядеть так:
def send_to_api(user_id, event_type, *args):
event_args = {"user_id": user_id,
"event_type": event_type,
"event_properties": args[0]}
Но, вероятно, будет лучше, если вы сможете изменить подпись на что-то вроде этого:
def send_to_api(user_id, event_type, event_properties, *args):
event_args = {"user_id": user_id,
"event_type": event_type,
"event_properties": event_properties}
Как по мне он намного чище;)
Если вам нужно обрабатывать любое количество позиционных аргументов - используйте * args в определении функции, тогда вы можете получить к ним доступ в кортеже аргументы внутри функции.
Если вам нужно обрабатывать любое количество аргументов с ключевыми словами - используйте ** kwargs в определении функции, тогда внутри функции вы можете получить к ним доступ в словаре kwargs.
так например:
def send_to_api(arg1, *args, **kwargs):
print(arg1, args, kwargs)
затем вы можете вызвать функцию с помощью:
send_to_api(1, 2 , key1=1, key2=2)
он напечатает:
1 (2,) {'key1': 1, 'key2': 2}
так что вы можете видеть, что аргументы - это кортеж (2,); kwargs - это словарь {'key1': 1, 'key2': 2}
Также вы можете передать kwargs в функцию как словарь с оператором распаковки:
send_to_api(1, 2, **{'key1': 1, 'key2': 2})
он напечатает то же самое:
1 (2,) {'a': 1, 'b': 2}
Итак, словарь {'key1': 1, 'key2': 2} был распакован с помощью оператора ** в аргументы ключевого слова key1 = 1, key2 = 2 и доступен внутри вашей функции в kwargs dict.
Никакого волшебства, просто попробуйте поиграть в интерактивной консоли Python.
* args и ** kwargs предназначены для передачи функции переменного количества аргументов. Перед их использованием вам необходимо знать, нужен ли вам аргумент keyworded или аргументы non-keyworded.
В вашем случае вы используете аргумент на основе ключевых слов, поэтому вам нужно изменить его на **kwargs
def test_arg_kwargs(arg1, arg2, **kwargs):
print("arg1:", arg1)
print("arg2:", arg2)
print("arg3:", kwargs)
event_properties = {"property_1": "a", "property_whatever": "b"}
test_arg_kwargs('arg1', 'arg2', **event_properties)
выход:
arg1: arg1
arg2: arg2
arg3: {'property_1': 'a', 'property_whatever': 'b'}
Изменить
*argsнаargs?