Есть ли способ определить, какие аргументы были переданы ключевым словом изнутри функции?
При попытке оценить значения параметров ключевых слов по умолчанию, да, есть варианты:
Код
Вариант 1 - locals()
def f(a, b=1, c="1"):
print(locals())
f(0)
# {'c': '1', 'b': 1, 'a': 0}
Вариант 2 - Частичные подсказки типа *
def g(a, b:int=1, c:float="1"):
pass
keys = g.__annotations__
values = g.__defaults__
dict(zip(keys, values))
# {'b': 1, 'c': '1'}
Вариант 3 - Полные подсказки типа *
def h(a:float, b:int=1, c:str="1") -> int:
return 0
keys = reversed(list(filter(lambda x: x != "return", h.__annotations__)))
values = reversed(h.__defaults__)
{k: v for k, v in zip(keys, values) if k != "return"}
# {'c': '1', 'b': 1}
Примечание: ни один из этих вариантов не является особенно Pythonic, но они демонстрируют потенциал.
Детали
locals()
зависит от вызова функции. Результаты должны иметь значения по умолчанию, но они изменяются со значениями, переданными в вызов, например, f(0)
против f(0 2, 3)
- Подсказки типа "Частично" означают, что аннотируются только ключевые параметры. Добавление любых других аннотаций не будет работать с этим наивным подходом.
- «Полный» или полный тип подсказок может включать в себя другие параметры. Мы повторяем в обратном порядке, чтобы избежать архивирования значений с необязательными позиционными параметрами. Поскольку аннотация
"return"
является необязательной, мы фильтруем ее во время итерации.
* Эти параметры зависят от подсказок типа и сохранения порядка вставки ключей (Python 3.6+). Они дают только значения по умолчанию и не изменяются со значениями вызова функции. Подсказки к типам являются необязательными прямо сейчас в Python, поэтому их следует использовать с осторожностью в производственном коде.
Предложение
Я бы использовал только последние подходы для отладки или быстрой проверки подписи функции. На самом деле, учитывая аргументы только для ключевых слов, можно использовать inspect.getargspec()
для захвата kwonlydefaults
dict.
def f(a, *, b=1, c="1"):
pass
spec = inspect.getfullargspec(f)
spec
# FullArgSpec(args=['a'], varargs=None, varkw=None, defaults=None,
# kwonlyargs=['b', 'c'], kwonlydefaults={'b': 1, 'c': '1'},
# annotations={})
spec.kwonlydefaults
# {'b': 1, 'c': '1'}
В противном случае объедините некоторые приемы с атрибутами args
и defaults
FullArgSpec
:
def get_keywords(func):
"""Return a dict of (reversed) keyword arguments from a function."""
spec = inspect.getfullargspec(func)
keys = reversed(spec.args)
values = reversed(spec.defaults)
return {k: v for k, v in zip(keys, values)}
get_keywords(f)
# {'c': '1', 'b': 1}