Принудительное именование параметров в Python

В Python у вас может быть определение функции:

def info(object, spacing=10, collapse=1) 

который можно было бы вызвать любым из следующих способов:

  • Должен ли я добавить конечную запятую после последнего аргумента в вызове функции?
  • В Python, что определяет порядок при итерации через kwargs?
  • Оцениваются ли функции при передаче в качестве параметров?
  • Передача аргументов C # vs Python
  • Python: как передать аргументы функции __code__ функции?
  • Что означает только звезда * в объявлении функции?
  •  info(odbchelper) info(odbchelper, 12) info(odbchelper, collapse=0) info(spacing=15, object=odbchelper) 

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

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

    так что в приведенных выше четырех примерах только последний проведет проверку, как и все параметры.

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

  • Python оптимизирует вызовы функций из циклов?
  • Применение наложений к изображению с различной прозрачностью
  • UnicodeEncodeError только при работе в качестве задания cron
  • Странное поведение с поплавками и преобразованием строк
  • Как сделать этот блок кода python коротким и эффективным
  • Доступ к атрибутам на литералах работает на всех типах, но не `int`; Зачем?
  • 10 Solutions collect form web for “Принудительное именование параметров в Python”

    В Python 3 – Да, вы можете указать * в списке аргументов.

    Параметры после «*» или «* идентификатор» являются параметрами только для ключевого слова и могут передаваться только аргументы ключевого слова.

    Пример кода ( из python ref ):

     >>> def foo(pos, *, forcenamed): ... print(pos, forcenamed) ... >>> foo(pos=10, forcenamed=20) 10 20 >>> foo(10, forcenamed=20) 10 20 >>> foo(10, 20) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: foo() takes exactly 1 positional argument (2 given) 

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

     def foo(*, arg0="default0", arg1="default1", arg2="default2"): pass 

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

     def foo(**kwargs): pass 

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

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

     __named_only_start = object() def info(param1,param2,param3,_p=__named_only_start,spacing=10,collapse=1): if _p is not __named_only_start: raise TypeError("info() takes at most 3 positional arguments") return str(param1+param2+param3) +"-"+ str(spacing) +"-"+ str(collapse) 

    Единственный способ, с помощью которого вызывающий абонент мог бы обеспечить spacing аргументов и collapse позициям (без исключения):

     info(arg1, arg2, arg3, module.__named_only_start, 11, 2) 

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

    В противном случае вызовы должны иметь форму:

     info(arg1, arg2, arg3, spacing=11, collapse=2) 

    Вызов

     info(arg1, arg2, arg3, 11, 2) 

    будет присвоить значение 11 параметру _p и исключение, поднятое первой инструкцией функции.

    Характеристики:

    • Параметры до _p=__named_only_start допускаются позиционно (или по имени).
    • Параметры после _p=__named_only_start должны предоставляться только по имени (если не получено __named_only_start и использование специального дозорного объекта __named_only_start ).

    Плюсы:

    • Параметры явны по количеству и значению (позже, если, конечно, выбраны и хорошие имена).
    • Если дозорный элемент указан как первый параметр, то все аргументы должны быть указаны по имени.
    • При вызове функции можно переключиться в позиционный режим с помощью объекта- __named_only_start в соответствующей позиции.
    • Можно ожидать более высокую производительность, чем другие альтернативы.

    Минусы:

    • Проверка происходит во время выполнения, а не времени компиляции.
    • Использование дополнительного параметра (хотя и не аргумента) и дополнительной проверки. Небольшое ухудшение производительности в отношении регулярных функций.
    • Функциональность – это взлом без прямой поддержки языка (см. Примечание ниже).
    • При вызове функции можно переключиться в позиционный режим с помощью объекта- __named_only_start в правой позиции. Да, это также можно рассматривать как профессионала.

    Пожалуйста, имейте в виду, что этот ответ применим только для Python 2. Python 3 реализует аналогичный, но очень элегантный, поддерживаемый языком механизм, описанный в других ответах.

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

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

     def foo(**args): print args foo(1,2) # Raises TypeError: foo() takes exactly 0 arguments (2 given) foo(hello = 1, goodbye = 2) # Works fine. 

    Обновить:

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

     def info(foo, **kwargs): 

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

    Это действительно сводится к тому, что говорит Брайан.


    (…) люди могут добавлять параметры между spacing и collapse (…)

    В общем, при смене функций новые аргументы всегда должны заканчиваться. В противном случае он прерывает код. Должно быть очевидно.
    Если кто-то изменяет функцию так, чтобы код ломался, это изменение должно быть отклонено.
    (Как говорит Брайан, это похоже на контракт)

    (…) иногда не всегда ясно, что нужно делать.

    Посмотрев на подпись функции (т. def info(object, spacing=10, collapse=1) ), вы должны сразу увидеть, что каждый аргумент, который не имеет значения по умолчанию, является обязательным.
    Для чего нужен аргумент, следует зайти в документную строку.


    Старый ответ (для полноты) :

    Это, вероятно, не очень хорошее решение:

    Вы можете определить функции таким образом:

     def info(**kwargs): ''' Some docstring here describing possible and mandatory arguments. ''' spacing = kwargs.get('spacing', 15) obj = kwargs.get('object', None) if not obj: raise ValueError('object is needed') 

    kwargs – словарь, содержащий любой аргумент ключевого слова. Вы можете проверить, присутствует ли обязательный аргумент, а если нет, поднимите исключение.

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

    Вы можете сделать это так , как в Python 2, так и в Python 3 , создав «фиктивный» аргумент первого ключевого слова со значением по умолчанию, которое не будет «естественно». Этому аргументу ключевого слова может предшествовать один или несколько аргументов без значения:

     _dummy = object() def info(object, _kw=_dummy, spacing=10, collapse=1): if _kw is not _dummy: raise TypeError("info() takes 1 positional argument but at least 2 were given") 

    Это позволит:

     info(odbchelper) info(odbchelper, collapse=0) info(spacing=15, object=odbchelper) 

    но нет:

     info(odbchelper, 12) 

    Если вы измените функцию на:

     def info(_kw=_dummy, spacing=10, collapse=1): 

    то все аргументы должны содержать ключевые слова, а info(odbchelper) больше не будет работать.

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

    Поэтому нет необходимости возвращаться к использованию def(**kwargs) и потерять информацию подписи в вашем интеллектуальном редакторе. Ваш социальный контракт заключается в предоставлении определенной информации, заставляя (некоторые из них) требовать ключевые слова, порядок, в котором они представлены, стал неактуальным.

    Вы можете использовать оператор ** :

     def info(**kwargs): 

    таким образом, люди вынуждены использовать именованные параметры.

     def cheeseshop(kind, *arguments, **keywords): 

    в python, если use * args означает, что вы можете передать n-число аргументов для этого параметра – в который будет входить список внутри функции для доступа

    и если использовать ** kw, что означает его аргументы ключевого слова, которые могут быть доступны как dict – вы можете передать n-число kw args, и если вы хотите ограничить этот пользователь, необходимо ввести последовательность и аргументы, чтобы затем не использовать * и ** – (его питоновский способ предоставления общих решений для больших архитектур …)

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

     def info(object, spacing, collapse) spacing = spacing or 10 collapse = collapse or 1 

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

    Если вы все еще хотите это сделать, используйте декоратор функции и функцию inspect.getargspec . Он будет использоваться примерно так:

     @require_named_args def info(object, spacing=10, collapse=1): .... 

    Реализация require_named_args оставлена ​​в качестве упражнения для читателя.

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

    Я не понимаю, почему программист добавит параметр между двумя другими в первую очередь.

    Если вы хотите, чтобы параметры функции использовались с именами (например, info(spacing=15, object=odbchelper) ), то не имеет значения, в каком порядке они определены, поэтому вы можете также добавить новые параметры в конце.

    Если вы хотите, чтобы заказ имел значение, тогда вы не можете ожидать, что что-то будет работать, если вы его измените!

    Python - лучший язык программирования в мире.