2009-07-16 2 views
4

Есть ли хорошее эмпирическое правило относительно того, когда вы должны предпочитать подписи функций varargs в вашем API, передавая итерабельность функции? ("Переменная длина" быть коротким для "VARIADIC" или "переменное число-аргументов", то есть *args)Когда я должен использовать varargs при разработке Python API?

Например, os.path.join имеет vararg подпись:

os.path.join(first_component, *rest) -> str 

В то время как min позволяет либо:

min(iterable[, key=func]) -> val 
min(a, b, c, ...[, key=func]) -> val 

в то время как any/all только позволяют итератора:

any(iterable) -> bool 

ответ

8

Рассмотрите возможность использования varargs, когда вы ожидаете, что ваши пользователи укажут список аргументов, поскольку код на call-площадке или наличие одного значения является общим случаем. Когда вы ожидаете, что ваши пользователи получат аргументы из другого места, не используйте varargs. Если вы сомневаетесь, ошибайтесь в стороне от использования varargs.

Используя ваши примеры, наиболее распространенные USECASE для os.path.join будет иметь префикс пути, и добавить имя файла/относительный путь на него, так что вызов обычно выглядит как os.path.join (префикс , some_file). С другой стороны, any() обычно используется для обработки списка данных, когда вы знаете все элементы, которые вы не используете, любой ([a, b, c]), вы используете a или b или c.

+0

Предсказание того, будет ли вызывающий объект иметь значения в локальном контексте (в общем случае), сложнее, чем кажется! (Я также подумал, что вы должны ошибаться на стороне итерации.) – cdleary

3

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

def enable_tab(tab_name) 
def enable_tabs(tabs_list) 

или даже хуже, имея только одну функцию

def enable_tabs(tabs_list) 

и использовать его в качестве enable_tabls(['tab1']), я предпочитаю использовать только: def enable_tabs(*tabs). Хотя, видя что-то вроде enable_tabs('tab1'), выглядит несколько неправильно (из-за множественного числа), я предпочитаю его по альтернативам.

0

Вы должны использовать его, когда список параметров является переменным.

Да, я знаю, что ответ довольно глупый, но это правда. Возможно, ваш вопрос был немного размытым. :-)

Аргументы по умолчанию, такие как min() выше, более полезны, когда вы либо хотите разное поведение (например, min()), либо когда вы просто не хотите заставить вызывающего абонента отправлять все параметры.

* arg - это когда у вас есть переменный список аргументов одного типа. Соединение является типичным примером. Вы можете заменить его аргументом, который также принимает список.

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

0

Это совершенно разные интерфейсы.
В одном случае у вас есть один параметр, в другом - много.

any(1, 2, 3) 
TypeError: any() takes exactly one argument (3 given) 

os.path.join("1", "2", "3") 
'1\\2\\3' 

Это действительно зависит от того, что вы хотите, чтобы подчеркнуть: any работы над списком (ну, вроде), в то время как os.path.join работает над набором строк.
Поэтому в первом случае вы запрашиваете список; во втором вы запрашиваете непосредственно строки.

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

Смежные вопросы