{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Заголовок придумаем позже\n", "## Деструктуризация при присваивании" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 20 30\n", "10 20 30\n", "[0, 1, 2]\n", "0 1 2\n" ] } ], "source": [ "a = [10, 20, 30]\n", "b = a\n", "x, y, z = a # этим переменным присвоилось содержимое списка\n", "print(x, y, z)\n", "\n", "# Работает ли с кортежем?\n", "c = (10, 20, 30) # с = 10, 20, 30\n", "x, y, z = c\n", "print(x, y, z)\n", "\n", "print(list(range(3)))\n", "x, y, z = range(3) # тоже работает!!!\n", "print(x, y, z) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Т.е. можно присваивать нескольким переменным через запятую перечисления. Надо только, чтобы переменных было столько же, сколько в перечислении.\n", "Это именно то, что происходило в цикле `for key, value in d.items()`. `items()` перечисляет пары (кортежи из двух элементов), получается, что мы `key, value = очередная пара из перечисления`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Очень частый шаблон в коде, обмен значений переменных:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "a = 10\n", "b = 20\n", "# кстати, можно a, b = 10, 20\n", "a, b = 10, 20 # справа кортеж\n", "\n", "a, b = b, a # !! Обмен значений. Справа кортеж, слева деструктуризация\n", "print(a, b)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "too many values to unpack (expected 2)", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m20\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m30\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# ошибка. Слишком много значений для распаковки\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: too many values to unpack (expected 2)" ] } ], "source": [ "x, y = [10, 20, 30] # ошибка. Слишком много значений для распаковки" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Что же делать, если не знаем, например, заранее длину перечисления, и не можем написать нужное количество переменных слева." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 20 [30, 40, 50]\n" ] } ], "source": [ "a = [10, 20, 30, 40, 50]\n", "x, y, *z = a # здесь звездочка перед z означает, что в z присвоится весь остаток списка\n", "print(x, y, z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Неформально. Вообще, звездочка перед переменной означает превращение перечисления внутри переменной в «набор значений через запятую».\n", "\n", "Можно звездочкой перед переменной пользоваться и в других контекстах:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[10, 20, 30, 40, 50]\n", "[10, 20, [30, 40, 50]]\n" ] } ], "source": [ "z = [30, 40, 50]\n", "a = [10, 20, *z] # \n", "print(a)\n", "# сравнить с \n", "b = [10, 20, z]\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Проведем эксперименты, что если использовать не списки" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 20 [30, 40, 50]\n", "0 1 [2, 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "a = (10, 20, 30, 40, 50)\n", "x, y, *z = a # все равно *z присваивается список\n", "print(x, y, z)\n", "\n", "x, y, *z = range(10) # и здесь присвоится список\n", "print(x, y, z)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[10, 20, 30, 10, 20, 30, 0, 1, 2, 3, 4, 'abc', 'hello', 'eee']\n", "{0, 1, 2, 3, 4, 'hello', 'eee', 10, 'abc', 20, 30}\n" ] } ], "source": [ "z1 = [10, 20, 30]\n", "z2 = (10, 20, 30)\n", "z3 = range(5)\n", "z4 = {\"abc\", \"eee\", \"hello\"}\n", "\n", "print([*z1, *z2, *z3, *z4]) # распаковываем, содержимое z как будто пишется через запятую\n", "print({*z1, *z2, *z3, *z4}) # аналогично, создавая множества" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "А со словарями?" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a ['b', 'c', 'd']\n", "('a', 1) [('b', 2), ('c', 3), ('d', 4)]\n" ] } ], "source": [ "d = {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}\n", "x, *y = d # словарь если используется как перечисление, то это перечисление ключей\n", "print(x, y)\n", "\n", "x, *y = d.items() # перечисление пар ключ/значение\n", "print(x, y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Аргументы функций\n", "### Функция print\n", "Что на самом деле означают аргументы print, и какие они могут быть." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 20 abc\n" ] } ], "source": [ "print(10, 20, \"abc\") # три аргумента" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Они распечатались через пробел" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 20 abc\n", "xxx &&&\n" ] } ], "source": [ "print(10, 20, \"abc\")\n", "print(\"xxx\", \"&&&\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Кроме того, что распечатались через пробел, после распечатки вывелся символ перевода строки.\n", "Получается, что print печатает пробелы, переводы строк, хотя мы его не просим об этом явно.\n", "Но этим можно управлять. " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10+20+abc\n", "10~~~20~~~abc\n", "10.20.abc%" ] } ], "source": [ "print(10, 20, \"abc\", sep=\"+\") # указываем, что разделять вывод надо плюсом\n", "print(10, 20, \"abc\", sep=\"~~~\")\n", "print(10, 20, \"abc\", sep=\".\", end=\"%\") # разделяем точкой, в конце процент" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "По умолчанию, `print` считает, что `sep=' '`, `end='\\n'`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[10, 20, 30]\n", "10 20 30\n", "0 10 20 30 40\n" ] } ], "source": [ "z = [10, 20, 30]\n", "print(z) # печать z как список, фактически печатается str(z), потому что нужно превратить\n", " # z в строку\n", "print(*z) # см. ранее. * означает, что элементы как будто написаны через запятую\n", "# эквивалентно print(10, 20, 30)\n", "print(0, *z, 40) # эквивалентно 0, 10, 20, 30, 40" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Функции с произвольным числом аргументов" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f1:\n", "x = 10\n", "y = 20\n", "z = (30, 40, 50)\n", "f2:\n", "x = 10\n", "y = 20\n", "z = ()\n", "f3:\n" ] } ], "source": [ "def f(x, y, *z):\n", " # в этой функции должно быть два аргумента x, y, и еще сколько угодно аргументов,\n", " # они попадут в список z\n", " print(\"x =\", x)\n", " print(\"y =\", y)\n", " print(\"z =\", z)\n", " \n", "\n", "\n", "print(\"f1:\")\n", "f(10, 20, 30, 40, 50) # как будто x, y, *z = [10, 20, 30, 40, 50], только z кортеж\n", "print(\"f2:\")\n", "f(10, 20)\n", "print(\"f3:\")\n", "# f(10) # ошибка, надо указать y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Единственное, такой аргумент функции со звездочкой принято называть `*args`" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, Ilya\n", "argument 1 = 10\n", "argument 2 = abc\n", "argument 3 = [44, 55]\n" ] } ], "source": [ "def g(name, *args):\n", " print(\"Hello,\", name)\n", " i = 1\n", " for a in args:\n", " print(f'argument {i} = {a}')\n", " i = i + 1\n", " \n", "g(\"Ilya\", 10, \"abc\", [44, 55])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Отсутпление*. Как делать цикл с перебором по индексам. Первый способ выше, завели переменную `i`, которую сами изменяем. Второй способ, как в C, Pascal:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 10\n", "1 20\n", "2 30\n" ] } ], "source": [ "a = [10, 20, 30]\n", "for i in range(len(a)):\n", " print(i, a[i]) # индекс i, элемент с этим индексом" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Третий способ, стандартный для python, его рекомендуется использовать:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 10\n", "1 20\n", "2 30\n" ] } ], "source": [ "a = [10, 20, 30]\n", "for i, x in enumerate(a): # enumerate(a) это перечисление пар индекс/элемент\n", " print(i, a[i])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Проверим, что делает `enumerate`:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(0, 10), (1, 20), (2, 30)]\n" ] } ], "source": [ "print(list(enumerate(a)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Именованные аргументы\n", "При вызове функций можно указывать имя аргумента:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Ilya has 10 apples\n", "Maria has 42 apples\n", "Maria has 42 apples\n", "John has 111 apples\n", "100 has Andrew apples\n" ] } ], "source": [ "def f(name, apples):\n", " print(f\"{name} has {apples} apples\")\n", " \n", "f(\"Ilya\", 10)\n", "f(\"Maria\", 42)\n", "f(name=\"Maria\", apples=42) # можно аргументам указать их название\n", "f(apples=111, name=\"John\") # можно менять местами\n", "f(100, apples=\"Andrew\")\n", "# f(apples=111, \"John\") # если вы начали указывать имя аргумента, дальше без имени нельзя" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Это очень полезно для читаемости. Особенно, если аргументы логические. Сравните\n", "`some_function(10, 20, True)` или `some_function(10, 20, printToFile=True)`.\n", "Поэтому при открытии файла я рекомендую писать `open(\"a.txt\", mode=\"r\")` вместо `open(\"a.txt\", \"r\")`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Значение аргументов по(-)умолчанию" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "30\n", "11\n", "11\n", "31\n", "41\n" ] } ], "source": [ "def f(x, y=1):\n", " return x + y\n", "\n", "print(f(10, 20)) # 10 + 20\n", "print(f(x=5, y=6)) # 5 + 6\n", "print(f(y=6, x=5)) # 5 + 6\n", "print(f(30)) # 30 + 1 значение y будет взято как 1, потому что это значение по-умолчанию\n", "print(f(x=40)) # 40 + 1\n", "# print(f(y=40)) # Ошибка, нет умолчания для x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Произвольное количество именованных аргументов функции\n", "Если в определении функции есть `**kwargs`, в словарь `kwargs` попадают все переданные в фунцию\n", "именованные аргументы, которые не удалось присвоить другим аргументам" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "called f\n", "x = 10\n", "y = 20\n", "args = (30, 40, 50)\n", "kwargs = {'z': 30, 't': 40}\n", "called f\n", "x = 10\n", "y = 20\n", "args = ()\n", "kwargs = {'z': 30, 't': 40}\n", "called g\n", "args = (10, 20, 30, 40)\n", "kwargs = {'x': 10, 'y': 20, 'z': 30, 't': 40}\n" ] } ], "source": [ "def f(x, y, *args, **kwargs):\n", " print(\"called f\")\n", " print(\"x =\", x)\n", " print(\"y =\", y)\n", " print(\"args =\", args)\n", " print(\"kwargs =\", kwargs)\n", " \n", "def g(*args, **kwargs):\n", " print(\"called g\")\n", " print(\"args =\", args)\n", " print(\"kwargs =\", kwargs)\n", "\n", "f(10, 20, 30, 40, 50, z=30, t=40) # x=10, y=20, args=(30,40,50) kwargs: {z: 30, t: 40}\n", "f(x=10, y=20, z=30, t=40)\n", "g(10, 20, 30, 40, x=10, y=20, z=30, t=40)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Следующие темы\n", " * Генераторы. Функции yield (вместо return) и выражения-генераторы, аналоги генераторов списков\n", " * lambda-функции. Способ задать функцию в виде выражения. (следующий семестр)\n", " * (!!!) Установим PyCharm (или IDEA) среду разработки." ] }, { "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.7.3" } }, "nbformat": 4, "nbformat_minor": 4 }