Любая причина не всегда использовать аргументы ключевых слов?


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

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

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

обновление:

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

11 52

11 ответов:

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

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

  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 и задокументируете использование ключевые слова аргументы, особенно если вы не разрабатываете что-то, что должно быть взаимозаменяемым с чем-то, что уже существует.

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

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

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

test(y=4, x=1)

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

x: 1
y: 4

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

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

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

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

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

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

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

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

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")

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

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

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

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

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

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

во-первых, иногда гораздо легче запомнить порядок ключевых слов, чем имена ключевых аргументов, и указание имен аргументов может сделать его менее ясным. Возьмите 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, minimum), и как только вам нужно будет искать имена параметров, вы можете также не использовать их (как вы только что посмотрели должный порядок.)

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

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). Конечно, вы могли бы написать функцию, чтобы взять именованное ключевое слово iterable def square_sum(params): и назвал его как square_sum([1,2,3,4,5]) но это может быть менее интуитивным, особенно когда нет потенциальной путаницы в имени аргумента или его содержание.

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

представьте себе, писать такое каждый раз..

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

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

testing(arg = 20, 56)

дает SyntaxError сообщение; что-то вроде:

SyntaxError: non-keyword arg after keyword arg

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