Когда я должен использовать varargs при разработке Python API? - PullRequest
5 голосов
/ 16 июля 2009

Есть ли хорошее практическое правило относительно того, когда вам следует отдавать предпочтение сигнатурам функции varargs в вашем API, а не передавать итерируемую функцию? ("varargs" является сокращением от "variadic" или "variable-number-of-arguments"; то есть *args)

Например, 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

Ответы [ 4 ]

8 голосов
/ 16 июля 2009

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

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

4 голосов
/ 16 июля 2009

Мое эмпирическое правило - использовать его, когда вы часто можете переключаться между передачей одного или нескольких параметров. Вместо двух функций (например, кода 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 голосов
/ 16 июля 2009

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

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 работает с набором строк. Поэтому в первом случае вы запрашиваете список; во втором вы запрашиваете непосредственно строки.

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

0 голосов
/ 16 июля 2009

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

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

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

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

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

...