Подтвердить что ты не робот

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

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

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

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

UPDATE:

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

Рассмотрим следующее:

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

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

Ответ 2

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

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

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

test(y=4, x=1)

Что явно дает вам результат:

x: 1
y: 4

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

create_user("George", "Martin", "[email protected]", "[email protected]", "1", "Radius Circle")

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

create_user(
    first_name="George",
    last_name="Martin",
    contact_email="[email protected]",
    billing_email="[email protected]",
    street_number="1",
    street_name="Radius Circle")

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

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

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

Ответ 10

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

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

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

Когда вы хотите генерировать случайный int из [0,10), его яснее писать randint(10), чем randint(low=10) на мой взгляд. Если вам нужно создать массив со 100 номерами в [0,10), вы, вероятно, можете запомнить порядок аргументов и написать randint(0, 10, 100). Однако вы можете не помнить имена переменных (например, это первый параметр: низкий, нижний, начальный, минимальный, минимальный), и как только вы должны искать имена параметров, вы также можете не использовать их (поскольку вы просто искали надлежащий порядок).

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

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]), но это может быть менее интуитивно понятным, особенно когда нет никакой путаницы в имени аргумента или его содержимом.