Python: Именованные аргументы
В этом уроке разберем, какие параметры существуют, чем они отличаются и в каких случаях их применять.
Аргументы — это данные, которые передаются в вызов функции. Они бывают двух типов:
Первый тип — позиционные аргументы. Они передаются в том же порядке, в котором определены параметры функции:
# (text, length) truncate('My Text', 3)
Второй тип — именованные аргументы. Они передаются не просто как значения, а как пара «имя=значение». Поэтому их можно передавать в любом порядке:
# Аргументы переданы в другом порядке truncate(length=3, text='My Text')
Если внимательно посмотреть на два примера выше, то можно понять, что это две одинаковые функции.
Теперь разберемся, в каких случаях нужно применять эти типы аргументов.
Выбор типа параметра зависит от того, кто вызывает функцию.
Есть две причины использовать именованные аргументы:
- Они повышают читаемость, так как сразу видно имена
- Можно не указывать все промежуточные параметры, которые нам сейчас не нужны
Последнее полезно, если у функции много необязательных параметров. Посмотрим на примере:
def print_params(a=1, b=2, c=None, d=4): print(a, b, c, d) # Нужно передать только d, но приходится передавать все f(1, 2, 3, 8) # Именованные аргументы позволяют передавать только d # Для остальных аргументов используются значения по умолчанию f(d=8)
Именованные аргументы можно передавать одновременно с позиционными. Тогда позиционные должны идти в самом начале:
# Передаем только a (позиционно) и d (как именованный) f(3, d=3)
Задание
Реализуйте функцию trim_and_repeat() , которая принимает три параметра: строку, offset — число символов, на которое нужно обрезать строку слева и repetitions — количество обрезанных строк, которые нужно вывести. Функция обрезает строку и повторяет ее столько раз, чтобы общее количество обрезанных строк равнялось repetitions . Функция должна записать результат в одну строку и вернуть его.
Число символов для среза по умолчанию равно 0, а повторений — 1.
text = 'python' print(trim_and_repeat(text, offset=3, repetitions=2)) # => honhon print(trim_and_repeat(text, repetitions=3)) # => pythonpythonpython print(trim_and_repeat(text)) # => python
Упражнение не проходит проверку — что делать?
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя
Это нормально , в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Именованные параметры в JavaScript
Я не думаю, что это возможно, но вы можете попытаться поместить некоторые неопределенные в пустые места. Что очень плохо. Используйте объект, это хорошо.
Vladislav Qulin 03 авг. 2012, в 12:54
Нет, JavaScript / EcmaScript не поддерживают именованные параметры. Сожалею.
smilledge 03 авг. 2012, в 12:54
Я уже знаю, что. Благодарю. Я искал способ, который включает в себя настройку, что может сделать существующая Function в javascript.
Robin Maben 03 авг. 2012, в 12:57
Существующая Function в Javascript не может изменить основной синтаксис Javascript.
Gareth 03 авг. 2012, в 13:04
@Gareth: Гарет: Да, но я могу изменить способ разрешения своих аргументов, верно? Или, может быть, поставить .apply для использования? Я не имею в виду строго C# способ. Во всяком случае, этот JavaScript может. (кроме проходящих объектов)
Robin Maben 03 авг. 2012, в 13:17
Coffeescript поддерживает именованные параметры
mquandalle 24 июль 2013, в 20:57
@mquandalle: есть ссылки? Если достоверно, пожалуйста, напишите в качестве ответа.
Robin Maben 25 июль 2013, в 05:54
@RobinMaben Я нашел этот блог . Он показывает, как у кофе есть синтаксис для реализации объекта, но вы не можете использовать значения по умолчанию с ним.
jpmc26 24 авг. 2013, в 06:28
Я думаю, что эта ссылка может быть полезной: javascriptkit.com/javatutors/namedfunction.shtml
A.Dara 29 нояб. 2015, в 10:37
Я не думаю, что Javascript поддерживает эту функцию. Я думаю, что ближе всего вы можете прийти к именованным параметрам: (1) добавить комментарий calculateBMI(70, /*height:*/ 175); , (2) предоставить объект calculateBMI(70,
tfmontague 23 дек. 2017, в 10:02
Показать ещё 8 комментариев
Поделиться:
optional-parameters
named-parameters
8 ответов
Лучший ответ
ES2015
В ES2015 деструктурирование параметров может использоваться для имитации именованных параметров. Это потребует, чтобы вызывающий передал объект, но вы можете избежать всех проверок внутри функции, если вы также используете параметры по умолчанию:
myFunction(< param1 : 70, param2 : 175>); function myFunction(=<>) < // . >
ES5
Есть способ приблизиться к тому, что вы хотите, но он основан на выходе Function.prototype.toString [ES5] , который в определенной степени зависит от реализации, поэтому он не может быть совместим с несколькими браузерами.
Идея состоит в том, чтобы проанализировать имена параметров из строкового представления функции, чтобы вы могли ассоциировать свойства объекта с соответствующим параметром.
Тогда вызов функции может выглядеть как
func(a, b, );
где a и b являются позиционными аргументами, а последний аргумент — объектом с именованными аргументами.
var parameterfy = (function() < var pattern = /function[^(]*\(([^)]*)\)/; return function(func) < // fails horribly for parameterless functions ;) var args = func.toString().match(pattern)[1].split(/,\s*/); return function() < var named_params = arguments[arguments.length - 1]; if (typeof named_params === 'object') < var params = [].slice.call(arguments, 0, -1); if (params.length < args.length) < for (var i = params.length, l = args.length; i < l; i++) < params.push(named_params[args[i]]); >return func.apply(this, params); > > return func.apply(null, arguments); >; >; >());
Что вы бы использовали как:
var foo = parameterfy(function(a, b, c) < console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c); >); foo(1, 2, 3); // a is 1 | b is 2 | c is 3 foo(1, ); // a is 1 | b is 2 | c is 3 foo(1, ); // a is 1 | b is undefined | c is 3 foo(); // a is 1 | b is undefined | c is 3
Для этого подхода существуют некоторые недостатки (вы были предупреждены!):
- Если последний аргумент является объектом, он рассматривается как «именованные объекты аргументов»
- Вы всегда получите столько аргументов, сколько вы определили в функции, но некоторые из них могут иметь значение undefined (отличное от того, чтобы не иметь никакого значения). Это означает, что вы не можете использовать arguments.length для проверки того, сколько аргументов было передано.
Вместо функции, создающей оболочку, вы также можете иметь функцию, которая принимает функцию и различные значения в качестве аргументов, например
call(func, a, b, );
или даже расширить Function.prototype , чтобы вы могли:
foo.execute(a, b, );
Felix Kling 03 авг. 2012, в 14:32
Поделиться
Клятва! Function.prototype .. Я надеялся, что кто-нибудь пойдет в этом направлении ..
Robin Maben 03 авг. 2012, в 14:58
Да . вот пример для этого: jsfiddle.net/9U328/1 (хотя вы должны лучше использовать Object.defineProperty и установить enumerable в false ). Нужно всегда быть осторожным при расширении нативных объектов. Весь подход выглядит немного хакерским, поэтому я не ожидал бы, что он будет работать сейчас и навсегда;)
Felix Kling 03 авг. 2012, в 15:03
Отметил. Я приступлю к использованию этого. Отмечается как ответ! . Теперь 😉
Robin Maben 03 авг. 2012, в 15:43
+1 за термин параметризация
CSJ 05 дек. 2013, в 21:08
Очень незначительная мелочь: я не думаю, что этот подход поймает функции стрелок EcmaScript 6. В настоящее время это не большая проблема, но, возможно, стоит упомянуть в разделе «Предостережения» вашего ответа.
NobodyMan 09 июнь 2015, в 23:33
@NobodyMan: правда. Я написал этот ответ до того, как стали работать функции со стрелками. В ES6 я бы на самом деле прибегнул к деструктуризации параметров.
Felix Kling 09 июнь 2015, в 23:38
Вот синтаксис с параметрами по умолчанию: function myFunction(
Darek Nędza 21 март 2017, в 00:19
Это было бы лучше с демонстрацией разрушения параметров. Я бы добавил это, но у меня проблемы с пониманием!
mikemaccana 12 окт. 2018, в 11:28
Показать ещё 6 комментариев
Нет — объектный подход — это ответ на JavaScript. Нет проблем с этим, если ваша функция ожидает объект, а не отдельные параметры.
Utkanos 03 авг. 2012, в 13:10
Поделиться
Объясняя голосование вниз : @Utkanos это больше комментарий, чем ответ.
Robin Maben 03 авг. 2012, в 15:41
@RobertMaben — Ответ на конкретный заданный вопрос заключается в том, что нет собственного способа собрать объявленные переменные или функции, не зная, что они живут в определенном пространстве имен. Тот факт, что ответ короткий, не отменяет его пригодности в качестве ответа — вы не согласны? Есть гораздо более короткие ответы, такие как «нет, не возможно». Короткие они могут быть, но они также являются ответом на вопрос.
Utkanos 03 авг. 2012, в 16:31
В настоящее время есть es6, хотя: 2ality.com/2011/11/keyword-parameters.html
slacktracer 12 янв. 2016, в 18:32
Это, безусловно, справедливый ответ — «именованные параметры» — это особенность языка. Объектный подход — следующая лучшая вещь в отсутствии такой особенности.
fatuhoku 19 янв. 2016, в 18:07
Показать ещё 2 комментария
Эта проблема была моей любимой мозолью в течение некоторого времени. Я опытный программист со многими языками под моим поясом. Один из моих любимых языков, которым я имел удовольствие использовать Python. Python поддерживает именованные параметры без каких-либо обманщиков. Поскольку я начал использовать Python (некоторое время назад), все стало проще. Я считаю, что каждый язык должен поддерживать именованные параметры, но это не так.
Многие говорят, что просто используют трюк «Пропустить объект», чтобы вы назвали параметры.
/** * My Function * * @param arg1 Named arguments */ function myFunc(arg1) < >myFunc(< param1 : 70, param2 : 175>);
И это отлично работает, за исключением того, что. когда дело доходит до большинства IDE, многие из нас разработчики полагаются на подсказки типа/аргумента в нашей среде IDE. Я лично использую PHP Storm (наряду с другими IDE JetBrains, такими как PyCharm для python и AppCode для Objective C)
И самая большая проблема с использованием трюка «Передача объекта» заключается в том, что когда вы вызываете функцию, среда IDE дает подсказку одного типа и что она. Как мы должны знать, какие параметры и типы должны перейдите в объект arg1?
Итак. трюк «Пропустить объект» не работает для меня. Это на самом деле вызывает больше головных болей, когда приходится смотреть на каждую функцию docblock, прежде чем я узнаю, какие параметры функция ожидает. Конечно, это здорово, когда вы поддерживаете существующий код, но это ужасно для написания нового кода.
Ну, это техника, которую я использую. Теперь могут быть некоторые проблемы с ней, и некоторые разработчики могут сказать мне, что я делаю это неправильно, и у меня есть открытый ум, когда дело доходит до этих вещей. Я всегда готов взглянуть на лучшие способы решения задачи. Итак, если есть проблема с этой техникой, то комментарии приветствуются.
/** * My Function * * @param arg1 Argument 1 * @param arg2 Argument 2 */ function myFunc(arg1, arg2) < >var arg1, arg2; myFunc(arg1='Param1', arg2='Param2');
Таким образом, у меня есть лучшее из обоих миров. новый код легко писать, так как моя IDE дает мне все правильные подсказки аргументов. И, сохраняя код позже, я могу сразу увидеть, не только значение, переданное функции, но и имя аргумента. Единственный недостаток, который я вижу, — объявлять ваши имена аргументов как локальные переменные, чтобы не загрязнять глобальное пространство имен. Конечно, это немного лишний набор текста, но тривиальный по сравнению с временем, необходимым для поиска докблоков при написании нового кода или сохранении существующего кода.
В чем разница между именованными и позиционными параметрами в Dart?
Dart поддерживает как именованные необязательные параметры, так и позиционные необязательные параметры. Каковы различия между ними?
Также, как вы можете определить, действительно ли был задан необязательный параметр?
спросил(а) 2022-01-08T16:35:07+03:00 1 год, 10 месяцев назад
добавить комментарий
пожаловаться
Дарт имеет два типа необязательных параметров: именованные и позиционные. Прежде чем обсуждать различия, позвольте мне сначала обсудить сходства. Необязательные параметры Dart являются необязательными в том смысле, что вызывающей стороне не требуется указывать значение параметра при вызове функции. Необязательные параметры могут быть объявлены только после любых обязательных параметров. Необязательные параметры могут иметь значение по умолчанию, которое используется, когда вызывающая сторона не указывает значение. Позиционные необязательные параметры Параметр, заключенный в [ ] является позиционным необязательным параметром. Вот пример:
getHttpUrl(String server, String path, [int port=80]) // .
>
В приведенном выше коде port является необязательным и имеет значение по умолчанию 80 . Вы можете вызвать getHttpUrl с третьим параметром или без него.
getHttpUrl('example.com', '/index.html', 8080); // port == 8080
getHttpUrl('example.com', '/index.html'); // port == 80
Вы можете указать несколько позиционных параметров для функции:
getHttpUrl(String server, String path, [int port=80, int numRetries=3]) // .
>
Необязательные параметры являются позиционными в том numRetries что вы не можете опустить port если хотите указать numRetries .
getHttpUrl('example.com', '/index.html');
getHttpUrl('example.com', '/index.html', 8080);
getHttpUrl('example.com', '/index.html', 8080, 5);
Конечно, если вы не знаете, что такое 8080 и 5, трудно сказать, что это за магические числа. Вы можете использовать именованные необязательные параметры для создания более удобочитаемых API. Именованные необязательные параметры Параметр, заключенный в < >является именованным необязательным параметром. Вот пример:
getHttpUrl(String server, String path, ) // .
>
Вы можете вызвать getHttpUrl с третьим параметром или без него. Вы должны использовать имя параметра при вызове функции.
getHttpUrl('example.com', '/index.html', port: 8080); // port == 8080
getHttpUrl('example.com', '/index.html'); // port == 80
Вы можете указать несколько именованных параметров для функции:
getHttpUrl(String server, String path, ) // .
>
Поскольку на именованные параметры ссылаются по имени, они могут использоваться в порядке, отличном от их объявления.
getHttpUrl('example.com', '/index.html');
getHttpUrl('example.com', '/index.html', port: 8080);
getHttpUrl('example.com', '/index.html', port: 8080, numRetries: 5);
getHttpUrl('example.com', '/index.html', numRetries: 5, port: 8080);
getHttpUrl('example.com', '/index.html', numRetries: 5);
Я полагаю, что именованные параметры упрощают понимание сайтов вызовов, особенно когда есть логические флаги или номера вне контекста. Проверка, был ли предоставлен необязательный параметр К сожалению, вы не можете различить случаи «необязательный параметр не был предоставлен» и «необязательный параметр был предоставлен со значением по умолчанию». Примечание. Вы можете использовать позиционные необязательные параметры или именованные необязательные параметры, но не оба в одной и той же функции или методе. Следующее не допускается.
thisFunctionWontWork(String foo, [String positonal], ) // will not work!
>
Именованные аргументы — Python: Функции
В Python у функций могут быть еще и именованные аргументы — keyword arguments.
Например, мы вызываем следующую функцию:
def bar(length, char1, char2): return (char1 + char2) * length + char1 print(bar(5, '-', '*')) # => -*-*-*-*-*-
У функции bar три аргумента. При вызове функции с позиционными аргументами важную роль играет порядок размещения передаваемых аргументов. Но если мы хотим изменить порядок, то нужно использовать именованные аргументы. В этом уроке мы научимся работать с ними.
Именованные аргументы
Чтобы передать именованные аргументы в функцию, нужно указать их имена, которые были заданы при объявлении функции:
def bar(length, char1, char2): return (char1 + char2) * length + char1 print(bar(length=3, char1='-', char2='*')) # => -*-*-*- print(bar(char1='-', char2='*', length=3)) # => -*-*-*- print(bar(char2='*', length=3, char1='-')) # => -*-*-*-
При вызове функции меняется порядок передаваемых аргументов. Когда функции назначаются соответствующие значения именованных аргументов, Python учитывает их имена, а не позиции. В результате функция будет всегда выводить одно и то же значение независимо от позиций переданных ей аргументов.
Значения аргументов по умолчанию
Предположим, что char1 и char2 чаще получают одни и те же значения. В такой ситуации удобно указать значения по умолчанию:
def bar(length, char1='-', char2='*'): return (char1 + char2) * length + char1 print(bar(5)) # => -*-*-*-*-*- print(bar(3, '.')) # => .*.*.*. print(bar(2, ':', '|')) # => :|:|:
Теперь предположим, что нас устраивает значение по умолчанию для char1 , но мы хотим задать свое значение для char2 . Это можно сделать с помощью именованных аргументов:
print(bar(4, char2='#')) # => -#-#-#-#- print(bar(char2='$', length=3)) # => -$-$-$-
Здесь имеет значение порядок групп аргументов — позиционные значения должны быть указаны до именованных. Иначе мы получим ошибку:
print(bar(char2='%', 2)) # => SyntaxError: positional argument follows keyword argument
Если у функции есть позиционные аргументы без значений по умолчанию, значения для этих аргументов все равно нужно указать либо в виде позиционных значений, либо в виде именованных. Нарушение этого правила приведет к ошибке вида:
bar(char2='!') # TypeError: bar() missing 1 required positional argument: 'length'
Нужно различать синтаксис объявления аргументов функции и синтаксис вызова функции. При вызове функции у нас больше свободы. Например, можно указывать именованные аргументы перед разворачиваемой группой позиционных:
def f(*args, x=None, y=None): print('args =', args, ', x =', x, ', y =', y) f(*(1, 2), x='a', *[3, 4], y='b', *(5, 6)) # => args = (1, 2, 3, 4, 5, 6), x = a, y = b
В данном примере переменная args содержит все позиционные аргументы, которые были переданы функции. А переменные x и y содержат значения аргументов, которые были переданы по именам.
Случаи применения именованных аргументов
Нет строгих правил, по которым используются именованные аргументы. Однако широко практикуется такой подход: если функция принимает больше трех аргументов, нужно хотя бы часть из них указать по имени. Важно именовать значения аргументов, если несколько значений имеют одинаковый тип. В другом случае будет трудно понять, что делает функция с подобным вызовом:
make('circle', 300, 150, 10, None, 2.5, False)
make( shape='circle', x=300, y=150, radius=10, line_pattern=None, line_width=2.5, fill=False )
Такой код читать проще.
У вышеупомянутого правила есть пара исключений:
- Если по названию функции можно сразу понять, что она выполняет и какие параметры принимает, то имена аргументам не задаются. Например, можно понять, что скрывается за значениями в вызове point3d(10, 50, 21) или rgb(0, 255, 0)
- Не нужно указывать имена аргументам, которые объявлены через * . У этого нет смысла и возможности
def sum(*args): … sum(x1=1, x2=2) # TypeError: sum() got an unexpected keyword argument 'x1'
В таких функциях имя args недоступно извне, ведь это не один аргумент, а получатель произвольного их количества.
Выводы
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
