сколько аргументов можно передать в функцию

Зона кода

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

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

Знакомство с функциями с переменным числом аргументов

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

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

Вот пример заголовка функции с переменным числом аргументов:

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

Доступ к необязательным параметрам в теле функции

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

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

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

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

Например, в теле функции fun() вызов макроса должен выглядеть так:

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

После того, как макрос va_arg() вызван нужное количество раз, необходимо вызвать макрос va_end() :

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

Ближе к делу

А теперь давайте обсудим особенности реализаций типа va_list и макросов, предназначенных для создания функций с переменным числом аргументов, в компиляторе MinGW64, работающем под управлением операционной системы Windows 10. Именно это программное обеспечение установлено на моём ноутбуке и именно его я буду использовать для запуска и компиляции программ, рассмотренных далее.

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

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

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

Последние две версии можно, кстати, объединить в третью.

А теперь рассмотрим два примера функций с переменным числом аргументов. При их создании будем использовать макросы. Всё будем делать «по науке», как положено. Нужно использовать макрос va_end() — значит будем использовать.

Первый пример функции с переменным числом аргументов

Создадим функцию print() с переменным числом аргументов. Единственный обязательный формальный параметр str будет иметь тип char * и содержать адрес C-строки. Все остальные параметры будут необязательными. Предполагается, что значение каждого необязательного аргумента — это либо целое число, либо вещественное число, либо символ, либо адрес C-строки. Функция будет выводить на консоль значения необязательных параметров в том порядке, в котором они были переданы функции (с тем очевидным исключением, что вместо адресов C-строк будут выводиться сами C-строки).

Как мы видим, к программе подключён заголовок (стр. 2).

Не забываем напоследок вызвать макрос va_end() (стр. 34).

Функция print() вызывается из main() ; первой из них, как мы видим, в качестве необязательных фактических аргументов передаются значения всех четырёх видов (но трёх типов, поскольку символы и целые имеют тип int ).

В результате запуска программы получаем следующий консольный вывод:

то в ходе компиляции мы получили бы предупреждение:

In function ‘print’:
[Warning] ‘char’ is promoted to ‘int’ when passed through ‘…’
[Note] (so you should pass ‘int’ not ‘char’ to ‘va_arg’)
[Note] if this code is reached, the program will abort

Программа скомпилировалась бы, но её запуск привёл бы к аварийному завершению.

Второй пример функции с переменным числом аргументов

В некоторых языках программирования, например, в C++ и Java поддерживается перегрузка функций. Под этим понимается сосуществование в одной области видимости функций, имеющих одинаковые имена, но различающихся количеством или (и) типами формальных параметров. Обычно одноимённые функции выполняют, по существу, близкие действия.

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

Второй обязательный формальный параметр num имеет тип int и содержит число необязательных параметров.

Если необязательные параметры — это целые или вещественные числа, то функция вычисляет их сумму и получает результат в виде значения типа int в первом случае или типа double во втором. А если необязательные параметры — это адреса C-строк, то функция выполняет конкатенацию всех C-строк, получая новую строку. Теперь уже результатом будет адрес новой строки (т. е. значение типа char * ).

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

В результате выполнения программы на консоль выводится следующий текст:

А можно обойтись без макросов?

Да, можно, поскольку мы имеем представление о том, как «работают» макросы в нашем случае. Но нам потребуется некоторая дополнительная информация. А именно, нам нужно получить ответы на 2 вопроса:

Заметим, что, вообще говоря, размер памяти, выделяемой в стеке под значение параметра, необязательно совпадает с размером значения, а может его превосходить.

Заметим, что размер переменной типа int составляет 4 байта. Таким образом, при хранении значения этого типа используется только половина отведённой памяти. Оказалось, что задействованы младшие 4 байта из 8 (под «младшими» понимаются имеющие меньшие адреса).

Этой информации вполне достаточно, чтобы написать новую версию функции sum() первой программы. Приводим код новой версии программы целиком:

Поскольку после получения значения последнего необязательного параметра значение p уже не изменяется, по окончании цикла p содержит адрес последнего параметра. А в случае использования va_arg() по окончании цикла в argptr находился адрес первого байта, следующего за 8-байтовой ячейкой стека, содержащей значение последнего необязательного параметра.

Макросу va_end никакой код в новой версии функции не соответствует.

Функция main() остаётся без изменений, как не изменяется и результат работы программы, выводимый на консоль.

Преимущество кода, не использующего макросы, определённые в файле stdarg.h, заключается в том, что он очень гибок. При желании мы можем «перепрыгивать» с одного значения необязательного параметра на другое, двигаться по стеку в любом направлении любое количество раз. В случае использования макросов наши возможности несколько ограничены: мы можем двигаться по стеку лишь в одном направлении. Чтобы вернуться к какому-либо уже пройденному значению, необходимо начинать весь путь заново.

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

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

Меры предосторожности

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

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

А вот предумышленный обман может произойти со стороны пользователя программы, при условии, что информация, полученная от него, без проверок передаётся функции с переменным числом аргументов. Такие рода ситуации описаны в статье хорошо известного Криса Касперски «Неизвестная уязвимость функции printf».

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

Источник

Параметры и аргументы функции

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

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

Рассмотрим схему и поясняющий ее пример:

Когда интерпретатор переходит к функции, чтобы начать ее исполнение, он присваивает переменным-параметрам переданные в функцию значения-аргументы. В примере переменной a будет присвоено 100, b будет присвоено 12.

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

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

Произвольное количество аргументов

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

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

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

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

В данном случае оба вызова – это вызовы с одними и теми же аргументами-значениями. Просто в первом случае сопоставление параметрам-переменным идет в порядке следования. Во-втором случае – по ключам, которыми выступают имена параметров.

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

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

Практическая работа

Напишите программу, в которой определены следующие четыре функции:

Функция getInput не имеет параметров, запрашивает ввод с клавиатуры и возвращает в основную программу полученную строку.

Функция strToInt имеет один параметр. В теле преобразовывает переданное значение к целочисленному типу. Возвращает полученное число.

Функция printInt имеет один параметр. Она выводит переданное значение на экран и ничего не возвращает.

Примеры решения и дополнительные уроки в android-приложении и pdf-версии курса

Источник

Функции с переменным числом параметров

Функции с переменным числом параметров

К ак уже обсуждалось ранее, по умолчанию параметры передаются функции через стек. Поэтому, технически, нет ограничения на количество передаваемых параметров – “запихать” можно сколько угодно. Проблема в том, как потом функция будет разбирать переданные параметры. Функции с переменным числом параметров объявляются как обычные функции, но вместо недостающих аргументов ставится многоточие. Пусть мы хотим сделать функцию, которая складывает переданные ей числа, чисел может быть произвольное количество. Необходимо каким-то образом передать функции число параметров. Во-первых, можно явно передать число параметров обязательным аргументом. Во-вторых, последний аргумент может иметь некоторое «терминальное» значение, наткнувшись на которое функция закончит выполнение.
Общий принцип работы следующий: внутри функции берём указатель на аргумент, далее двигаемся к следующему аргументу, увеличивая значение указателя.

OLD SCHOOL

Д елаем всё вручную. Функция, которая складывает переданные ей аргументы

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

Далее считываем все числа и складываем их. В этой функции мы также при сложении проверяем на переполнение типа unsigned.

Можно сделать первый аргумент необязательным и «перешагнуть» аргумент unsigned char num, но тогда возникнет большая проблема: аргументы располагаются друг за другом, но не факт, что непрерывно. Например, в нашем случае первый аргумент будет сдвинут не на один байт, а на 4 относительно num. Это сделано для повышения производительности. На другой платформе или с другим компилятором, или с другими настройками компилятора могут быть другие результаты.

Поэтому лучше число параметров, если это аргумент, сделать типом int или unsigned int.

Можно сделать по-другому: в качестве «терминального» элемента передавать ноль и считать, что если мы встретили ноль, то больше аргументов нет. Пример

Но теперь уже передавать нули в качестве аргументов нельзя. Здесь также есть один обязательный аргумент – первое переданное число. Если его не передавать, то мы не сможем найти адрес, по которому размещаются переменные в стеке. Некоторые компиляторы (Borland Turbo C) позволяют получить указатель на …, но такое поведение не является стандартным и его нужно избегать.

VA_ARG

М ожно воспользоваться макросом va_arg библиотеки stdarg.h. Он делает практически то же самое, что и мы: получает указатель на первый аргумент а затем двигается по стеку. Пример, та же функция, только с va_arg

Первый аргумент – число параметров – также лучше делать типа int, иначе получим проблему со сдвигом, кратным 4.

Макросы и типы для работы с переменным числом параметров

НазваниеОписание
va_listТип, который используется для извлечения дополнительных параметров функции с переменным числом параметров
void va_start(va_list ap, paramN)Макрос инициализирует ap для извлечения дополнительных аргументов, которые идут после переменной paramN. Параметр не должен быть объявлена как register, не может иметь типа массива или указателя на функцию.
void va_end(va_list ap)Макрос необходим для нормального завершения работы функции, работает в паре с макросом va_start.
void va_copy(va_list dest, va_list src)Макрос копирует src в dest. Поддерживается начиная со стандарта C++11

Неправильное использование

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

Так как очистку стека производит вызывающая функция, то стек не будет повреждён. Получается, что если изменить схему вызова и сделать так, чтобы вызываемый объект сам чистил стек после себя, то в случае неправильного количества аргументов стек будет повреждён. То есть, буде функция объявлена как __stdcall, в целях безопасности она не может иметь переменного числа аргументов.
Однако, если добавить спецификатор __stdcall к нашей функции summ она будет компилироваться. Это связано с тем, что компилятор автоматически заменит __stdcall на __cdecl.

Программа завершится с ошибкой вроде The value of ESP was not properly saved across a function call.

Источник

Сколько аргументов теоретически можно передать в качестве параметров в функциях c ++?

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

Мне просто интересно, потому что я должен поддерживать функции из 5+ аргументов здесь, на моей работе.

3 ответа

Ни стандарты C, ни C ++ не предъявляют абсолютных требований к количеству аргументов / параметров, которые вы должны иметь возможность передавать при вызове функции, но стандарт C предполагает, что реализация должна поддерживать не менее 127 параметров / аргументов (§5.2.4.1 / 1), а стандарт C ++ предполагает, что он должен поддерживать как минимум 256 параметров / аргументов (§B / 2).

Точная формулировка стандарта C:

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

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

Стандарт C ++ даже не заходит так далеко, а только говорит, что:

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

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

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

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

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

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

Похоже, вы попадаете на субъективную территорию, учитывая, что аргументы C (обычно) передаются механически так же, как и другие аргументы.

Первые несколько аргументов помещаются в регистры ЦП в большинстве ABI. Сколько зависит от количества архитектурных регистров; он может варьироваться от двух до десяти. В C ++ пустые классы (например, теги отправки перегрузки) обычно полностью опускаются. Загрузка данных в регистры обычно обходится «дешево как бесплатно».

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

Источник

Функции в Python

В предыдущих разделах мы уже часто сталкивались с встроенными функция ( int, float, print, type, len ) Каждая функция в Python предназначена для выполнения одной конкретной задачи. Использование функции упрощает написание и чтение кода.

Содержание страницы:
1. Функция в Python
2. Передача аргументов функции
2.1 Позиционные аргументы
2.2. Именованные аргументы
2.3. Значения по умолчанию
2.4. Передача произвольного набора аргументов
2.5. Позиционные аргументы с произвольным набором аргументов
2.6. Произвольный набор именнованных аргументов
3. Возвращаемое значение в функции
3.1. Возвращение простого значения
3.2. Возвращение словаря
4. Использования функции в цикле while
5. Передача списка функции на Python
6. Использование лямбда-выражений вместо функций

1. Функция в Python

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

Напишем функцию, которая вычисляет квадрат своего аргумента и выводит на экран:

>>> def square ( number ):
. «»»Вычисление квадрата числа»»»
. print(number ** 2)
.
>>> square (5)
25
>>> square (124.45)
15487.802500000002

Команда squre(5) вызывает функции square() и передает ей значение аргумента, для выполнения команды print. Функция возводит число в квадрат и выводит на экран.

2. Передача аргументов функции в Python

2.1. Позиционные аргументы

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

>>> def car (car_brend, car_model, mileage):
. «»»Выводит информацию о автомобиле»»»
. print(f»Продается с пробегом км.»)
.
>>> car (‘bmw’, ‘x5’, 51345)
Продается Bmw X5 с пробегом 51345 км.

2.2. Именованные аргументы

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

>>> def car (car_brend, car_model, mileage):
. «»»Выводит информацию о автомобиле»»»
. print(f»Продается с пробегом км.»)
.
>>> car (mileage = 45152, car_model = ‘x5′, car_brend=’bmw’)
Продается Bmw X5 с пробегом 45152 км.

При обработке вызова функции Python знает к какому аргументу принадлежат данные и проблем с выводом не случается.

2.3. Значения по умолчанию

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

>>> def car (car_model, mileage, car_brend=’bmv’):
. «»»Выводит информацию о автомобиле»»»
. print(f»Продается с пробегом км.»)
.
>>> car (‘x7’, 12345)
Продается Bmv X7 с пробегом 12345 км.

Для изменения значения по умолчанию, мы можем передать именованный аргумент для изменения значения car_brend=’audi’:

>>> car (‘q7’, 35600, car_brend=’audi’)
Продается Audi Q7 с пробегом 35600 км.

Так как аргумент для параметра car_brend задан явно, Python игнорирует значение по умолчанию.

2.4. Передача произвольного набора аргументов

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

>>> def cars ( * args ):
. «»»Вывод автомобилей»»»
. print( args )
.
>>> cars (‘audi’, ‘bmv’, ‘ford’, ‘kia’)
(‘audi’, ‘bmv’, ‘ford’, ‘kia’)
>>> cars (‘porshe’)
(‘porshe’)

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

Для более удобной работы с данными, например изменения регистра символов можно воспользоваться циклом for:

>>> def cars ( * args):
. «»»Вывод автомобилей в продаже»»»
. print(‘Автомобили в продаже:’)
. for arg in args:
. print(f»-«)
.
>>> cars (‘audi’, ‘bmv’, ‘ford’, ‘kia’)
Автомобили в продаже:
-Audi
-Bmv
-Ford
-Kia

2.5. Позиционные аргументы с произвольным набором аргументов

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

>>> def car (car_brend, car_model, * colors):
. «»»Выводит информацию о автомобиле»»»
. print(f»Автомобиль можно заказать в цветах:»)
. for color in colors:
. print(f»-«)
.
>>> car (‘bmw’, ‘x7’, ‘синий’, ‘зеленый’, ‘белый’, ‘черный’, ‘желтый’)
Автомобиль Bmw X7 можно заказать в цветах:
-синий
-зеленый
-белый
-черный
-желтый

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

В большинстве программ часто используется имя обобщенного параметра *args для хранения произвольного набора позиционных аргументов.

2.6. Произвольный набор именованных аргументов

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

>>> def profile (first, last, **user_info):
. «»»Возвращает словарь с данными о пользователе»»»
. user_info[‘first_name’] = first
. user_info[‘last_name’] = last
. return user_info
.
>>> profile_1 = profile (‘tomas’, ‘edisson’, location=’usa’)
>>> print(profile_1)

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

3. Возвращаемое значение в функции на Python

3.1. Возвращение простого значения

Напишем функцию, которая возвращает отформатированное имя и фамилию

>>> def form_name (last_name, first_name, middle_name):
. «»»Возвращает отформатированное полное имя»»»
. full_name = f» »
. return full_name.title()
.
>>> poet = form_name (‘пушкин’, ‘александр’, ‘сергеевич’)
>>> print(poet)
Пушкин Александр Сергеевич

>>> def form_name (last_name, first_name, middle_name=»):
. «»»Возвращает отформатированное полное имя»»»
. full_name = f» »
. return full_name.title()
.
>>> poet = form_name (‘пушкин’, ‘александр’)
>>> print(poet)
Пушкин Александр
>>> poet = form_name(‘пушкин’, ‘александр’, ‘сергеевич’)
>>> print(poet)
Пушкин Александр Сергеевич

С необязательным аргументом мы не получим ошибку (TypeError: form_name() missing 1 required positional argument: ‘middle_name’) в случае отсутствия на входе данных по аргументу.

3.2. Возвращение словаря

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

>>> def info_person (first_name, last_name):
. «»»Возвращает словарь с данными о человеке»»»
. person = <'first': first_name, 'last': last_name>
. return person
.
>>> musician = info_person (‘Freddie’, ‘Mercury’)
>>> print(musician)

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

4. Использования функции в цикле while

Функции могут вызываться в циклах while где угодно. Приведем пример цикла while, где у посетителя запрашивают имя и фамилию, а с помощью функции form_name возвращается отформатированное имя и фамилия с приветствием:

def form_name (first_name, last_name):
«»»Возвращает отформатированное полное имя»»»
full_name = f» »
return full_name.title()

while True:
print(«\nВведите ‘x’ если хотите завершить программу»)
first_name = input(«Введите ваше имя: «)
if first_name == ‘x’:
break
last_name = input(«Введите вашу фамилию: «)
if last_name == ‘x’:
break
formatted_name = form_name (first_name, last_name)
print(f»\nДобрый день !»)

В данном примере в цикле whle запрашивается имя и фамилия и с помощью функции form_name возвращается отформатированное полное имя и записывается в переменную formatted_name. А затем уже с помощью функции print данные выводятся на экран.

5. Передача списка функции на Python

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

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

6. Использование лямбда-выражений вместо функций

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

>>> square = lambda x : x ** 2
>>> print(square(5))
25

Лямбда-выражение может иметь и несколько параметров. Например, перемножать передаваемые числа.

>>> mult = lambda x, y, z : x * y * z
>>> print(mult(2, 4, 6))
48

Таким образом любая простая функция в форме

может быть выражена в более компактной форме посредством лямбда-выражения

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *