Проблема:
Я хочу написать функцию общего назначения:
def foo(positional, a=None, b=None, c=None, *, keyword_only=True):
# ... ?? ... magic_code
return a_b_c_in_tuple_in_order
, которая возвращает кортеж с сохранением порядка аргументов ключевого слова a,b,c
:
xx = 'some object'
>>> foo(xx, 1, 2, 3)
(1, 2, 3)
>>> foo(xx, 1, 2)
(1, 2)
>>> foo(xx, a=1, b=2, c=3, keyword_only=False)
(1, 2, 3)
>>> foo(xx, b=2, a=1, c=3) # <---- key behaviour
(2, 1, 3)
>>> foo(xx, b=2, c=3)
(2, 3)
>>> foo(xx, c=3, a=1)
(3, 1)
>>> foo(xx, a='may be anything', c=range(5), b=[1, 2])
('may be anything', range(0, 5), [1, 2])
>>> foo(xx, b=1)
(1,) # may be 1 or (1,)
Как я могу этого добиться? Является ли такой код unpythoni c, и если да, то что мне следует использовать вместо него?
Основные цели - простота использования и удобочитаемость.
Почему?
Моя цель - использовать такую функцию для преобразования между системами единиц измерения (например, СИ <--> имперские, но реальный вариант использования более сложен), где пользователь сможет интуитивно написать, например,
l, (t1, t2) = convert(params, lengths=L, times=(T1, T2), normalized=True)
# or
(t1, t2), l = convert(params, times=(T1, T2), lengths=L, normalized=True)
независимо от того, как функция определена, и если количества являются числами с плавающей запятой, массивами и т. д. c.
Угловые случаи:
Хорошо реагировать на такое неправильное использование не требуется, но защита от ошибок - это бонус:
>>> foo(b=2, a=1, c=3, positional=xx)
(2, 1, 3)
>>> foo(b=2, positional=xx, a=1, keyword_only=False, c=3)
(2, 1, 3)