{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Функции" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Чтобы выполнить задачу, определеннуюввиде функции, вы указываете имя функции, отвечающей за эту задачу. Если задча должна многократно выполняться в программе, вам не придется заново вводить весь необходимый код; просто вызовите функцию, предназначенную для решения задачи, и этот вызов приказывает Python выполнить код, содержащийся внутри функции. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello!\n" ] } ], "source": [ "def greet_user():\n", " \"\"\"Выводит простое приветствие.\"\"\"\n", " print(\"Hello!\")\n", "greet_user()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello!\n" ] } ], "source": [ "greet_user()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Передача информации функции" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "С небольшими изменениями функция greet_user()сможет не только сказать «Привет!» пользователю, но и поприветствовать его по имени. Для этого следует включить имя username в круглых скобках в определение функции def greet_user(). С добавлением username функция примет любое значение, которое будет заключено в скобки при вызове. Теперь функция ожидает, что при каждом вызове будет передаваться имя пользователя. При вызове greet_user() укажите имя (например,'jesse') в круглых скобках:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, Jesse!\n" ] } ], "source": [ "def greet_user(username):\n", " \"\"\"Выводит простое приветствие.\"\"\"\n", " print(\"Hello, \" + username.title() + \"!\")\n", "greet_user('jesse')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Аргументы и параметры" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Функция greet_user() определена так, что для работы она должна получить значение переменной username. После того как функция будет вызвана и получит необходимую информацию (имя пользователя), она выведет правильное приветствие." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Переменная username в определении greet_user() — параметр, то есть условные данные, необходимые функции для выполнения ее работы. Значение'jesse'в greet_user('jesse') — _аргумент_, то есть конкретная информация, переданная при вызове функции. Вызывая функцию, вы заключаете значение, с которым функция должна работать, в круглые скобки. В данном случае аргумент 'jesse' был передан функции greet_user(), а его значение было сохранено в переменной username." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Передача аргументов" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Определение функции может иметь несколько параметров, и может оказаться, что при вызове функции должны передаваться несколько аргументов. Существуют несколько способов передачи аргументов функциям.Позиционные аргументы перечисляются в порядке, точно соответствующем порядку записи параметров; именованные аргументы состоят из имени переменной изначения; наконец, существуют списки и словари значений. Рассмотрим все эти способы." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Позиционные аргументы" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "При вызове функции каждому аргументу должен быть поставлен в соответствие параметр в определении функции. Проще всего сделать это на основании порядка перечисления аргументов. Значения, связываемые с аргументами подобным образом, называются позиционными аргументами.Чтобы понять, как работает эта схема, рассмотрим функцию для вывода информации о домашних животных. Функция сообщает тип животного и его имя:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "I have a hamster.\n", "My hamster's name is Harry.\n" ] } ], "source": [ "def describe_pet(animal_type, pet_name):\n", " \"\"\"Выводит информацию оживотном.\"\"\"\n", " print(\"\\nI have a \" + animal_type + \".\")\n", " print(\"My \" + animal_type + \"'s name is \" + pet_name.title() + \".\")\n", "describe_pet('hamster', 'harry')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Многократные вызовы функций" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Функция может вызываться в программе столько раз, сколько потребуется. Для вывода информации о другом животном достаточно одного вызова __describe_pet()__:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "I have a hamster.\n", "My hamster's name is Harry.\n", "\n", "I have a dog.\n", "My dog's name is Willie.\n" ] } ], "source": [ "def describe_pet(animal_type, pet_name):\n", " \"\"\"Выводит информацию оживотном.\"\"\"\n", " print(\"\\nI have a \" + animal_type + \".\")\n", " print(\"My \" + animal_type + \"'s name is \" + pet_name.title() + \".\")\n", " \n", "describe_pet('hamster', 'harry')\n", "describe_pet('dog', 'willie')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### О важности порядка позиционных аргументов" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если нарушить порядок следования аргументов ввызове при использовании позиционных аргументов, возможны неожиданные результаты:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "I have a harry.\n", "My harry's name is Hamster.\n" ] } ], "source": [ "def describe_pet(animal_type, pet_name):\n", " \"\"\"Выводит информацию оживотном.\"\"\"\n", " print(\"\\nI have a \" + animal_type + \".\")\n", " print(\"My \" + animal_type + \"'s name is \" + pet_name.title() + \".\")\n", "describe_pet('harry', 'hamster')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Именованные аргументы" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Именованный аргумент_ представляет собой пару «имя—значение», передаваемую функции. Имя изначение связываются с аргументом напрямую, так что при передаче аргумента путаница с порядком исключается. Именованные аргументы избавляют от хлопот с порядком аргументов при вызове функции, а также проясняют роль каждого значения ввызове функции." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "I have a hamster.\n", "My hamster's name is Harry.\n" ] } ], "source": [ "def describe_pet(animal_type, pet_name):\n", " \"\"\"Выводит информацию оживотном.\"\"\"\n", " print(\"\\nI have a \" + animal_type + \".\")\n", " print(\"My \" + animal_type + \"'s name is \" + pet_name.title() + \".\")\n", " \n", "describe_pet(animal_type='hamster', pet_name='harry')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Значения по умолчанию" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Для каждого параметра вашей функции можно определить значение по умолчанию. Если при вызове функции передается аргумент, соответствующий данному параметру, Python использует значение аргумента, а если нет — использует значение по умолчанию. Таким образом, если для параметра определено значениепо умолчанию, вы можете опустить соответствующий аргумент, который обычно включается ввызов функции. Значения по умолчанию упрощают вызовы функцийи проясняют типичные способы использования функций. Например, если вы заметили, что большинство вызововd escribe_pet() используется для описания собак, задайте animal_type значение по умолчанию'dog'.Теперь в любом вызове describe_pet() для собаки эту информацию можно опустить:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "I have a dog.\n", "My dog's name is Willie.\n" ] } ], "source": [ "def describe_pet(pet_name, animal_type='dog'):\n", " \"\"\"Выводит информацию оживотном.\"\"\"\n", " print(\"\\nI have a \" + animal_type + \".\")\n", " print(\"My \" + animal_type + \"'s name is \" + pet_name.title() + \".\")\n", " \n", "describe_pet(pet_name='willie')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Эквивалентные вызовы функций" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Так как позиционные аргументы, именованные аргументы изначения по умолчанию могут использоваться одновременно, часто существуют несколько эквивалентных способов вызова функций. Возьмем оператор describe_pets()с однимзначением по умолчанию:\n", "
def describe_pet(pet_name, animal_type='dog'):\n", "
При таком определении аргумент для параметра pet_name должен задаваться в любом случае, но это значение может передаваться как в позиционном, так и в именованном формате. Если описываемое животное не является собакой, то аргумент animal_type тоже должен быть включен в вызов, и этот аргумент тоже может быть задан как в позиционном, так и в именованном формате.Все следующие вызовы являются допустимыми для данной функции:\n", "
describe_pet('willie')\n", "
describe_pet(pet_name='willie')\n", "
describe_pet('harry', 'hamster')\n", "
describe_pet(pet_name='harry', animal_type='hamster')\n", "
describe_pet(animal_type='hamster', pet_name='harry')\n", "
Все вызовы функции выдадут такой же результат как и в предыдущих примерах." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Возвращаемое значение" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Функция не обязана выводить результаты своей работы. В место этого она может обработать данные, а затем вернуть значение или набор сообщений. Значение,возвращаемое функцией, называется _возвращаемым значением_. Команда __return__ передает значение из функции в строку, в которой эта функция была вызвана. Возвращаемые значения помогают переместить бульшую часть рутинной работы в вашей программе в функции, чтобы упростить основной код программы." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Возвращение простого значения" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Рассмотрим функцию, которая получает имя и фамилию и возвращает аккуратно отформатированное полное имя:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jimi Hendrix\n" ] } ], "source": [ "def get_formatted_name(first_name, last_name):\n", " \"\"\"Возвращает аккуратно отформатированное полное имя.\"\"\"\n", " full_name = first_name + ' ' + last_name\n", " return full_name.title()\n", "\n", "musician = get_formatted_name('jimi', 'hendrix')\n", "print(musician)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Необязательные аргументы" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Иногда бывает удобно сделать аргумент необязательным, чтобы разработчик, использующий функцию, мог передать дополнительную информацию только в том случае, если он этого захочет. Чтобы сделать аргумент необязательным, можно воспользоваться значением по умолчанию. Допустим, вы захотели расширить функцию get_formatted_name(), чтобы она также работала и со вторыми именами.Первая попытка могла бы выглядеть так:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "John Lee Hooker\n" ] } ], "source": [ "def get_formatted_name(first_name, middle_name, last_name):\n", " \"\"\"Возвращает аккуратно отформатированное полное имя.\"\"\"\n", " full_name = first_name + ' ' + middle_name + ' ' + last_name\n", " return full_name.title()\n", "\n", "musician = get_formatted_name('john', 'lee', 'hooker')\n", "print(musician)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Однако вторые имена нужны не всегда, а в такой записи функция не будет работать, если при вызове ей передаются только имя и фамилия. Чтобы средний аргумент был необязательным, можно присвоить аргументу middle_name пустое значение по умолчанию; этот аргумент игнорируется, если пользователь не передал для него значение. Чтобы функция get_formatted_name() работала без второго имени, следует назначить для параметра middle_name пустую строку значением по умолчанию и переместить его в конец списка параметров:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Jimi Hendrix\n", "John Lee Hooker\n" ] } ], "source": [ "def get_formatted_name(first_name, last_name, middle_name=''):\n", " \"\"\"Возвращает аккуратно отформатированное полное имя.\"\"\"\n", " if middle_name:\n", " full_name = first_name + ' ' + middle_name + ' ' + last_name\n", " else:\n", " full_name = first_name + ' ' + last_name\n", " return full_name.title()\n", "\n", "musician = get_formatted_name('jimi', 'hendrix')\n", "print(musician)\n", "\n", "musician = get_formatted_name('john', 'hooker', 'lee')\n", "print(musician)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Возвращение словаря" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Функция может вернуть любое значение, нужное вам, в том числе и более сложную структуру данных (например, список или словарь). Так, следующая функция получает части имени и возвращает словарь, представляющий человека:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'first': 'jimi', 'last': 'hendrix'}\n" ] } ], "source": [ "def build_person(first_name, last_name):\n", " \"\"\"Возвращает словарь синформацией очеловеке.\"\"\"\n", " person = {'first': first_name, 'last': last_name}\n", " return person\n", "\n", "musician = build_person('jimi', 'hendrix')\n", "print(musician)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Использование функции вцикле while" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Please tell me your name:\n", "(enter 'q' at any time to quit)\n", "First name: Ivan\n", "Last name: Klopov\n", "\n", "Please tell me your name:\n", "(enter 'q' at any time to quit)\n", "First name: q\n", "\n", "Hello, Q Klopov!\n" ] } ], "source": [ "def get_formatted_name(first_name, last_name):\n", " \"\"\"Возвращает аккуратно отформатированное полное имя.\"\"\"\n", " full_name = first_name + ' ' + last_name\n", " return full_name.title()\n", " \n", "while True:\n", " print(\"\\nPlease tell me your name:\")\n", " print(\"(enter 'q' at any time to quit)\")\n", " f_name = input(\"First name: \")\n", " if f_name == 'q':\n", " break\n", " l_name = input(\"Last name: \")\n", " if l_name == 'q':\n", " break\n", " \n", "formatted_name = get_formatted_name(f_name, l_name)\n", "print(\"\\nHello, \" + formatted_name + \"!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Передача списка" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Часто при вызове функции удобно передать список — имен, чисел или более сложных объектов (например, словарей). При передаче списка функция получает прямой доступ ко всему его содержимому. Мы воспользуемся функциями для того,чтобы сделать работу со списком более эффективной. Допустим, вы хотите вывести приветствие для каждого пользователя из списка. Вследующем примере список имен передается функции greet_users(), которая выводит приветствие для каждого пользователя по отдельности:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, Hannah!\n", "Hello, Ty!\n", "Hello, Margot!\n" ] } ], "source": [ "def greet_users(names):\n", " \"\"\"Вывод простого приветствия для каждого пользователя всписке.\"\"\"\n", " for name in names:\n", " msg = \"Hello, \" + name.title() + \"!\"\n", " print(msg)\n", " \n", "usernames = ['hannah', 'ty', 'margot']\n", "greet_users(usernames)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Изменение списка в функции" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если вы передаете список функции, код функции сможет изменить список. Все изменения, внесенные в список в теле функции, закрепляются, что позволяет эффективно работать со списком даже при больших объемах данных. Допустим, компания печатает на 3D-принтере модели, предоставленные пользователем. Проекты хранятся в списке, а после печати перемещаются в отдельный список. Вследующем примере приведена реализация, не использующая функции:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Printing model: dodecahedron\n", "Printing model: robot pendant\n", "Printing model: iphone case\n", "\n", "The following models have been printed:\n", "dodecahedron\n", "robot pendant\n", "iphone case\n" ] } ], "source": [ "# Список моделей, которые необходимо напечатать.\n", "unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']\n", "completed_models = []\n", "# Цикл последовательно печатает каждую модель до конца списка.# После печати каждая модель перемещается в список completed_models.\n", "while unprinted_designs:\n", " current_design = unprinted_designs.pop()\n", " # Печать модели на 3D-принтере.\n", " print(\"Printing model: \" + current_design)\n", " completed_models.append(current_design)\n", "# Вывод всех готовых моделей.\n", "print(\"\\nThe following models have been printed:\")\n", "for completed_model in completed_models:\n", " print(completed_model)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В начале программы создается список моделей и пустой список completed_models,в который каждая модель перемещается после печати. Пока в unprinted_designs остаются модели, цикл while имитирует печать каждой модели: модель удаляется с конца списка, сохраняется в current_design, а пользователь получает сообщение о том, что текущая модель была напечатана. Затем модель перемещается в список напечатанных. После завершения цикла выводится список напечатанных моделей." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Мы можем изменить структуру этого кода: для этого следует написать две функции, каждая из которых решает одну конкретную задачу. Большая часть кода останется неизменной; просто программа становится более эффективной. Первая функция занимается печатью, а вторая выводит сводку напечатанных моделей:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Printing model: dodecahedron\n", "Printing model: robot pendant\n", "Printing model: iphone case\n", "\n", "The following models have been printed:\n", "dodecahedron\n", "robot pendant\n", "iphone case\n" ] } ], "source": [ "def print_models(unprinted_designs, completed_models):\n", " \"\"\"Имитирует печать моделей, пока список не станет пустым.Каждая модель после печати перемещается вcompleted_models.\"\"\"\n", " while unprinted_designs:\n", " current_design = unprinted_designs.pop()\n", " # Имитация печати модели на 3D-принтере.\n", " print(\"Printing model: \" + current_design)\n", " completed_models.append(current_design)\n", "def show_completed_models(completed_models):\n", " \"\"\"Выводит информацию обо всех напечатанных моделях.\"\"\"\n", " print(\"\\nThe following models have been printed:\")\n", " for completed_model in completed_models:\n", " print(completed_model)\n", "unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']\n", "completed_models = []\n", "print_models(unprinted_designs, completed_models)\n", "show_completed_models(completed_models)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Запрет изменения списка в функции" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Иногда требуется предотвратить изменение списка в функции. Допустим, у вас имеется список моделей для печати, и вы пишете функцию для перемещения их в список готовых моделей, как в предыдущем примере. Возможно, даже после печати всех моделей исходный список нужно оставить для отчетности. Но,поскольку все имена моделей были перенесены из списка unprinted_designs, остался только пустой список; исходная версия списка потеряна. Проблему можно решить передачей функции копии списка вместо оригинала. В этом случае все изменения, вносимые функцией в список, будут распространяться только на копию, а оригинал списка остается неизменным." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" } }, "nbformat": 4, "nbformat_minor": 2 }