Любая причина НЕ всегда использовать ключевые аргументы? - PullRequest
57 голосов
/ 12 августа 2011

Прежде чем перейти к питону, я начал с некоторых книг по Objective-C / Cocoa. Насколько я помню, большинству функций требовалось явно указывать аргументы ключевых слов. До недавнего времени я забыл все об этом и просто использовал позиционные аргументы в Python. Но в последнее время я столкнулся с несколькими ошибками, возникшими из-за неправильных позиций - хитрыми мелочами, которыми они были.

Заставил меня задуматься - вообще говоря, если только нет обстоятельства, которое конкретно требует аргументов без ключевых слов - есть ли веская причина НЕ использовать аргументы с ключевыми словами? Считается ли плохим стилем всегда использовать их, даже для простых функций?

Мне кажется, что большинство моих 50-строчных программ регулярно масштабировались до 500 или более строк, если я просто привыкну всегда использовать аргументы ключевых слов, код будет более легко читаемым и обслуживаемым по мере роста. По какой причине это может быть не так?

UPDATE:

Общее впечатление, которое я получаю, заключается в том, что это предпочтение стиля, со многими хорошими аргументами, которые обычно не должны использоваться для очень простых аргументов, но в остальном согласуются с хорошим стилем. Прежде чем принять, я просто хочу уточнить, есть ли какие-то специфические проблемы, не связанные со стилем, которые возникают из-за этого метода - например, существенное снижение производительности?

Ответы [ 11 ]

54 голосов
/ 12 августа 2011

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

Я следую следующему общему правилу:

  1. Если трудно определить функцию (имя) аргумента из имени функции - передайте его по ключевому слову (например, я бы не хотел, чтобы в моем коде было text.splitlines(True)).
  2. Если сложно определить порядок аргументов, например, если у вас слишком много аргументов или если у вас есть независимые необязательные аргументы - передайте его по ключевому слову (например, funkyplot(x, y, None, None, None, None, None, None, 'red') выглядит не очень хорошо).
  3. Никогда не передавайте первые несколько аргументов по ключевому слову, если цель аргумента очевидна. Видите ли, sin(2*pi) лучше, чем sin(value=2*pi), то же самое верно для plot(x, y, z).

В большинстве случаев стабильные обязательные аргументы будут позиционными, а необязательные аргументы - ключевыми.

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

ОБНОВЛЕНИЕ: Несестистические проблемы

Аргументы ключевого слова могут делать все, что могут позиционные аргументы, и если вы определяете новый API, нет никаких технических недостатков, кроме возможных проблем с производительностью. Однако у вас могут быть небольшие проблемы, если вы комбинируете свой код с существующими элементами.

Обратите внимание на следующее:

  • Если вы заставите свою функцию принимать аргументы с ключевыми словами, это станет частью вашего интерфейса. Вы не можете заменить свою функцию другой, имеющей аналогичную подпись, но с другим ключевым словом для того же аргумента.
  • Возможно, вы захотите использовать декоратор или другую утилиту в вашей функции, которая предполагает, что ваша функция принимает позиционный аргумент. Несвязанные методы являются примером такой утилиты, потому что они всегда передают первый аргумент как позиционный после чтения его как позиционный, поэтому cls.method(self=cls_instance) не работает, даже если в определении есть аргумент self.

Ничто из этого не будет реальной проблемой, если вы хорошо спроектируете свой API и задокументируете использование аргументов ключевых слов, особенно если вы не разрабатываете что-то, что должно быть взаимозаменяемым с тем, что уже существует.

17 голосов
/ 12 августа 2011

Если вы хотите улучшить читабельность вызовов функций, почему бы просто не объявить функции как обычно, например,

def test(x, y):
    print "x:", x
    print "y:", y

И просто вызовите функции, объявив имена явно, например:

test(y=4, x=1)

Что, очевидно, дает вам вывод:

x: 1
y: 4

или это упражнение будет бессмысленным.

Это позволяет избежать необязательного использования аргументов и необходимости использования значений по умолчанию (если только вы не хотите, чтобы они были, в этом случае просто используйте ключевое слово arguments! :) и обеспечивает универсальность и улучшенную читаемость именованных аргументов, которые не ограничены. по заказу.

11 голосов
/ 12 августа 2011

Ну, есть несколько причин, по которым я бы этого не делал.

Если все ваши аргументы являются аргументами ключевых слов, это увеличивает шум в коде и может убрать ясность относительно того, какие аргументы требуются, а какиеявляются опциональными.

Кроме того, если мне придется использовать ваш код, я, возможно, захочу вас убить !!(Шучу), но каждый раз вводить имя всех параметров ... не так весело.

6 голосов
/ 12 августа 2011

Я помню, как читал очень хорошее объяснение «параметров» в программах UNIX: «Параметры должны быть необязательными, программа должна иметь возможность работать без каких-либо параметров».

Тот же принцип может применяться к ключевому слову аргументам в Python. Аргументы такого рода должны позволять пользователю «настраивать» вызов функции, но функция должна быть в состоянии вызываться без каких-либо неявных пар аргументов ключевое слово-значение.

5 голосов
/ 12 августа 2011

Просто чтобы предложить другой аргумент, я думаю, что в некоторых случаях именованные параметры могут улучшить читаемость. Например, представьте себе функцию, которая создает пользователя в вашей системе:

create_user("George", "Martin", "g.m@example.com", "payments@example.com", "1", "Radius Circle")

Из этого определения не совсем ясно, что эти значения могут означать, даже если все они обязательны, однако для именованных параметров это всегда очевидно:

create_user(
    first_name="George",
    last_name="Martin",
    contact_email="g.m@example.com",
    billing_email="payments@example.com",
    street_number="1",
    street_name="Radius Circle")
4 голосов
/ 12 августа 2011

Иногда вещи должны быть простыми, потому что они просты.

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

4 голосов
/ 12 августа 2011

Когда встроенные в Python функции compile() и __import__() получают поддержку аргумента ключевого слова , тот же аргумент был сделан в пользу ясности. Похоже, что никакого существенного снижения производительности нет, если таковые имеются.

Теперь, если вы заставите свои функции только принимать аргументы ключевого слова (в отличие от передачи позиционных параметров с использованием ключевых слов при их вызове, что разрешено), тогда да, это будет раздражать.

3 голосов
/ 12 августа 2011

Я не вижу цели использования аргументов с ключевыми словами, когда смысл аргументов очевиден

2 голосов
/ 13 августа 2011

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

Во-первых, иногда гораздо проще запомнить порядок ключевых слов, чем имена аргументов ключевых слов, и указание имен аргументов может сделатьэто менее понятно.Возьмите randint из scipy.random со следующей строкой документации:

randint(low, high=None, size=None)    
Return random integers x such that low <= x < high.
If high is None, then 0 <= x < low.

Когда вы хотите сгенерировать случайное целое число из [0,10), его нагляднее будет написать randint(10), чем randint(low=10) на мой взгляд.Если вам нужно сгенерировать массив из 100 чисел в [0,10), вы, возможно, запомните порядок аргументов и напишите randint(0, 10, 100).Однако вы можете не помнить имена переменных (например, первый параметр low, lower, start, min, минимум), и как только вам придется искать имена параметров, вы также можете не использовать их (как вы только что искалиправильный порядок).

Также рассмотрим функции с переменными числами (с переменным числом параметров, которые сами являются анонимными).Например, вы можете написать что-то вроде:

def square_sum(*params):
    sq_sum = 0
    for p in params:
        sq_sum += p*p
    return sq_sum

, к которому может быть применено несколько параметров (square_sum(1,2,3,4,5) # gives 55).Конечно, вы могли бы написать функцию, чтобы взять итерируемое ключевое слово с именем итерация def square_sum(params): и назвать его как square_sum([1,2,3,4,5]), но это может быть менее интуитивно, особенно когда нет никакой путаницы в отношении имени аргумента или его содержимого.

2 голосов
/ 12 августа 2011

Единственным недостатком, который я могу видеть, является то, что вам придется думать о разумном значении по умолчанию для всего, и во многих случаях может не быть никакого разумного значения по умолчанию (включая None). Тогда вы почувствуете себя обязанным написать целый код обработки ошибок для случаев, когда kwarg, который по логике должен быть позиционным аргументом, не был указан.

Представь, что ты каждый раз пишешь такие вещи ...

def logarithm(x=None):
    if x is None:
        raise TypeError("You can't do log(None), sorry!")
...