├── README.md └── Lectures ├── Lecture_03.ipynb ├── Lecture_10.ipynb ├── Lecture_05.ipynb ├── Lecture_09.ipynb └── Lecture_04.ipynb /README.md: -------------------------------------------------------------------------------- 1 | # Python_1_HSE_2024 2 | Курс "Язык программирования Python" для 1 курса ФКН ВШЭ 2024-2025 год 3 | 4 | #### [Лекция 1: Ввод-вывод, типы данных, PEP-8](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_01.ipynb) 5 | #### [Лекция 2: Ввод-вывод с файла, циклы и условия](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_02.ipynb) 6 | #### [Лекция 3: Множества, словари](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_03.ipynb) 7 | #### [Лекция 4: Функции, рекурсии](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_04.ipynb) 8 | #### [Лекция 5: Collections + itertools, регулярные выражения](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_05.ipynb) 9 | #### Лекция 6: Контрольная работа (без лекции) 10 | #### [Лекция 7: ООП-1](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_07_08.ipynb) 11 | #### [Лекция 8: ООП-2](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_07_08.ipynb) 12 | #### [Лекция 9: Декораторы](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_09.ipynb) 13 | #### [Лекция 10: Итераторы и генераторы](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_10.ipynb) 14 | #### [Лекция 11: Исключения и тестирование](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_11.ipynb) 15 | #### [Лекция 12: Numpy](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_12.ipynb) 16 | #### [Лекция 13: Pandas](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_13.ipynb) 17 | #### [Лекция 14: Matplotlib + seaborn](https://colab.research.google.com/github/Palladain/Python_1_HSE_2024/blob/main/Lectures/Lecture_14.ipynb) 18 | -------------------------------------------------------------------------------- /Lectures/Lecture_03.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "source": [ 20 | "# Python-1, Лекция 3\n", 21 | "\n", 22 | "Лекторы: Петров Тимур, Фролов Андрей" 23 | ], 24 | "metadata": { 25 | "id": "8y5Q2vP2l0X7" 26 | } 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "source": [ 31 | "## Множества" 32 | ], 33 | "metadata": { 34 | "id": "dxa__Uzkl6D9" 35 | } 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "source": [ 40 | "Скорее всего вы знаете, что такое множества, исходя из математики. Множество - это набор уникальных элементов.\n", 41 | "\n", 42 | "Ну и что же в этом уникального, спросите вы? Можно же просто просто хранить список. А вот нет, тогда мы будем сильно проигрывать по времени. Давайте попробуем что-нибудь:" 43 | ], 44 | "metadata": { 45 | "id": "FjWXX3hfmUE-" 46 | } 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": { 52 | "id": "rjDejp-nlvX7" 53 | }, 54 | "outputs": [], 55 | "source": [ 56 | "a = [i for i in range(100000)]\n", 57 | "b = set(a) #создать множество можно из чего угодно" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "source": [ 63 | "%%time\n", 64 | "\n", 65 | "## Вот так можно замерить время\n", 66 | "\n", 67 | "c = 10000\n", 68 | "if c not in a:\n", 69 | " a.append(c)" 70 | ], 71 | "metadata": { 72 | "colab": { 73 | "base_uri": "https://localhost:8080/" 74 | }, 75 | "id": "crOsAtctoc_P", 76 | "outputId": "47e33982-8a31-40ea-a2f9-e02308c31a1d" 77 | }, 78 | "execution_count": null, 79 | "outputs": [ 80 | { 81 | "output_type": "stream", 82 | "name": "stdout", 83 | "text": [ 84 | "CPU times: user 184 µs, sys: 0 ns, total: 184 µs\n", 85 | "Wall time: 189 µs\n" 86 | ] 87 | } 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "source": [ 93 | "%%time\n", 94 | "\n", 95 | "## Вот так можно замерить время\n", 96 | "\n", 97 | "c = 10000\n", 98 | "if c not in b:\n", 99 | " b.add(c)" 100 | ], 101 | "metadata": { 102 | "colab": { 103 | "base_uri": "https://localhost:8080/" 104 | }, 105 | "id": "5wUdkU3popLs", 106 | "outputId": "ba959e17-3794-45de-e629-1b101a495132" 107 | }, 108 | "execution_count": null, 109 | "outputs": [ 110 | { 111 | "output_type": "stream", 112 | "name": "stdout", 113 | "text": [ 114 | "CPU times: user 6 µs, sys: 1 µs, total: 7 µs\n", 115 | "Wall time: 11.4 µs\n" 116 | ] 117 | } 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "source": [ 123 | "Опа и пожалуйста, экономия времени! Как это получается? На самом деле ответ кроется в том, как хранит элементы множество и список (список хранит просто в раличных ячейках памяти элементы, множество же занимается хэшированием, но про это вам расскажут на курсе алгоритмов)\n", 124 | "\n", 125 | "А наша задача, в первую очередь, это вообще понять, как с ними работать. Итак, поехали:" 126 | ], 127 | "metadata": { 128 | "id": "MSK31w6uo_au" 129 | } 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "source": [ 134 | "* s.add(elem) - добавить элемент во множество (если элемент уже есть, то ничего не изменится)\n", 135 | "\n", 136 | "* clear() - очистить множество\n", 137 | "\n", 138 | "* copy() - скопировать множество\n", 139 | "\n", 140 | "* s.discard(elem) / s.remove(elem) / s.pop() - разные методы удаления (первое - не ругнется, если попробовать убрать элемент не из множества, второй - ругнется, третий - просто вытаскивает рандомный элемент и возвращает его)\n", 141 | "\n", 142 | "* difference / difference_update() / - - разность\n", 143 | "\n", 144 | "* union() / | - объединение множеств\n", 145 | "\n", 146 | "* intersection() / & - пересечение множеств\n", 147 | "\n", 148 | "* issubset() / isdisjoint() / issuperset() - проверка на подмножество, наличие пересечений и проверка на супермножество (один находится в другом)\n", 149 | "\n", 150 | "* symmetric_difference / ^ - симметричная разность\n", 151 | "\n", 152 | "* len(s) - узнать число элементов во множестве\n", 153 | "\n", 154 | "* ==, <=, >= - проверки на равенство (поэлементно), является ли одно множество под(над)множеством другого\n", 155 | "\n", 156 | "Как можно заметить, можно использовать и операторы)" 157 | ], 158 | "metadata": { 159 | "id": "Rey23DlopqgS" 160 | } 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "source": [ 165 | "![](https://i.pinimg.com/originals/d3/59/3a/d3593ae3a7dbdccf9513d3aa5b608230.png)" 166 | ], 167 | "metadata": { 168 | "id": "Vy29pQMB-gCw" 169 | } 170 | }, 171 | { 172 | "cell_type": "code", 173 | "source": [ 174 | "a = {1,2,3,5} #а еще множества можно объявлять вот так\n", 175 | "b = {4,5,6}\n", 176 | "\n", 177 | "print(a.union(b), a | b)\n", 178 | "print(a.intersection(b), a & b)\n", 179 | "print(a.difference(b), a - b)\n", 180 | "print(a.symmetric_difference(b), a ^ b)" 181 | ], 182 | "metadata": { 183 | "colab": { 184 | "base_uri": "https://localhost:8080/" 185 | }, 186 | "id": "5j_PPmBLsyRM", 187 | "outputId": "2668a0ad-bccb-469a-a780-c044fb798f3b" 188 | }, 189 | "execution_count": null, 190 | "outputs": [ 191 | { 192 | "output_type": "stream", 193 | "name": "stdout", 194 | "text": [ 195 | "{1, 2, 3, 4, 5, 6} {1, 2, 3, 4, 5, 6}\n", 196 | "{5} {5}\n", 197 | "{1, 2, 3} {1, 2, 3}\n", 198 | "{1, 2, 3, 4, 6} {1, 2, 3, 4, 6}\n" 199 | ] 200 | } 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "source": [ 206 | "Есть такая штука, как difference_update. Как думаете, в чем разница?" 207 | ], 208 | "metadata": { 209 | "id": "cnnmDYxPtEiI" 210 | } 211 | }, 212 | { 213 | "cell_type": "code", 214 | "source": [ 215 | "print(a.difference(b), a)\n", 216 | "print(a.difference_update(b), a)" 217 | ], 218 | "metadata": { 219 | "colab": { 220 | "base_uri": "https://localhost:8080/" 221 | }, 222 | "id": "cAd-BBm2tKPj", 223 | "outputId": "60e0640a-2590-4dba-f6be-56d64848d977" 224 | }, 225 | "execution_count": null, 226 | "outputs": [ 227 | { 228 | "output_type": "stream", 229 | "name": "stdout", 230 | "text": [ 231 | "{1, 2, 3} {1, 2, 3, 5}\n", 232 | "None {1, 2, 3}\n" 233 | ] 234 | } 235 | ] 236 | }, 237 | { 238 | "cell_type": "markdown", 239 | "source": [ 240 | "Поиграемся с удалениями элементов:" 241 | ], 242 | "metadata": { 243 | "id": "G5wQ-6eNtULD" 244 | } 245 | }, 246 | { 247 | "cell_type": "code", 248 | "source": [ 249 | "a.discard(5)\n", 250 | "a.discard(5)\n", 251 | "a.remove(3)\n", 252 | "a.remove(3)" 253 | ], 254 | "metadata": { 255 | "colab": { 256 | "base_uri": "https://localhost:8080/", 257 | "height": 222 258 | }, 259 | "id": "upsQVq4ltTuw", 260 | "outputId": "1f29d9be-0be1-4d7b-cf74-671bdaea85c1" 261 | }, 262 | "execution_count": null, 263 | "outputs": [ 264 | { 265 | "output_type": "error", 266 | "ename": "KeyError", 267 | "evalue": "ignored", 268 | "traceback": [ 269 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 270 | "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", 271 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdiscard\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremove\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mremove\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 272 | "\u001b[0;31mKeyError\u001b[0m: 3" 273 | ] 274 | } 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "source": [ 280 | "while a:\n", 281 | " print(a.pop())" 282 | ], 283 | "metadata": { 284 | "colab": { 285 | "base_uri": "https://localhost:8080/" 286 | }, 287 | "id": "0ion_mKAtfuk", 288 | "outputId": "1214623a-30a5-4674-f01b-f781fb41dd7f" 289 | }, 290 | "execution_count": null, 291 | "outputs": [ 292 | { 293 | "output_type": "stream", 294 | "name": "stdout", 295 | "text": [ 296 | "1\n", 297 | "2\n" 298 | ] 299 | } 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "source": [ 305 | "a.add([15,20]) #упс, а почему так нельзя?" 306 | ], 307 | "metadata": { 308 | "colab": { 309 | "base_uri": "https://localhost:8080/", 310 | "height": 185 311 | }, 312 | "id": "0uI-W9YqtjnX", 313 | "outputId": "7211a1d6-b48d-40ea-e664-a64f7688239e" 314 | }, 315 | "execution_count": null, 316 | "outputs": [ 317 | { 318 | "output_type": "error", 319 | "ename": "TypeError", 320 | "evalue": "ignored", 321 | "traceback": [ 322 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 323 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 324 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m15\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m20\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 325 | "\u001b[0;31mTypeError\u001b[0m: unhashable type: 'list'" 326 | ] 327 | } 328 | ] 329 | }, 330 | { 331 | "cell_type": "markdown", 332 | "source": [ 333 | "Как раз здесь нам значимо, что есть mutable и immutable типы данных. Как мы упоминали на первой лекции, отличие кортежа от списка в том, что одно - изменяемое, а другое - нет\n", 334 | "\n", 335 | "Это играет большую роль в случае с хэшированием. Изменяемые объекты не хешируемы! А это значит, что их нельзя хранить в множествах и словарях (в словарях - в качестве ключей). Почему? А потому что принцип их работы зависит от того условия, что объекты нельзя изменить (только таким образом это работает быстро и так, как надо).\n", 336 | "\n", 337 | "Ну хорошо, как же тогда быть? Использовать кортеж!" 338 | ], 339 | "metadata": { 340 | "id": "0gZegHentq-y" 341 | } 342 | }, 343 | { 344 | "cell_type": "code", 345 | "source": [ 346 | "a.add((15, 20))\n", 347 | "a" 348 | ], 349 | "metadata": { 350 | "colab": { 351 | "base_uri": "https://localhost:8080/" 352 | }, 353 | "id": "CpLkx6M2uQjB", 354 | "outputId": "70b24906-aa00-47bd-d67e-34415813bb69" 355 | }, 356 | "execution_count": null, 357 | "outputs": [ 358 | { 359 | "output_type": "execute_result", 360 | "data": { 361 | "text/plain": [ 362 | "{(15, 20)}" 363 | ] 364 | }, 365 | "metadata": {}, 366 | "execution_count": 29 367 | } 368 | ] 369 | }, 370 | { 371 | "cell_type": "markdown", 372 | "source": [ 373 | "Славно! А какие типы изменяемые, а какие нет? Давайте поделим:\n", 374 | "\n", 375 | "1. Изменяемые:\n", 376 | "\n", 377 | "* Списки\n", 378 | "\n", 379 | "* Множества\n", 380 | "\n", 381 | "* Словари\n", 382 | "\n", 383 | "2. Неизменяемые:\n", 384 | "\n", 385 | "* Строки\n", 386 | "\n", 387 | "* Кортежи\n", 388 | "\n", 389 | "* Числа\n", 390 | "\n", 391 | "* Логические значения" 392 | ], 393 | "metadata": { 394 | "id": "k1TktXf-uUh0" 395 | } 396 | }, 397 | { 398 | "cell_type": "markdown", 399 | "source": [ 400 | "Так что в целом не так все и плохо!" 401 | ], 402 | "metadata": { 403 | "id": "dKaa08oOu1Em" 404 | } 405 | }, 406 | { 407 | "cell_type": "markdown", 408 | "source": [ 409 | "### FrozenSet" 410 | ], 411 | "metadata": { 412 | "id": "DrBP9jP0mC9h" 413 | } 414 | }, 415 | { 416 | "cell_type": "markdown", 417 | "source": [ 418 | "А теперь то же самое, но только сделаем так, чтобы set был неизменяемым (иногда это нужно)" 419 | ], 420 | "metadata": { 421 | "id": "gq5UybUOmUlA" 422 | } 423 | }, 424 | { 425 | "cell_type": "code", 426 | "source": [ 427 | "a.add(frozenset({15, 20})) #жесть, так можно!\n", 428 | "a" 429 | ], 430 | "metadata": { 431 | "colab": { 432 | "base_uri": "https://localhost:8080/" 433 | }, 434 | "id": "C0yZOpxZmU8C", 435 | "outputId": "56d4bac9-cea7-412d-d1d3-c4936e30697d" 436 | }, 437 | "execution_count": null, 438 | "outputs": [ 439 | { 440 | "output_type": "execute_result", 441 | "data": { 442 | "text/plain": [ 443 | "{(15, 20), frozenset({15, 20})}" 444 | ] 445 | }, 446 | "metadata": {}, 447 | "execution_count": 30 448 | } 449 | ] 450 | }, 451 | { 452 | "cell_type": "markdown", 453 | "source": [ 454 | "Подерживает все те же операции, что и set, но которые его не меняют (нельзя изменить frozenset, на то он и нужен). Вы спросите: круто, а зачем? Ответ прост: использовать там, где нужны именно immutable объекты, например, в словарях!" 455 | ], 456 | "metadata": { 457 | "id": "PA65csanvQxC" 458 | } 459 | }, 460 | { 461 | "cell_type": "markdown", 462 | "source": [ 463 | "## Словари" 464 | ], 465 | "metadata": { 466 | "id": "8Om1iSgAl76q" 467 | } 468 | }, 469 | { 470 | "cell_type": "markdown", 471 | "source": [ 472 | "Ну хорошо, у нас есть множества, давайте пойдем чуть дальше. Допустим, что мы хотим иметь не просто множество, а еще уметь и считать, сколько раз тот или иной элемент встретился!\n", 473 | "\n", 474 | "Можно ответить про Counter, конечно, но про это мы позже поговорим тоже, а сейчас давайте про уже встроенные методы. То есть что бы нам хотелось? Хранить некоторую пару \"value\" - \"значение\" (в нашем случае сколько раз встретилось)\n", 475 | "\n", 476 | "Вот для этого и подходят словари! (почему словарь - аналогия с переводом)\n", 477 | "Давайте создавать!" 478 | ], 479 | "metadata": { 480 | "id": "j0qa_qhjl9Mb" 481 | } 482 | }, 483 | { 484 | "cell_type": "code", 485 | "source": [ 486 | "d = {1:5, 2:6, 3:7} #явно объявить можно вот таким образом, так же существует просто вызов dict()\n", 487 | "d" 488 | ], 489 | "metadata": { 490 | "colab": { 491 | "base_uri": "https://localhost:8080/" 492 | }, 493 | "id": "DnI9IM0eDNZS", 494 | "outputId": "1e0db169-1fc6-4f9c-edc8-aa7140681f6b" 495 | }, 496 | "execution_count": null, 497 | "outputs": [ 498 | { 499 | "output_type": "execute_result", 500 | "data": { 501 | "text/plain": [ 502 | "{1: 5, 2: 6, 3: 7}" 503 | ] 504 | }, 505 | "metadata": {}, 506 | "execution_count": 31 507 | } 508 | ] 509 | }, 510 | { 511 | "cell_type": "markdown", 512 | "source": [ 513 | "Все, что находится слева (до двоеточия) - это ключи (или же keys), все, что после - это значения (или же values)" 514 | ], 515 | "metadata": { 516 | "id": "T1v9kuA0DeJx" 517 | } 518 | }, 519 | { 520 | "cell_type": "code", 521 | "source": [ 522 | "print(d.keys(), d.values(), d.items())" 523 | ], 524 | "metadata": { 525 | "colab": { 526 | "base_uri": "https://localhost:8080/" 527 | }, 528 | "id": "GveiZeqgDmbk", 529 | "outputId": "7c295883-40c4-4990-cab5-4ba8a615b46e" 530 | }, 531 | "execution_count": null, 532 | "outputs": [ 533 | { 534 | "output_type": "stream", 535 | "name": "stdout", 536 | "text": [ 537 | "dict_keys([1, 2, 3]) dict_values([5, 6, 7]) dict_items([(1, 5), (2, 6), (3, 7)])\n" 538 | ] 539 | } 540 | ] 541 | }, 542 | { 543 | "cell_type": "markdown", 544 | "source": [ 545 | "Как обращаться по ключу? Абсолютно точно также, как и в списке (можно считать, будто это индексы):" 546 | ], 547 | "metadata": { 548 | "id": "qXD2B436LE38" 549 | } 550 | }, 551 | { 552 | "cell_type": "code", 553 | "source": [ 554 | "d[3]" 555 | ], 556 | "metadata": { 557 | "colab": { 558 | "base_uri": "https://localhost:8080/" 559 | }, 560 | "id": "cFTSDgjwLMZ3", 561 | "outputId": "92c4dc15-84e7-49a4-a1f6-426a190c42fe" 562 | }, 563 | "execution_count": null, 564 | "outputs": [ 565 | { 566 | "output_type": "execute_result", 567 | "data": { 568 | "text/plain": [ 569 | "7" 570 | ] 571 | }, 572 | "metadata": {}, 573 | "execution_count": 39 574 | } 575 | ] 576 | }, 577 | { 578 | "cell_type": "markdown", 579 | "source": [ 580 | "Но потом мы попробовали вот так:" 581 | ], 582 | "metadata": { 583 | "id": "hEShj_o2LP0b" 584 | } 585 | }, 586 | { 587 | "cell_type": "code", 588 | "source": [ 589 | "d[4]" 590 | ], 591 | "metadata": { 592 | "colab": { 593 | "base_uri": "https://localhost:8080/", 594 | "height": 185 595 | }, 596 | "id": "k1W5X1fCLRw8", 597 | "outputId": "f72f0462-7c62-4f58-fee2-b20dd4e08ca9" 598 | }, 599 | "execution_count": null, 600 | "outputs": [ 601 | { 602 | "output_type": "error", 603 | "ename": "KeyError", 604 | "evalue": "ignored", 605 | "traceback": [ 606 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 607 | "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", 608 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 609 | "\u001b[0;31mKeyError\u001b[0m: 4" 610 | ] 611 | } 612 | ] 613 | }, 614 | { 615 | "cell_type": "markdown", 616 | "source": [ 617 | "И получили ошибку, что же делать? Для этого есть более \"безопасный\" вариант: get()" 618 | ], 619 | "metadata": { 620 | "id": "BwawQG1nLTIw" 621 | } 622 | }, 623 | { 624 | "cell_type": "code", 625 | "source": [ 626 | "print(d.get(4)) #он выведет ничего, так как ничего и нет" 627 | ], 628 | "metadata": { 629 | "colab": { 630 | "base_uri": "https://localhost:8080/" 631 | }, 632 | "id": "jYNw4kt5LZWu", 633 | "outputId": "c4be3751-6f82-4303-8dab-6e9e17634a54" 634 | }, 635 | "execution_count": null, 636 | "outputs": [ 637 | { 638 | "output_type": "stream", 639 | "name": "stdout", 640 | "text": [ 641 | "None\n" 642 | ] 643 | } 644 | ] 645 | }, 646 | { 647 | "cell_type": "markdown", 648 | "source": [ 649 | "Что можео быть в качестве значения? На самом деле что угодно!\n", 650 | "\n", 651 | "Что может быть в качестве ключей? Только НЕизменяемые объекты" 652 | ], 653 | "metadata": { 654 | "id": "H4jgBDeoLsAT" 655 | } 656 | }, 657 | { 658 | "cell_type": "code", 659 | "source": [ 660 | "a = {\"abc\": set([1,2,3])}\n", 661 | "a" 662 | ], 663 | "metadata": { 664 | "colab": { 665 | "base_uri": "https://localhost:8080/" 666 | }, 667 | "id": "eNUFhYv1LxxI", 668 | "outputId": "b8a2e327-3cc7-47f1-d6c3-5ddebe50f058" 669 | }, 670 | "execution_count": null, 671 | "outputs": [ 672 | { 673 | "output_type": "execute_result", 674 | "data": { 675 | "text/plain": [ 676 | "{'abc': {1, 2, 3}}" 677 | ] 678 | }, 679 | "metadata": {}, 680 | "execution_count": 44 681 | } 682 | ] 683 | }, 684 | { 685 | "cell_type": "markdown", 686 | "source": [ 687 | "Ну хорошо, создавать от руки мы умеем. А как теперь добавлять/удалять и так далее, что мы вообще можем делать со словарем?\n", 688 | "\n" 689 | ], 690 | "metadata": { 691 | "id": "NHUllYNKL54z" 692 | } 693 | }, 694 | { 695 | "cell_type": "code", 696 | "source": [ 697 | "d[4] = 100\n", 698 | "d[1] += 1\n", 699 | "print(d)" 700 | ], 701 | "metadata": { 702 | "colab": { 703 | "base_uri": "https://localhost:8080/" 704 | }, 705 | "id": "YcxE52x5MRQX", 706 | "outputId": "12959f6d-ea55-40f7-bd9d-77c3825b2e62" 707 | }, 708 | "execution_count": null, 709 | "outputs": [ 710 | { 711 | "output_type": "stream", 712 | "name": "stdout", 713 | "text": [ 714 | "{1: 6, 2: 6, 3: 7, 4: 100}\n" 715 | ] 716 | } 717 | ] 718 | }, 719 | { 720 | "cell_type": "markdown", 721 | "source": [ 722 | "* d.pop(elem) - удалить ключ и вернуть по нему значение\n", 723 | "\n", 724 | "* d.popitem() - удали рандомный элемент и верни ключ-значение удаленного\n", 725 | "\n", 726 | "* d.clear() - очистить словарь\n", 727 | "\n", 728 | "* len(d) - число элементов\n", 729 | "\n", 730 | "* d.setdefault(key, value) - поставь значение по ключу, если его нет, то поставь value" 731 | ], 732 | "metadata": { 733 | "id": "0WLRBamyRCI6" 734 | } 735 | }, 736 | { 737 | "cell_type": "code", 738 | "source": [ 739 | "d.pop(4)\n", 740 | "print(d.popitem())\n", 741 | "print(len(d))\n", 742 | "print(d.setdefault(4, 10000))\n", 743 | "print(d)" 744 | ], 745 | "metadata": { 746 | "colab": { 747 | "base_uri": "https://localhost:8080/" 748 | }, 749 | "id": "UsVyTCb7RgaE", 750 | "outputId": "3b9dddec-2a4a-4440-94e0-c9b4350197b7" 751 | }, 752 | "execution_count": null, 753 | "outputs": [ 754 | { 755 | "output_type": "stream", 756 | "name": "stdout", 757 | "text": [ 758 | "(3, 7)\n", 759 | "2\n", 760 | "10000\n" 761 | ] 762 | } 763 | ] 764 | }, 765 | { 766 | "cell_type": "code", 767 | "source": [ 768 | "d.clear()\n", 769 | "d" 770 | ], 771 | "metadata": { 772 | "colab": { 773 | "base_uri": "https://localhost:8080/" 774 | }, 775 | "id": "Di3vId6_R7vq", 776 | "outputId": "6b4a2871-5460-4716-8847-bcc8c48c5fe6" 777 | }, 778 | "execution_count": null, 779 | "outputs": [ 780 | { 781 | "output_type": "execute_result", 782 | "data": { 783 | "text/plain": [ 784 | "{}" 785 | ] 786 | }, 787 | "metadata": {}, 788 | "execution_count": 50 789 | } 790 | ] 791 | }, 792 | { 793 | "cell_type": "markdown", 794 | "source": [ 795 | "Ну хорошо, вроде как понятно, как работать со словарем. Но, допустим, к нам приходит отдел маркетинга и такой: хотим автоматизировать подсчет переходов по рекламе. У нас есть ЭКСЕЛЬКА, в которой есть список с рекламными компаниями и текущие значения, которые посчитали, а как добавить эту информацию и дальше считать по-новому?\n", 796 | "\n", 797 | "Мы призадумались..." 798 | ], 799 | "metadata": { 800 | "id": "wRBJSfX2L9aq" 801 | } 802 | }, 803 | { 804 | "cell_type": "code", 805 | "source": [ 806 | "c = [\"c_1\", \"c_2\", \"c_3\", \"c_4\", \"c_5\"]\n", 807 | "n = [1, 2, 3, 4, 100]\n", 808 | "\n", 809 | "## Что-то надо сделать" 810 | ], 811 | "metadata": { 812 | "id": "_P3AYUKDMbnK" 813 | }, 814 | "execution_count": null, 815 | "outputs": [] 816 | }, 817 | { 818 | "cell_type": "markdown", 819 | "source": [ 820 | "Можно было бы сделать вот так:" 821 | ], 822 | "metadata": { 823 | "id": "_ZpTnE8IMkX5" 824 | } 825 | }, 826 | { 827 | "cell_type": "code", 828 | "source": [ 829 | "d = dict()\n", 830 | "for i in range(len(c)):\n", 831 | " d[c[i]] = n[i]\n", 832 | "print(d)" 833 | ], 834 | "metadata": { 835 | "colab": { 836 | "base_uri": "https://localhost:8080/" 837 | }, 838 | "id": "DSOPdGFnMm8d", 839 | "outputId": "375040c4-cf59-4301-bb04-25fafaaaaa2f" 840 | }, 841 | "execution_count": null, 842 | "outputs": [ 843 | { 844 | "output_type": "stream", 845 | "name": "stdout", 846 | "text": [ 847 | "{'c_1': 1, 'c_2': 2, 'c_3': 3, 'c_4': 4, 'c_5': 100}\n" 848 | ] 849 | } 850 | ] 851 | }, 852 | { 853 | "cell_type": "markdown", 854 | "source": [ 855 | "Но можно ли не использовать циклы и сделать это более кратко?...\n", 856 | "\n", 857 | "А вот можно!" 858 | ], 859 | "metadata": { 860 | "id": "ta9xrCYHMuYt" 861 | } 862 | }, 863 | { 864 | "cell_type": "code", 865 | "source": [ 866 | "d = dict(zip(c, n))\n", 867 | "print(d)" 868 | ], 869 | "metadata": { 870 | "colab": { 871 | "base_uri": "https://localhost:8080/" 872 | }, 873 | "id": "6o4BKShbM1Tj", 874 | "outputId": "f9e9434d-66ce-4106-a819-163ac14326ea" 875 | }, 876 | "execution_count": null, 877 | "outputs": [ 878 | { 879 | "output_type": "stream", 880 | "name": "stdout", 881 | "text": [ 882 | "{'c_1': 1, 'c_2': 2, 'c_3': 3, 'c_4': 4, 'c_5': 100}\n" 883 | ] 884 | } 885 | ] 886 | }, 887 | { 888 | "cell_type": "markdown", 889 | "source": [ 890 | "Вау! А что случилось?\n", 891 | "\n", 892 | "Функция zip позволяет объединить данные в кортежи (аналогия с застежкой)" 893 | ], 894 | "metadata": { 895 | "id": "y_F_m87KM5yY" 896 | } 897 | }, 898 | { 899 | "cell_type": "code", 900 | "source": [ 901 | "list(zip(c, n)) ## приходится делать list, потому что zip создает итератор (но про это позже)" 902 | ], 903 | "metadata": { 904 | "colab": { 905 | "base_uri": "https://localhost:8080/" 906 | }, 907 | "id": "aoBvpIsFNK5r", 908 | "outputId": "77c8b0f3-fc48-4836-837c-3a990d6c3911" 909 | }, 910 | "execution_count": null, 911 | "outputs": [ 912 | { 913 | "output_type": "execute_result", 914 | "data": { 915 | "text/plain": [ 916 | "[('c_1', 1), ('c_2', 2), ('c_3', 3), ('c_4', 4), ('c_5', 100)]" 917 | ] 918 | }, 919 | "metadata": {}, 920 | "execution_count": 9 921 | } 922 | ] 923 | }, 924 | { 925 | "cell_type": "markdown", 926 | "source": [ 927 | "## DefaultDict" 928 | ], 929 | "metadata": { 930 | "id": "CtI2AsPzmFW1" 931 | } 932 | }, 933 | { 934 | "cell_type": "markdown", 935 | "source": [ 936 | "Итак, в чем самая главная проблема словарей? Ну банально в том, что нужно каждый раз проверять, а есть ли ключ в словаре, а то если его нет, то наш скрипт, само собой, упадет. А что, если бы мы прям с самого начал уже задавали какое-то базовое (дефолтное) значение? Вот для этого существует такая вещь, как defaultdict, которая лежит в отдельном модуле collections" 937 | ], 938 | "metadata": { 939 | "id": "DCFIpSSdmVX8" 940 | } 941 | }, 942 | { 943 | "cell_type": "markdown", 944 | "source": [ 945 | "Итак, сегодня мы в первый раз поговорим про библиотеки и модули. Что это такое?\n", 946 | "\n", 947 | "По сути библиотека - это набор дополнительных функций, которые позволяют вам использовать их с помощью вызова всего лишь одной строчки кода!" 948 | ], 949 | "metadata": { 950 | "id": "BMV6oSynJ0UJ" 951 | } 952 | }, 953 | { 954 | "cell_type": "code", 955 | "source": [ 956 | "import math # когда делаем вот так, то можно вызывать функции через название модуля.функция\n", 957 | "from numpy import * # импортим все и можем обращаться напрямую\n", 958 | "import matplotlib.pyplot as plt # даем сокращение названию модулю" 959 | ], 960 | "metadata": { 961 | "id": "MFF8mF_5J2K1" 962 | }, 963 | "execution_count": null, 964 | "outputs": [] 965 | }, 966 | { 967 | "cell_type": "markdown", 968 | "source": [ 969 | "Давайте попробуем импортировать [collections](https://docs.python.org/3/library/collections.html):" 970 | ], 971 | "metadata": { 972 | "id": "5uU3MPsjKCJj" 973 | } 974 | }, 975 | { 976 | "cell_type": "code", 977 | "source": [ 978 | "from collections import defaultdict\n", 979 | "\n", 980 | "d = defaultdict(int)\n", 981 | "print(d[10])" 982 | ], 983 | "metadata": { 984 | "colab": { 985 | "base_uri": "https://localhost:8080/" 986 | }, 987 | "id": "FqBuJwTSKTE3", 988 | "outputId": "7c762c43-bac6-4aa2-9405-5f29325e6477" 989 | }, 990 | "execution_count": 2, 991 | "outputs": [ 992 | { 993 | "output_type": "stream", 994 | "name": "stdout", 995 | "text": [ 996 | "0\n" 997 | ] 998 | } 999 | ] 1000 | }, 1001 | { 1002 | "cell_type": "markdown", 1003 | "source": [ 1004 | "Опа, мы вызвали значение от несуществующего ключа и вдруг ничего не выдало ошибку. Как же так? Давайте разбираться:\n", 1005 | "\n", 1006 | "* defaultdict(factory) - создай словарь вот с такой функцией по дефолту\n", 1007 | "\n", 1008 | "В данном случае мы вызвали int, который при вызове сам по себе дает 0:" 1009 | ], 1010 | "metadata": { 1011 | "id": "UxRdapueKyDt" 1012 | } 1013 | }, 1014 | { 1015 | "cell_type": "code", 1016 | "source": [ 1017 | "int()" 1018 | ], 1019 | "metadata": { 1020 | "colab": { 1021 | "base_uri": "https://localhost:8080/" 1022 | }, 1023 | "id": "ntaccAySLNip", 1024 | "outputId": "2be9ee33-0d10-4839-951f-55feeddbfdf7" 1025 | }, 1026 | "execution_count": null, 1027 | "outputs": [ 1028 | { 1029 | "output_type": "execute_result", 1030 | "data": { 1031 | "text/plain": [ 1032 | "0" 1033 | ] 1034 | }, 1035 | "metadata": {}, 1036 | "execution_count": 3 1037 | } 1038 | ] 1039 | }, 1040 | { 1041 | "cell_type": "markdown", 1042 | "source": [ 1043 | "Можно использовать несколько других вариантов, например, string, list, или в целом любую функцию (когда будем говорить про функции мы ощутим полную мощь данного инструмента)\n", 1044 | "\n", 1045 | "Давайте еще вот такой пример:" 1046 | ], 1047 | "metadata": { 1048 | "id": "-HfqQWcVLOuE" 1049 | } 1050 | }, 1051 | { 1052 | "cell_type": "code", 1053 | "source": [ 1054 | "s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]\n", 1055 | "d = defaultdict(list)\n", 1056 | "for k, v in s:\n", 1057 | " d[k].append(v)\n", 1058 | "\n", 1059 | "d.items()" 1060 | ], 1061 | "metadata": { 1062 | "colab": { 1063 | "base_uri": "https://localhost:8080/" 1064 | }, 1065 | "id": "vJcHybYrLaCz", 1066 | "outputId": "1c2c7914-e995-4730-dfd3-cb9ceeefcf71" 1067 | }, 1068 | "execution_count": null, 1069 | "outputs": [ 1070 | { 1071 | "output_type": "execute_result", 1072 | "data": { 1073 | "text/plain": [ 1074 | "dict_items([('yellow', [1, 3]), ('blue', [2, 4]), ('red', [1])])" 1075 | ] 1076 | }, 1077 | "metadata": {}, 1078 | "execution_count": 4 1079 | } 1080 | ] 1081 | }, 1082 | { 1083 | "cell_type": "markdown", 1084 | "source": [ 1085 | "Что здесь случилось? Мы задали в качестве изначальной функции list(). Что это значит? По дефолту создается пустой лист, внутри которого мы далее делаем append, то есть таким образом собираем все значения" 1086 | ], 1087 | "metadata": { 1088 | "id": "3gaw1khnLiKL" 1089 | } 1090 | }, 1091 | { 1092 | "cell_type": "markdown", 1093 | "source": [ 1094 | "## Животное дня" 1095 | ], 1096 | "metadata": { 1097 | "id": "bRBavKLsJbw-" 1098 | } 1099 | }, 1100 | { 1101 | "cell_type": "markdown", 1102 | "source": [ 1103 | "![](https://animaljournal.ru/articles/wild/primati/koshachiy_lemur/detenish_lemura1.jpg)" 1104 | ], 1105 | "metadata": { 1106 | "id": "Po6ms7FNJ3v4" 1107 | } 1108 | }, 1109 | { 1110 | "cell_type": "markdown", 1111 | "source": [ 1112 | "Это кошачий лемур. Их все так или иначе видели (по крайней мере вот в таком виде):" 1113 | ], 1114 | "metadata": { 1115 | "id": "kk6rs4ERJ5YS" 1116 | } 1117 | }, 1118 | { 1119 | "cell_type": "markdown", 1120 | "source": [ 1121 | "![](https://www.meme-arsenal.com/memes/819abc6f23381d803a640e91092ea4a1.jpg)" 1122 | ], 1123 | "metadata": { 1124 | "id": "OSsmBDTgKEce" 1125 | } 1126 | }, 1127 | { 1128 | "cell_type": "markdown", 1129 | "source": [ 1130 | "На Мадагаскаре (где они и обитают) их зовут маки! По размерам как кошка (действительно), при этом хвост может весить примерно половину от всего веса лемура, и это неудивительно - хвост лемура играют важную роль в его жизни.\n", 1131 | "\n", 1132 | "Помимо самых понятных прикладных функций (с помощью хвоста лемуры удерживают равновесие, будучи на ветках, а также балансируют с его помощью при прыжке), хвост также выполняет социальные функции\n", 1133 | "\n", 1134 | "С его помощью он более заметен своим сородичам, а также показывают, кто здесь главный (через секрет, которым они этот самый хвост обмазывают)\n", 1135 | "\n", 1136 | "А еще посмотрите, как они сидят)" 1137 | ], 1138 | "metadata": { 1139 | "id": "GLj3Arp-KMQr" 1140 | } 1141 | }, 1142 | { 1143 | "cell_type": "markdown", 1144 | "source": [ 1145 | "![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/93/Ring.tailed.lemur.situp.arp.jpg/1024px-Ring.tailed.lemur.situp.arp.jpg)" 1146 | ], 1147 | "metadata": { 1148 | "id": "2yPxHCkDLaEC" 1149 | } 1150 | }, 1151 | { 1152 | "cell_type": "markdown", 1153 | "source": [ 1154 | "Лемуры - социальные животные, живут группой по 30 особей (причем у них матриархат), причем у них максимально яркая социальность: будучи одни, они просто с ума сходят, поэтому нормально изучить их когнитивные способности достаточно сложно" 1155 | ], 1156 | "metadata": { 1157 | "id": "Kh7Sr2VHLptu" 1158 | } 1159 | } 1160 | ] 1161 | } -------------------------------------------------------------------------------- /Lectures/Lecture_10.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "source": [ 20 | "# Python-1, Лекция 10\n", 21 | "\n", 22 | "Лектор: Петров Тимур, Фролов Андрей" 23 | ], 24 | "metadata": { 25 | "id": "gul1ajImwD0W" 26 | } 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "source": [ 31 | "## Итераторы и итерируемое" 32 | ], 33 | "metadata": { 34 | "id": "kVC6gn4agVTR" 35 | } 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "source": [ 40 | "Начнем с базы. Внутри Python есть две вещи: iterator и iterable. В чем разница и что это такое?\n", 41 | "\n", 42 | "Iterable - это объект, над которым можно проводить итерацию. Что такое итерация? По сути это процесс перебора элементов (например, строки/множества/списки - это итерируемые объекты)\n", 43 | "\n", 44 | "А что же тогда такое итератор? А это у нас объект, который занимается процессом итерации. По определению это класс, у которого реализованы методы next и iter (для iterable объекта реализуется только сам iter)\n" 45 | ], 46 | "metadata": { 47 | "id": "4KkW_VMkgaQf" 48 | } 49 | }, 50 | { 51 | "cell_type": "code", 52 | "source": [ 53 | "c = [1, 2, 3, 4]\n", 54 | "for i in c: # что здесь происходит? Неявно вызывается iter(c)\n", 55 | "# Причем iter() работает для так называемых контейнеров (для всех, у кого есть __getitem__ или __iter__)\n", 56 | " print(i)" 57 | ], 58 | "metadata": { 59 | "colab": { 60 | "base_uri": "https://localhost:8080/" 61 | }, 62 | "id": "CX6_-IaCiAsZ", 63 | "outputId": "aa57b1fa-a08a-4380-98bd-3aff95093cda" 64 | }, 65 | "execution_count": null, 66 | "outputs": [ 67 | { 68 | "output_type": "stream", 69 | "name": "stdout", 70 | "text": [ 71 | "1\n", 72 | "2\n", 73 | "3\n", 74 | "4\n" 75 | ] 76 | } 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "source": [ 82 | "iter(c)" 83 | ], 84 | "metadata": { 85 | "colab": { 86 | "base_uri": "https://localhost:8080/" 87 | }, 88 | "id": "8T6mX3KmxP_l", 89 | "outputId": "69dc999a-2c39-4520-dbc9-1edf7e85fae5" 90 | }, 91 | "execution_count": null, 92 | "outputs": [ 93 | { 94 | "output_type": "execute_result", 95 | "data": { 96 | "text/plain": [ 97 | "" 98 | ] 99 | }, 100 | "metadata": {}, 101 | "execution_count": 8 102 | } 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "source": [ 108 | "for c in 32: #поэтому по числам не получится, они не итерируемые\n", 109 | " print(c)" 110 | ], 111 | "metadata": { 112 | "colab": { 113 | "base_uri": "https://localhost:8080/", 114 | "height": 194 115 | }, 116 | "id": "WWTdV5i4jjeW", 117 | "outputId": "dd3fde37-ff76-49b9-878b-ea931ca1e909" 118 | }, 119 | "execution_count": null, 120 | "outputs": [ 121 | { 122 | "output_type": "error", 123 | "ename": "TypeError", 124 | "evalue": "ignored", 125 | "traceback": [ 126 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 127 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 128 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mc\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;36m32\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 129 | "\u001b[0;31mTypeError\u001b[0m: 'int' object is not iterable" 130 | ] 131 | } 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "source": [ 137 | "n = iter(c)\n", 138 | "print(next(n))\n", 139 | "print(next(n))\n", 140 | "print(next(n))\n", 141 | "print(next(n))\n", 142 | "print(next(n))" 143 | ], 144 | "metadata": { 145 | "colab": { 146 | "base_uri": "https://localhost:8080/", 147 | "height": 288 148 | }, 149 | "id": "OEfcnk-Dxqae", 150 | "outputId": "c6e05c08-6db3-444f-b055-e9de0217693a" 151 | }, 152 | "execution_count": null, 153 | "outputs": [ 154 | { 155 | "output_type": "stream", 156 | "name": "stdout", 157 | "text": [ 158 | "1\n", 159 | "2\n", 160 | "3\n", 161 | "4\n" 162 | ] 163 | }, 164 | { 165 | "output_type": "error", 166 | "ename": "StopIteration", 167 | "evalue": "ignored", 168 | "traceback": [ 169 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 170 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 171 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 172 | "\u001b[0;31mStopIteration\u001b[0m: " 173 | ] 174 | } 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "source": [ 180 | "l = [1, 2, 3]\n", 181 | "next(l) #список iterable, но не итератор" 182 | ], 183 | "metadata": { 184 | "colab": { 185 | "base_uri": "https://localhost:8080/", 186 | "height": 204 187 | }, 188 | "id": "hhzoGeFtMC-Z", 189 | "outputId": "c82b6386-9215-4ca4-b33b-bc46a25632c8" 190 | }, 191 | "execution_count": null, 192 | "outputs": [ 193 | { 194 | "output_type": "error", 195 | "ename": "TypeError", 196 | "evalue": "ignored", 197 | "traceback": [ 198 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 199 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 200 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0ml\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ml\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 201 | "\u001b[0;31mTypeError\u001b[0m: 'list' object is not an iterator" 202 | ] 203 | } 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "source": [ 209 | "Где можно встретить итераторы? Да на самом деле много где!\n", 210 | "\n", 211 | "Например, функция zip возвращает итератор:" 212 | ], 213 | "metadata": { 214 | "id": "OT7BVsDuMc3N" 215 | } 216 | }, 217 | { 218 | "cell_type": "code", 219 | "source": [ 220 | "a = [1, 2, 3]\n", 221 | "b = [1, 2, 3]\n", 222 | "c = zip(a, b)\n", 223 | "print(next(c))\n", 224 | "print(next(c))\n", 225 | "print(next(c))" 226 | ], 227 | "metadata": { 228 | "colab": { 229 | "base_uri": "https://localhost:8080/" 230 | }, 231 | "id": "oQniCjrDMhW3", 232 | "outputId": "568ba44d-1d61-401b-a049-a034d515e830" 233 | }, 234 | "execution_count": null, 235 | "outputs": [ 236 | { 237 | "output_type": "stream", 238 | "name": "stdout", 239 | "text": [ 240 | "(1, 1)\n", 241 | "(2, 2)\n", 242 | "(3, 3)\n" 243 | ] 244 | } 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "source": [ 250 | "А также есть функция enumerate() - она делает нумерацию элементов, что можно впоследствие использовать внутри for:" 251 | ], 252 | "metadata": { 253 | "id": "QtmMtONGMptv" 254 | } 255 | }, 256 | { 257 | "cell_type": "code", 258 | "source": [ 259 | "k = [4, 5, 6]\n", 260 | "k_e = enumerate(k)\n", 261 | "print(next(k_e))\n", 262 | "print(next(k_e))\n", 263 | "print(next(k_e))" 264 | ], 265 | "metadata": { 266 | "colab": { 267 | "base_uri": "https://localhost:8080/" 268 | }, 269 | "id": "ya81LwQ4MkvD", 270 | "outputId": "3137b4ef-8f30-4362-e402-79da76d06a36" 271 | }, 272 | "execution_count": null, 273 | "outputs": [ 274 | { 275 | "output_type": "stream", 276 | "name": "stdout", 277 | "text": [ 278 | "(0, 4)\n", 279 | "(1, 5)\n", 280 | "(2, 6)\n" 281 | ] 282 | } 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "source": [ 288 | "for num, el in enumerate(k):\n", 289 | " print(num, el)" 290 | ], 291 | "metadata": { 292 | "colab": { 293 | "base_uri": "https://localhost:8080/" 294 | }, 295 | "id": "eKc3NA8YM7tQ", 296 | "outputId": "920adc5e-cd03-4bc9-d6ef-57958b4633e0" 297 | }, 298 | "execution_count": null, 299 | "outputs": [ 300 | { 301 | "output_type": "stream", 302 | "name": "stdout", 303 | "text": [ 304 | "0 4\n", 305 | "1 5\n", 306 | "2 6\n" 307 | ] 308 | } 309 | ] 310 | }, 311 | { 312 | "cell_type": "markdown", 313 | "source": [ 314 | "### А как сделать свой собственный итератор?" 315 | ], 316 | "metadata": { 317 | "id": "AzCWp-eLhAUz" 318 | } 319 | }, 320 | { 321 | "cell_type": "markdown", 322 | "source": [ 323 | "С итераторами мы уже встречались в itertools - собственно название говорит само за себя, она содержит полезные итераторы.\n", 324 | "\n", 325 | "Что есть итератор? С точки зрения Python - это объект, который обладает dunder методом \\_\\_next\\_\\_, который берет и возвращает следующий элемент до самого конца. В тот момент, когда происходит конец, он должен возвращать ошибку StopIteration\n", 326 | "\n", 327 | "Давайте делать простой итератор на строках:" 328 | ], 329 | "metadata": { 330 | "id": "1priSdOEhF_Z" 331 | } 332 | }, 333 | { 334 | "cell_type": "code", 335 | "source": [ 336 | "class MyIter:\n", 337 | " def __init__(self, s):\n", 338 | " self.s = s\n", 339 | " self.index = 0\n", 340 | "\n", 341 | " def __next__(self):\n", 342 | " if self.index >= len(self.s):\n", 343 | " raise StopIteration(\"Ended\")\n", 344 | " else:\n", 345 | " self.index += 1\n", 346 | " return self.s[self.index - 1]\n", 347 | "\n", 348 | "a = \"abcdefg\"\n", 349 | "iter = MyIter(a)\n", 350 | "print(next(iter))\n", 351 | "print(next(iter))\n", 352 | "print(next(iter))\n", 353 | "print(next(iter))\n", 354 | "print(next(iter))\n", 355 | "print(next(iter))" 356 | ], 357 | "metadata": { 358 | "colab": { 359 | "base_uri": "https://localhost:8080/" 360 | }, 361 | "id": "qBjEzrbBka32", 362 | "outputId": "0d4448b4-1096-49c8-91af-75ba87719780" 363 | }, 364 | "execution_count": 8, 365 | "outputs": [ 366 | { 367 | "output_type": "stream", 368 | "name": "stdout", 369 | "text": [ 370 | "a\n", 371 | "b\n", 372 | "c\n", 373 | "d\n", 374 | "e\n", 375 | "f\n" 376 | ] 377 | } 378 | ] 379 | }, 380 | { 381 | "cell_type": "code", 382 | "source": [ 383 | "print(next(iter))\n", 384 | "print(next(iter))" 385 | ], 386 | "metadata": { 387 | "colab": { 388 | "base_uri": "https://localhost:8080/", 389 | "height": 320 390 | }, 391 | "id": "U2ZEbJUClbtT", 392 | "outputId": "095919d8-1c18-445d-d166-dfc119eecaed" 393 | }, 394 | "execution_count": 9, 395 | "outputs": [ 396 | { 397 | "output_type": "stream", 398 | "name": "stdout", 399 | "text": [ 400 | "g\n" 401 | ] 402 | }, 403 | { 404 | "output_type": "error", 405 | "ename": "StopIteration", 406 | "evalue": "Ended", 407 | "traceback": [ 408 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 409 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 410 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miter\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miter\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 411 | "\u001b[0;32m\u001b[0m in \u001b[0;36m__next__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__next__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Ended\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 9\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 412 | "\u001b[0;31mStopIteration\u001b[0m: Ended" 413 | ] 414 | } 415 | ] 416 | }, 417 | { 418 | "cell_type": "markdown", 419 | "source": [ 420 | "Ура, сделали простой рабочий итератор! Как вы можете заметить, внутри next можно делать что угодно (можно изменять элементы, выводить по условиям и так далее). Но этого недостаточно, потому что давайте попробуем сделать следующее:" 421 | ], 422 | "metadata": { 423 | "id": "HifdIv38ldSH" 424 | } 425 | }, 426 | { 427 | "cell_type": "code", 428 | "source": [ 429 | "a = \"abcdefg\"\n", 430 | "iter = MyIter(a)\n", 431 | "for i in iter:\n", 432 | " print(i)" 433 | ], 434 | "metadata": { 435 | "colab": { 436 | "base_uri": "https://localhost:8080/", 437 | "height": 207 438 | }, 439 | "id": "kLi6Tgw-nBII", 440 | "outputId": "0ebc73cc-2017-46b9-af8f-941ea8fc29ae" 441 | }, 442 | "execution_count": 10, 443 | "outputs": [ 444 | { 445 | "output_type": "error", 446 | "ename": "TypeError", 447 | "evalue": "'MyIter' object is not iterable", 448 | "traceback": [ 449 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 450 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 451 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"abcdefg\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0miter\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mMyIter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0miter\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 452 | "\u001b[0;31mTypeError\u001b[0m: 'MyIter' object is not iterable" 453 | ] 454 | } 455 | ] 456 | }, 457 | { 458 | "cell_type": "markdown", 459 | "source": [ 460 | "Опа, вроде как сделали итератор, но он не iterable. Как так?\n", 461 | "\n", 462 | "Чтобы итератор стал полным итератором, нам надо добавить dunder метод \\_\\_iter\\_\\_, который и должен возвращать объект (вернее то, что нужно итерировать):" 463 | ], 464 | "metadata": { 465 | "id": "wds9oO5jnGXt" 466 | } 467 | }, 468 | { 469 | "cell_type": "code", 470 | "source": [ 471 | "class MyIter:\n", 472 | " def __init__(self, s):\n", 473 | " self.s = s\n", 474 | " self.index = 0\n", 475 | "\n", 476 | " def __iter__(self):\n", 477 | " return self\n", 478 | "\n", 479 | " def __next__(self):\n", 480 | " if self.index >= len(self.s):\n", 481 | " raise StopIteration(\"Ended\")\n", 482 | " else:\n", 483 | " self.index += 1\n", 484 | " return self.s[self.index - 1]" 485 | ], 486 | "metadata": { 487 | "id": "G4cCIqsenSh9" 488 | }, 489 | "execution_count": 11, 490 | "outputs": [] 491 | }, 492 | { 493 | "cell_type": "code", 494 | "source": [ 495 | "a = \"abcdefg\"\n", 496 | "iter = MyIter(a)\n", 497 | "for i in iter:\n", 498 | " print(i)" 499 | ], 500 | "metadata": { 501 | "colab": { 502 | "base_uri": "https://localhost:8080/" 503 | }, 504 | "id": "U06IwRavnXVj", 505 | "outputId": "9dfab050-fffb-4ca8-b72d-3ca96bacf6ae" 506 | }, 507 | "execution_count": 12, 508 | "outputs": [ 509 | { 510 | "output_type": "stream", 511 | "name": "stdout", 512 | "text": [ 513 | "a\n", 514 | "b\n", 515 | "c\n", 516 | "d\n", 517 | "e\n", 518 | "f\n", 519 | "g\n" 520 | ] 521 | } 522 | ] 523 | }, 524 | { 525 | "cell_type": "markdown", 526 | "source": [ 527 | "Зачем нужны итераторы?\n", 528 | "\n", 529 | "* Позволяет перебирать элементы (без итераторов нам бы пришлось делать while, обращаться к каждому элементу). По факту проще синтаксис, не более\n", 530 | "\n", 531 | "* Позволяет экономить память\n", 532 | "\n", 533 | "Про второе - мы как-то говорили про раницу между range и xrange во втором Python (range во втором Питоне просто выдает сразу весь список, а его хранить в памяти надо)\n", 534 | "\n", 535 | "Давайте попробуем сделать свой собственный range:" 536 | ], 537 | "metadata": { 538 | "id": "yanYRNIbnjMR" 539 | } 540 | }, 541 | { 542 | "cell_type": "code", 543 | "source": [ 544 | "class MyRange:\n", 545 | " def __init__(self, start=0, end=10, step=1):\n", 546 | " self.start = start\n", 547 | " self.end = end\n", 548 | " self.step = step\n", 549 | "\n", 550 | " def __iter__(self):\n", 551 | " return self\n", 552 | "\n", 553 | " def __next__(self):\n", 554 | " if self.start >= self.end:\n", 555 | " raise StopIteration\n", 556 | " else:\n", 557 | " self.start += self.step\n", 558 | " return self.start - self.step\n", 559 | "\n", 560 | "for i in MyRange(1, 3, 0.5):\n", 561 | " print(i)" 562 | ], 563 | "metadata": { 564 | "colab": { 565 | "base_uri": "https://localhost:8080/" 566 | }, 567 | "id": "loErm4M6oR29", 568 | "outputId": "b586acb6-96fa-455a-fd9a-3957d56bdd5c" 569 | }, 570 | "execution_count": 17, 571 | "outputs": [ 572 | { 573 | "output_type": "stream", 574 | "name": "stdout", 575 | "text": [ 576 | "1.0\n", 577 | "1.5\n", 578 | "2.0\n", 579 | "2.5\n" 580 | ] 581 | } 582 | ] 583 | }, 584 | { 585 | "cell_type": "markdown", 586 | "source": [ 587 | "## Генераторы" 588 | ], 589 | "metadata": { 590 | "id": "3EC2WocBnk6b" 591 | } 592 | }, 593 | { 594 | "cell_type": "markdown", 595 | "source": [ 596 | "В чем разница между генератором и итератором?\n", 597 | "\n", 598 | "* Итератор - объект, позволяющий пройтись по объектам\n", 599 | "\n", 600 | "* Генератор - объект, позволяющий генерировать значения\n", 601 | "\n", 602 | "Формально генератор - это расширение итератора (за счет того, что можно генерировать данные)" 603 | ], 604 | "metadata": { 605 | "id": "_0sC82q-vHJC" 606 | } 607 | }, 608 | { 609 | "cell_type": "markdown", 610 | "source": [ 611 | "Как распознать генератор? Простым словом yield!" 612 | ], 613 | "metadata": { 614 | "id": "-Pu_cGgTnn1K" 615 | } 616 | }, 617 | { 618 | "cell_type": "code", 619 | "source": [ 620 | "def simple_gen():\n", 621 | " yield \"Какапо\"\n", 622 | " yield \"Кеа\"\n", 623 | " yield \"Ара\"\n", 624 | " yield \"Какаду\"\n", 625 | " yield \"Корелла\"\n", 626 | "\n", 627 | "s = simple_gen()\n", 628 | "print(next(s))\n", 629 | "print(next(s))\n", 630 | "print(next(s))\n", 631 | "print(next(s))\n", 632 | "print(next(s))\n", 633 | "print(next(s)) # опа, знакомая нам ошибка\n" 634 | ], 635 | "metadata": { 636 | "colab": { 637 | "base_uri": "https://localhost:8080/", 638 | "height": 282 639 | }, 640 | "id": "nBEn93pXoNtG", 641 | "outputId": "fe89fb1e-f764-4fb4-d110-7c8bae3214cc" 642 | }, 643 | "execution_count": 18, 644 | "outputs": [ 645 | { 646 | "output_type": "stream", 647 | "name": "stdout", 648 | "text": [ 649 | "Какапо\n", 650 | "Кеа\n", 651 | "Ара\n", 652 | "Какаду\n", 653 | "Корелла\n" 654 | ] 655 | }, 656 | { 657 | "output_type": "error", 658 | "ename": "StopIteration", 659 | "evalue": "", 660 | "traceback": [ 661 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 662 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 663 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m)\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", 664 | "\u001b[0;31mStopIteration\u001b[0m: " 665 | ] 666 | } 667 | ] 668 | }, 669 | { 670 | "cell_type": "code", 671 | "source": [ 672 | "for i in simple_gen():\n", 673 | " print(i)" 674 | ], 675 | "metadata": { 676 | "colab": { 677 | "base_uri": "https://localhost:8080/" 678 | }, 679 | "id": "gqtqf1UitIdu", 680 | "outputId": "cf7fec5a-0a1e-4ce4-9077-16a582a9e9bd" 681 | }, 682 | "execution_count": 19, 683 | "outputs": [ 684 | { 685 | "output_type": "stream", 686 | "name": "stdout", 687 | "text": [ 688 | "Какапо\n", 689 | "Кеа\n", 690 | "Ара\n", 691 | "Какаду\n", 692 | "Корелла\n" 693 | ] 694 | } 695 | ] 696 | }, 697 | { 698 | "cell_type": "markdown", 699 | "source": [ 700 | "Как работает генератор, что за yield?\n", 701 | "\n", 702 | "Все просто:\n", 703 | "\n", 704 | "Мы вызываем функцию. Когда он доходит до yield, то выдает значение. После этого функция переходит как бы в режим ожидания. Когда мы ее вызываем в следующий раз, он начинает с места, где закончил и продолжает. Как закончить жизнь генератора? Сделать return" 705 | ], 706 | "metadata": { 707 | "id": "_USnaMOoorom" 708 | } 709 | }, 710 | { 711 | "cell_type": "code", 712 | "source": [ 713 | "def fibonacci(n):\n", 714 | " a, b, counter = 0, 1, 0\n", 715 | " while True:\n", 716 | " if (counter > n):\n", 717 | " return\n", 718 | " yield a\n", 719 | " a, b = b, a + b\n", 720 | " counter += 1\n", 721 | "\n", 722 | "f = fibonacci(5)\n", 723 | "print(f)\n", 724 | "for x in f:\n", 725 | " print(x, end=\" \")" 726 | ], 727 | "metadata": { 728 | "colab": { 729 | "base_uri": "https://localhost:8080/" 730 | }, 731 | "id": "X2kUdOBDpRW9", 732 | "outputId": "dbe04b4a-32d3-478f-ea8b-81f22cb716f0" 733 | }, 734 | "execution_count": null, 735 | "outputs": [ 736 | { 737 | "output_type": "stream", 738 | "name": "stdout", 739 | "text": [ 740 | "\n", 741 | "0 1 1 2 3 5 " 742 | ] 743 | } 744 | ] 745 | }, 746 | { 747 | "cell_type": "markdown", 748 | "source": [ 749 | "Ну хорошо, в нашем первом примере как-то это явно неудобно, писать кучу строк... А можно, на самом деле, сделать вот такую штуку:" 750 | ], 751 | "metadata": { 752 | "id": "yUGJBP6zrNx2" 753 | } 754 | }, 755 | { 756 | "cell_type": "code", 757 | "source": [ 758 | "def simple_gen():\n", 759 | " yield from [\"Какапо\", \"Кеа\", \"Ара\", \"Какаду\", \"Корелла\"] #yield from работает только с iterable объектами\n", 760 | "\n", 761 | "s = simple_gen()\n", 762 | "print(next(s))\n", 763 | "print(next(s))\n", 764 | "print(next(s))\n", 765 | "print(next(s))\n", 766 | "print(next(s))" 767 | ], 768 | "metadata": { 769 | "colab": { 770 | "base_uri": "https://localhost:8080/" 771 | }, 772 | "id": "A1JTCWnSsB4E", 773 | "outputId": "8cc7791a-9f00-4c94-c162-19298f0b1cca" 774 | }, 775 | "execution_count": null, 776 | "outputs": [ 777 | { 778 | "output_type": "stream", 779 | "name": "stdout", 780 | "text": [ 781 | "Какапо\n", 782 | "Кеа\n", 783 | "Ара\n", 784 | "Какаду\n", 785 | "Корелла\n" 786 | ] 787 | } 788 | ] 789 | }, 790 | { 791 | "cell_type": "markdown", 792 | "source": [ 793 | "Где вы могли видеть генераторы? А вот тут:" 794 | ], 795 | "metadata": { 796 | "id": "MDFsUrQKtosT" 797 | } 798 | }, 799 | { 800 | "cell_type": "code", 801 | "source": [ 802 | "(i for i in range(10))" 803 | ], 804 | "metadata": { 805 | "colab": { 806 | "base_uri": "https://localhost:8080/" 807 | }, 808 | "id": "Ty2q6sextrpP", 809 | "outputId": "7214c926-685c-44c4-985c-a1efc753e86e" 810 | }, 811 | "execution_count": 20, 812 | "outputs": [ 813 | { 814 | "output_type": "execute_result", 815 | "data": { 816 | "text/plain": [ 817 | " at 0x7cc55f08bdf0>" 818 | ] 819 | }, 820 | "metadata": {}, 821 | "execution_count": 20 822 | } 823 | ] 824 | }, 825 | { 826 | "cell_type": "markdown", 827 | "source": [ 828 | "Что еще крутого есть в генераторах? Для итераторов мы можем только ходить по значениям и делать с ними что-то (итерироваться). А вот в генераторы мы можем отправлять значения!\n", 829 | "\n", 830 | "В чем прикол: на самом деле yield не только дает значения, но и послыает значения. Если воспринимать генератор как итератор, то разницы никакой, в общем-то, а вот если расширять функции генератора, то не совсем.\n", 831 | "\n", 832 | "По дефолту yield выдает None, а поскольку мы ничего с этим не делаем, то как бы и ок. Но мы можем отправить что-то с помощью send(), и таким образом, модернизировать значения!" 833 | ], 834 | "metadata": { 835 | "id": "Y8GMBkd7soKV" 836 | } 837 | }, 838 | { 839 | "cell_type": "code", 840 | "source": [ 841 | "def count(firstval=0, step=1):\n", 842 | " counter = firstval\n", 843 | " while True:\n", 844 | " new_counter_val = yield counter # здесь возвращается либо None, либо результат send\n", 845 | " if new_counter_val is None:\n", 846 | " counter += step\n", 847 | " else:\n", 848 | " counter = new_counter_val[0]\n", 849 | " step = new_counter_val[1]\n", 850 | "\n", 851 | "start_value = 2.1\n", 852 | "step_value = 0.3\n", 853 | "counter = count(start_value, step_value)\n", 854 | "for i in range(10):\n", 855 | " new_value = next(counter)\n", 856 | " print(f\"{new_value:2.2f}\", end=\", \")\n", 857 | "\n", 858 | "print()\n", 859 | "print(\"set current count value to another value:\")\n", 860 | "counter.send((100.5, 2)) # ооотправляем посылочку\n", 861 | "for i in range(10):\n", 862 | " new_value = next(counter)\n", 863 | " print(f\"{new_value:2.2f}\", end=\", \")" 864 | ], 865 | "metadata": { 866 | "colab": { 867 | "base_uri": "https://localhost:8080/" 868 | }, 869 | "id": "3pU2RizrsT5B", 870 | "outputId": "bab751cf-1673-4bb3-b732-70a62c4fad71" 871 | }, 872 | "execution_count": null, 873 | "outputs": [ 874 | { 875 | "output_type": "stream", 876 | "name": "stdout", 877 | "text": [ 878 | "2.10, 2.40, 2.70, 3.00, 3.30, 3.60, 3.90, 4.20, 4.50, 4.80, \n", 879 | "set current count value to another value:\n", 880 | "102.50, 104.50, 106.50, 108.50, 110.50, 112.50, 114.50, 116.50, 118.50, 120.50, " 881 | ] 882 | } 883 | ] 884 | }, 885 | { 886 | "cell_type": "markdown", 887 | "source": [ 888 | "А еще можем вкидывать ошибки)))" 889 | ], 890 | "metadata": { 891 | "id": "yLCNxcgQuzVK" 892 | } 893 | }, 894 | { 895 | "cell_type": "code", 896 | "source": [ 897 | "def count(firstval=0, step=1):\n", 898 | " counter = firstval\n", 899 | " while True:\n", 900 | " try:\n", 901 | " new_counter_val = yield counter\n", 902 | " if new_counter_val is None:\n", 903 | " counter += step\n", 904 | " else:\n", 905 | " counter = new_counter_val\n", 906 | " except Exception:\n", 907 | " yield (firstval, step, counter)\n", 908 | "\n", 909 | "c = count()\n", 910 | "for i in range(6):\n", 911 | " print(next(c))\n", 912 | "print(\"Our state\")\n", 913 | "state_of_count = c.throw(Exception)\n", 914 | "print(state_of_count)\n", 915 | "for i in range(3):\n", 916 | " print(next(c))" 917 | ], 918 | "metadata": { 919 | "colab": { 920 | "base_uri": "https://localhost:8080/" 921 | }, 922 | "id": "NvmQDH_Uu3Ad", 923 | "outputId": "d1b308eb-216d-47a3-f668-e1a6b2b681d4" 924 | }, 925 | "execution_count": null, 926 | "outputs": [ 927 | { 928 | "output_type": "stream", 929 | "name": "stdout", 930 | "text": [ 931 | "0\n", 932 | "1\n", 933 | "2\n", 934 | "3\n", 935 | "4\n", 936 | "5\n", 937 | "Our state\n", 938 | "(0, 1, 5)\n", 939 | "5\n", 940 | "6\n", 941 | "7\n" 942 | ] 943 | } 944 | ] 945 | }, 946 | { 947 | "cell_type": "markdown", 948 | "source": [ 949 | "И на всякий случай, с чего начали, к тому и пришли: генераторы тоже можно передавать в качестве аргументов функции, опа, доп обертка" 950 | ], 951 | "metadata": { 952 | "id": "Dm9o_pBvvQMD" 953 | } 954 | }, 955 | { 956 | "cell_type": "code", 957 | "source": [ 958 | "def firstn(generator, n):\n", 959 | " g = generator()\n", 960 | " for i in range(n):\n", 961 | " yield next(g)\n", 962 | "\n", 963 | "print(list(firstn(simple_gen, 3)))" 964 | ], 965 | "metadata": { 966 | "colab": { 967 | "base_uri": "https://localhost:8080/" 968 | }, 969 | "id": "W5d1pWdFvXxX", 970 | "outputId": "bb8ac7b4-d838-48e3-dab2-fbb41d609e9a" 971 | }, 972 | "execution_count": null, 973 | "outputs": [ 974 | { 975 | "output_type": "stream", 976 | "name": "stdout", 977 | "text": [ 978 | "['Какапо', 'Кеа', 'Ара']\n" 979 | ] 980 | } 981 | ] 982 | }, 983 | { 984 | "cell_type": "markdown", 985 | "source": [ 986 | "## Попугай дня" 987 | ], 988 | "metadata": { 989 | "id": "xAL_LbetgNuo" 990 | } 991 | }, 992 | { 993 | "cell_type": "markdown", 994 | "source": [ 995 | "![](https://i.pinimg.com/originals/2d/59/dc/2d59dc37ef7d2c3767f075e05ed193a6.jpg)" 996 | ], 997 | "metadata": { 998 | "id": "QdCs2NJKgRGf" 999 | } 1000 | }, 1001 | { 1002 | "cell_type": "markdown", 1003 | "source": [ 1004 | "А это не попугай! Это капибара (или ее еще называют водосвинкой, а в Мексике ее вообще зовут кокосовой собачкой)\n", 1005 | "\n", 1006 | "Самые крупные грызуны на планете, максимально милейшие, дружелюбные и очень хорошо ладят с людьми. Едят траву, а водосвинками называются, потому что они плавают и в целом любят воду\n", 1007 | "\n", 1008 | "Какие факты есть про них:\n", 1009 | "\n", 1010 | "1. Они балдежные и очень спокойные\n", 1011 | "\n", 1012 | "2. Католическая церковь в XVI веке говорила, что капибары из-за их полуводного образа жизни являются рыбами, а поэтому их можно было есть в пост\n", 1013 | "\n", 1014 | "3. В Аргентине недавно переселились в богатые районы Буэнос-Айреса (где, естественно, много зелени) и теперь там хозяйствуют (поэтому есть кучами мемов с капибарами-коммунистами). А поскольку естественные враги капибар - это кайманы и пумы, то как-то их и не выселишь" 1015 | ], 1016 | "metadata": { 1017 | "id": "2fjnj9aegYse" 1018 | } 1019 | }, 1020 | { 1021 | "cell_type": "markdown", 1022 | "source": [ 1023 | "![](https://i.pinimg.com/originals/83/0e/16/830e163003a346352ac0d9ba20203b2e.jpg)" 1024 | ], 1025 | "metadata": { 1026 | "id": "X7eLvbODhmUG" 1027 | } 1028 | } 1029 | ] 1030 | } -------------------------------------------------------------------------------- /Lectures/Lecture_05.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "collapsed_sections": [ 8 | "-2k_UncjnhHQ", 9 | "c11qThyDs5tj", 10 | "g5mUKTcO5Cv2", 11 | "XQyJ09DF9DEN", 12 | "qrLg4waSKBCh", 13 | "gMFY_bf533vm" 14 | ] 15 | }, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | }, 20 | "language_info": { 21 | "name": "python" 22 | } 23 | }, 24 | "cells": [ 25 | { 26 | "cell_type": "markdown", 27 | "source": [ 28 | "# Python-1, лекция 5\n", 29 | "\n", 30 | "Лектор: Петров Тимур, Фролов Андрей" 31 | ], 32 | "metadata": { 33 | "id": "hprOLVzS5nOp" 34 | } 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "source": [ 39 | "# Регулярные выражения" 40 | ], 41 | "metadata": { 42 | "id": "xSQAp0rw6-Qr" 43 | } 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": { 48 | "id": "NZiBXLMElWND" 49 | }, 50 | "source": [ 51 | "## Что такое регулярные выражения?\n", 52 | "\n", 53 | "Регулярное выражение - это строка, которая задает некоторый паттерн (шаблон) для поиска внутри строки. С его помощью можно находить в тексте необходимые части (например, все города внутри текста, слова на русском и так далее), а также проверять строки на правильность (например, проверка e-mail, телефона и тому подобное)\n", 54 | "\n", 55 | "Это очень удобная и сильная вещь, но палка о двух концах (об этом будет далее). Итак, приступим:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": { 61 | "id": "IK83DxlUmx83" 62 | }, 63 | "source": [ 64 | "## Где потренироваться и проверять регулярку\n", 65 | "\n", 66 | "Ответ очевиден - в Питоне с помощью библиотеки re 🐍\n", 67 | "\n", 68 | "[Ссылка на документацию](https://docs.python.org/3/library/re.html) (осторожно, english)\n", 69 | "\n", 70 | "Но если лень писать код, или хочется видеть результат в режиме онлайн, то существует множество сайтов, где можно это посмотреть, например, [вот здесь](https://https://regex101.com/) (не забудьте слева выбрать Flavor Python, потому что реализация различается, хоть и не сильно)" 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": { 76 | "id": "-2k_UncjnhHQ" 77 | }, 78 | "source": [ 79 | "## Основы и квантификаторы" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "source": [ 85 | "Допустим, вам нужно найти просто все вхождения слова внутри текста. Тогда регулярное выражение не будет иметь в себе никаких сложностей и будет состоять из самого слова:" 86 | ], 87 | "metadata": { 88 | "id": "jYQTZCgj6Ke3" 89 | } 90 | }, 91 | { 92 | "cell_type": "code", 93 | "metadata": { 94 | "colab": { 95 | "base_uri": "https://localhost:8080/" 96 | }, 97 | "id": "r1O9hf6OlQOT", 98 | "outputId": "2c6a3869-222f-4bfe-c803-e984788310c6" 99 | }, 100 | "source": [ 101 | "import re # библиотека для регулярок в Питоне\n", 102 | "\n", 103 | "# re.search(pattern, text) - поиск первого паттерна вида pattern внутри строки text.\n", 104 | "\n", 105 | "m = re.search(r'ah', r'ahahah aha') # r перед строкой - считываем строку как есть (raw)\n", 106 | "print(m)\n", 107 | "print(m.group(0))\n", 108 | "\n", 109 | "# re.findall(pattern, text) - поиск всех паттернов вида pattern внутри строки text. Возвращает список всех совпадений\n", 110 | "\n", 111 | "m = re.findall(r'aha', r'ahahah aha') # r перед строкой - считываем строку как есть (raw)\n", 112 | "print(m)\n", 113 | "\n", 114 | "# re.compile(pattern, flags) - запись паттерна, который можно использовать в дальнейшем. Flags дает дополнительные фичи\n", 115 | "\n", 116 | "pattern = re.compile(r'aha', flags = re.A)\n", 117 | "print(pattern)\n", 118 | "m = re.findall(pattern, r'ahahah aha')\n", 119 | "print(m)" 120 | ], 121 | "execution_count": null, 122 | "outputs": [ 123 | { 124 | "output_type": "stream", 125 | "name": "stdout", 126 | "text": [ 127 | "\n", 128 | "ah\n", 129 | "['aha', 'aha']\n", 130 | "re.compile('aha', re.ASCII)\n", 131 | "['aha', 'aha']\n" 132 | ] 133 | } 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": { 139 | "id": "nba8w_oPqrLw" 140 | }, 141 | "source": [ 142 | "Усложним задачу. Допустим, что мы ищем слово цвет на английском, которое может записываться как color (Ам), так и colour (Бр)\n", 143 | "\n", 144 | "Для этого есть квантификаторы, которые могут учитывать, сколько раз может встречаться та или иная буква:\n", 145 | "\n", 146 | "* {a} - встречается ровно a раз\n", 147 | "* {a,b} - встречается от a до b раз\n", 148 | "* {,b} - максимум b раз\n", 149 | "* {a,} - минимум a раз\n", 150 | "\n", 151 | "Квантификатор будет ставится после буквы (или простого шаблона), для которого он нужен.\n", 152 | "\n", 153 | "В нашем случае это будет выглядеть так:\n", 154 | "\n" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "metadata": { 160 | "colab": { 161 | "base_uri": "https://localhost:8080/" 162 | }, 163 | "id": "TLPeBBLTrcyY", 164 | "outputId": "2b0855fc-ffd0-489e-9624-48ed24aa0851" 165 | }, 166 | "source": [ 167 | "pattern = re.compile(r'colou{,1}r') # color, colour - будет засчитано\n", 168 | "s = 'color, colour'\n", 169 | "m = re.findall(pattern, s)\n", 170 | "print(m)" 171 | ], 172 | "execution_count": null, 173 | "outputs": [ 174 | { 175 | "output_type": "stream", 176 | "name": "stdout", 177 | "text": [ 178 | "['color', 'colour']\n" 179 | ] 180 | } 181 | ] 182 | }, 183 | { 184 | "cell_type": "markdown", 185 | "metadata": { 186 | "id": "1fKP3cBFsI-m" 187 | }, 188 | "source": [ 189 | "Некоторые квантификаторы используется достаточно часто, поэтому для них есть особенные символы:\n", 190 | "\n", 191 | "* $?$ = {0,1} - встречается 0 или 1 раз\n", 192 | "* $*$ = {0,} - встречается от 0 раз и больше\n", 193 | "* $+$ = {1,} - встречается от 1 раза и больше\n", 194 | "\n", 195 | "Можем упростить наше выражение:" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "metadata": { 201 | "colab": { 202 | "base_uri": "https://localhost:8080/" 203 | }, 204 | "id": "WjuB9ryNsoYP", 205 | "outputId": "e3bd799b-5d0f-420b-9a73-1ce85102d1d0" 206 | }, 207 | "source": [ 208 | "pattern = re.compile(r'c?o?l?o?u?r')\n", 209 | "s = 'color, colour, olur'\n", 210 | "m = re.findall(pattern, s)\n", 211 | "print(m)\n", 212 | "\n", 213 | "pattern = re.compile(r'colou*r')\n", 214 | "s = 'color, colour colouuuuuuuuuuuuuuuuuur'\n", 215 | "m = re.findall(pattern, s)\n", 216 | "print(m)\n", 217 | "\n", 218 | "pattern = re.compile(r'colo.*r')\n", 219 | "s = 'color, colour colouuuuuuuuuuuuuuuuuur'\n", 220 | "m = re.findall(pattern, s)\n", 221 | "print(m)" 222 | ], 223 | "execution_count": null, 224 | "outputs": [ 225 | { 226 | "output_type": "stream", 227 | "name": "stdout", 228 | "text": [ 229 | "['color', 'colour', 'olur']\n", 230 | "['color', 'colour', 'colouuuuuuuuuuuuuuuuuur']\n", 231 | "['color, colour colouuuuuuuuuuuuuuuuuur']\n" 232 | ] 233 | } 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": { 239 | "id": "c11qThyDs5tj" 240 | }, 241 | "source": [ 242 | "## Особые символы" 243 | ] 244 | }, 245 | { 246 | "cell_type": "markdown", 247 | "source": [ 248 | "Для того, чтобы сделать поиск уникальным, нам теперь надо добавить дополнительные символы, с помощью которых можно осуществлять поиск. Среди таких:\n", 249 | "\n", 250 | "* $.$ - любой символ, кроме начала строки\n", 251 | "* $[]$ - набор символов (символы можно перечислять через -, например [A-Z] = все заглавные символы английского алфавита)\n", 252 | "* [^] - отрицание набора символов (то есть [^A-Z] = все, кроме заглавных букв английского алфавита)\n", 253 | "* ^ - начало текста\n", 254 | "* $ - конец текста\n", 255 | "\n", 256 | "Отдельные символы для букв, цифр и символов:\n", 257 | "\n", 258 | "* \\d - цифра\n", 259 | "* \\D - все, кроме цифры\n", 260 | "* \\w - любая буква, цифра, а также нижнее подчеркивание (буква - это все, что считается буквой в Unicode, то есть и русские буквы, и так далее)\n", 261 | "* \\W - все, кроме букв, цифр и нижнего подчеркивания\n", 262 | "* \\s - пробельные символы (пробел, табуляция, перенос строки и так далее)\n", 263 | "* \\S - все, кроме пробельного символа\n", 264 | "* \\b - начало слова (слева \\W, справа \\w) - ставится по позиции, а не по символу\n", 265 | "* \\B - не начало слова\n", 266 | "\n", 267 | "И есть еще один отдельный символ: \\ - символ экранирования. Экранирование дает прочесть символ как символ, а не как шаблон (например, точку). Внутри набора экранируют только символы ] и \\\\.\n" 268 | ], 269 | "metadata": { 270 | "id": "_uf6kR6J6HSb" 271 | } 272 | }, 273 | { 274 | "cell_type": "code", 275 | "metadata": { 276 | "colab": { 277 | "base_uri": "https://localhost:8080/" 278 | }, 279 | "id": "dNMcq7nZxdmK", 280 | "outputId": "650a1274-c71d-4927-8539-6ebe3f62855f" 281 | }, 282 | "source": [ 283 | "# Хотим найти все слова на английском\n", 284 | "\n", 285 | "pattern = re.compile(r'[a-zA-Z]+')\n", 286 | "s = 'color, colour, sfasdas, lfosdlf5lsfl..'\n", 287 | "m = re.findall(pattern, s)\n", 288 | "print(m)\n", 289 | "\n", 290 | "# Хотим найти даты вида дд.мм.гггг\n", 291 | "\n", 292 | "pattern = re.compile(r'\\d{2}\\.\\d{2}\\.\\d{4}')\n", 293 | "s = 'color, colour, sfasdas, lfosdlf5lsfl 19.04.2012'\n", 294 | "m = re.findall(pattern, s)\n", 295 | "print(m)\n", 296 | "\n", 297 | "# Хотим найти все слова на английском, перед которыми нет ничего\n", 298 | "\n", 299 | "pattern = re.compile(r'\\b[a-zA-Z]+')\n", 300 | "s = 'color, colour, 4sfasdas, lfosdlf5lsfl'\n", 301 | "m = re.findall(pattern, s)\n", 302 | "print(m)" 303 | ], 304 | "execution_count": null, 305 | "outputs": [ 306 | { 307 | "output_type": "stream", 308 | "name": "stdout", 309 | "text": [ 310 | "['color', 'colour', 'sfasdas', 'lfosdlf', 'lsfl']\n", 311 | "['19.04.2012']\n", 312 | "['color', 'colour', 'lfosdlf']\n" 313 | ] 314 | } 315 | ] 316 | }, 317 | { 318 | "cell_type": "markdown", 319 | "metadata": { 320 | "id": "DebQA-MszGjD" 321 | }, 322 | "source": [ 323 | "## Группировки" 324 | ] 325 | }, 326 | { 327 | "cell_type": "markdown", 328 | "source": [ 329 | "Допустим, что наш шаблон нужно повторить несколько раз. Например, нам нужно найти MAC-адрес в тексте (MAC-адрес - это физический адрес устройства в Интернете). Он представляет из себя 6 групп из чисел в шестнадцатеричной системе, которая разделена - или : (пример: 01-23-45-67-89-ab)\n", 330 | "\n", 331 | "Если писать, как есть, то это будет выглядеть как:\n", 332 | "\n", 333 | "[0-9a-fA-F]{2}[:-][0-9a-fA-F]{2}[:-][0-9a-fA-F]{2}[:-][0-9a-fA-F]{2}[:-][0-9a-fA-F]{2}[:-][0-9a-fA-F]{2}\n", 334 | "\n", 335 | "Громоздко и некрасиво, читать сложно. Но здесь есть повторяющийся паттерн [0-9a-fA-F]{2}[:-]\n", 336 | "\n", 337 | "Паттерны можно группировать с помощью скобок:\n", 338 | "\n", 339 | "* (?:) - внутри указывается паттерн\n", 340 | "\n", 341 | "К ней уже можно применять те же самые квантификаторы. И тогда у нас будет:" 342 | ], 343 | "metadata": { 344 | "id": "IXp3GtlW6RU8" 345 | } 346 | }, 347 | { 348 | "cell_type": "code", 349 | "metadata": { 350 | "colab": { 351 | "base_uri": "https://localhost:8080/" 352 | }, 353 | "id": "-P3leAtj0oQe", 354 | "outputId": "b5a450a9-2e7f-402c-b30e-8f9c3f4a8719" 355 | }, 356 | "source": [ 357 | "pattern = re.compile(r'[0-9a-fA-F]{2}(?:[:-][0-9a-fA-F]{2}){5}')\n", 358 | "s = 'color, colour, sfasdas, lfosdlf5lsfl 19.04.2012 01:89:14:16:a1:a2'\n", 359 | "m = re.findall(pattern, s)\n", 360 | "print(m)" 361 | ], 362 | "execution_count": null, 363 | "outputs": [ 364 | { 365 | "output_type": "stream", 366 | "name": "stdout", 367 | "text": [ 368 | "['01:89:14:16:a1:a2']\n" 369 | ] 370 | } 371 | ] 372 | }, 373 | { 374 | "cell_type": "markdown", 375 | "metadata": { 376 | "id": "nyWWInNv06nP" 377 | }, 378 | "source": [ 379 | "Кроме того, внутри группировки можно использовать перечисление (логическое OR). Делается это с помощью |\n", 380 | "\n", 381 | "Например, пусть часть адреса зашифрована с помощью комбинации xx. Тогда, чтобы найти адрес, надо сделать вот так:" 382 | ] 383 | }, 384 | { 385 | "cell_type": "code", 386 | "metadata": { 387 | "colab": { 388 | "base_uri": "https://localhost:8080/" 389 | }, 390 | "id": "K_6yJHch1PS2", 391 | "outputId": "a5e350e1-d0c2-4746-fdad-261b19b32fe2" 392 | }, 393 | "source": [ 394 | "pattern = re.compile(r'(?:[0-9a-fA-F]{2}|[Xx]{2})(?:[:-][0-9a-fA-F]{2}|[:-][Xx]{2}){5}')\n", 395 | "s = 'color, colour, sfasdas, lfosdlf5lsfl 19.04.2012 01:22:14:16:a1:a2 xx:-2:14:XX:a1:a2'\n", 396 | "m = re.findall(pattern, s)\n", 397 | "print(m)" 398 | ], 399 | "execution_count": null, 400 | "outputs": [ 401 | { 402 | "output_type": "stream", 403 | "name": "stdout", 404 | "text": [ 405 | "['01:12:14:16:a1:a2', 'xx:-2:14:XX:a1:a2']\n" 406 | ] 407 | } 408 | ] 409 | }, 410 | { 411 | "cell_type": "markdown", 412 | "metadata": { 413 | "id": "PED9_cke2qAW" 414 | }, 415 | "source": [ 416 | "Группировки могут также использоваться для различных проверок. Скажем, если нам нужно проверить, что перед нужным текстом находятся что-то нужное (например, ищем, когда у нас встречается II только перед именем Николай). Для этого есть так называемые условия lookaround:\n", 417 | "\n", 418 | "* (?=) - проверить, встречается ли этот паттерн после нужного паттерна\n", 419 | "* (?!) - проверить, не встречается ли этот паттерн после нужного паттерна\n", 420 | "* (?<=) - проверить, встречается ли этот паттерн до нужного паттерна (но только фиксированной длины паттерн)\n", 421 | "* (? rotate(1) -> 2-3-4-5-1\n", 732 | "print(d)\n", 733 | "d.rotate(-2) # вправо\n", 734 | "# 1-2-3-4-5 -> rotate(-2) -> 4-5-1-2-3\n", 735 | "print(d)\n", 736 | "d.reverse() # перевернуть очередь\n", 737 | "print(d)\n", 738 | "\n", 739 | "print('-' * 30)\n", 740 | "\n", 741 | "# вставка и удаление\n", 742 | "\n", 743 | "d.insert(1, 'x')\n", 744 | "print(d)\n", 745 | "print(d.index('x'))\n", 746 | "d.remove('x')\n", 747 | "print(d)" 748 | ], 749 | "execution_count": null, 750 | "outputs": [ 751 | { 752 | "output_type": "stream", 753 | "name": "stdout", 754 | "text": [ 755 | "deque(['ab', 'ab', 'bc', 'cd', 'ab'])\n", 756 | "------------------------------\n", 757 | "ab\n", 758 | "ab\n", 759 | "bc\n", 760 | "cd\n", 761 | "ab\n", 762 | "------------------------------\n", 763 | "deque(['pp', 'hh', 'dd', 'ab', 'ab', 'bc', 'cd', 'ab', 'aa', 'hh', 'pp'])\n", 764 | "------------------------------\n", 765 | "pp\n", 766 | "pp\n", 767 | "deque(['hh', 'dd', 'ab', 'ab', 'bc', 'cd', 'ab', 'aa', 'hh'])\n", 768 | "------------------------------\n", 769 | "hh\n", 770 | "aa\n", 771 | "2\n", 772 | "------------------------------\n", 773 | "deque(['hh', 'hh', 'dd', 'ab', 'ab', 'bc', 'cd', 'ab', 'aa'])\n", 774 | "deque(['dd', 'ab', 'ab', 'bc', 'cd', 'ab', 'aa', 'hh', 'hh'])\n", 775 | "deque(['hh', 'hh', 'aa', 'ab', 'cd', 'bc', 'ab', 'ab', 'dd'])\n", 776 | "------------------------------\n", 777 | "deque(['hh', 'x', 'hh', 'aa', 'ab', 'cd', 'bc', 'ab', 'ab', 'dd'])\n", 778 | "1\n", 779 | "deque(['hh', 'hh', 'aa', 'ab', 'cd', 'bc', 'ab', 'ab', 'dd'])\n" 780 | ] 781 | } 782 | ] 783 | }, 784 | { 785 | "cell_type": "markdown", 786 | "metadata": { 787 | "id": "Ym-9IZhSHabA" 788 | }, 789 | "source": [ 790 | "## Defaultdict" 791 | ] 792 | }, 793 | { 794 | "cell_type": "markdown", 795 | "metadata": { 796 | "id": "dJVyj9IvHejV" 797 | }, 798 | "source": [ 799 | "Словарь, где можно задать дефолтное значение для ключей, которых пока нет в словаре. При добавлении не надо использовать get или же проверять, есть ли ключ в словаре\n", 800 | "\n", 801 | "Работает полностью как словарь" 802 | ] 803 | }, 804 | { 805 | "cell_type": "code", 806 | "metadata": { 807 | "colab": { 808 | "base_uri": "https://localhost:8080/" 809 | }, 810 | "id": "S4dCDUDRFJa0", 811 | "outputId": "6ddc3256-5bc4-4e7d-f141-ccb2aec954b3" 812 | }, 813 | "source": [ 814 | "from collections import defaultdict\n", 815 | "\n", 816 | "d = defaultdict(int) # задаем тип значения по дефолту (если int - то это 0)\n", 817 | "s = ['ab', 'ab', 'bc', 'cd', 'ab']\n", 818 | "for elem in s:\n", 819 | " d[elem] += 1\n", 820 | "print(d)\n", 821 | "\n", 822 | "print('-' * 30)\n", 823 | "\n", 824 | "d = defaultdict(list) # задаем тип значения по дефолту (если int - то это 0)\n", 825 | "s = ['ab', 'ab', 'bc', 'cd', 'ab']\n", 826 | "for elem in s:\n", 827 | " d[elem].append(elem)\n", 828 | "print(d)\n", 829 | "\n", 830 | "print('-' * 30)\n", 831 | "\n", 832 | "d = defaultdict(lambda: '') # в качестве значения по дефолту можно использовать функцию\n", 833 | "s = ['ab', 'ab', 'bc', 'cd', 'ab']\n", 834 | "for elem in s:\n", 835 | " d[elem] += elem\n", 836 | "print(d)" 837 | ], 838 | "execution_count": null, 839 | "outputs": [ 840 | { 841 | "output_type": "stream", 842 | "name": "stdout", 843 | "text": [ 844 | "defaultdict(, {'ab': 3, 'bc': 1, 'cd': 1})\n", 845 | "------------------------------\n", 846 | "defaultdict(, {'ab': ['ab', 'ab', 'ab'], 'bc': ['bc'], 'cd': ['cd']})\n", 847 | "------------------------------\n", 848 | "defaultdict( at 0x7ff35d14e830>, {'ab': 'ababab', 'bc': 'bc', 'cd': 'cd'})\n" 849 | ] 850 | } 851 | ] 852 | }, 853 | { 854 | "cell_type": "markdown", 855 | "metadata": { 856 | "id": "qrLg4waSKBCh" 857 | }, 858 | "source": [ 859 | "# Itertools" 860 | ] 861 | }, 862 | { 863 | "cell_type": "markdown", 864 | "metadata": { 865 | "id": "9jCNYYPJKFW-" 866 | }, 867 | "source": [ 868 | "Itertools - библиотека с некоторыми полезными реализованными итераторами. Полезно при генерации последовательностей, создании комбинаций, перестановок, произведений" 869 | ] 870 | }, 871 | { 872 | "cell_type": "code", 873 | "metadata": { 874 | "colab": { 875 | "base_uri": "https://localhost:8080/" 876 | }, 877 | "id": "r1INzY7SKwXS", 878 | "outputId": "0f69f9ca-6d5d-456c-d70e-7fb6c9b7be75" 879 | }, 880 | "source": [ 881 | "from itertools import count, cycle, repeat\n", 882 | "\n", 883 | "# Арифметическая прогрессия\n", 884 | "\n", 885 | "i = count(10, 2)\n", 886 | "print(next(i))\n", 887 | "print(next(i))\n", 888 | "print(next(i))\n", 889 | "print(next(i))\n", 890 | "\n", 891 | "print('-' * 30)\n", 892 | "\n", 893 | "# Цикл\n", 894 | "\n", 895 | "i = cycle('ABC')\n", 896 | "print(next(i))\n", 897 | "print(next(i))\n", 898 | "print(next(i))\n", 899 | "print(next(i))\n", 900 | "print(next(i))\n", 901 | "print(next(i))\n", 902 | "print(next(i))\n", 903 | "print(next(i))\n", 904 | "\n", 905 | "print('-' * 30)\n", 906 | "\n", 907 | "# Повтор\n", 908 | "\n", 909 | "i = repeat('ABC', 5)\n", 910 | "print(next(i))\n", 911 | "print(next(i))\n", 912 | "print(next(i))\n", 913 | "print(next(i))\n", 914 | "print(next(i))" 915 | ], 916 | "execution_count": null, 917 | "outputs": [ 918 | { 919 | "output_type": "stream", 920 | "name": "stdout", 921 | "text": [ 922 | "10\n", 923 | "12\n", 924 | "14\n", 925 | "16\n", 926 | "------------------------------\n", 927 | "A\n", 928 | "B\n", 929 | "C\n", 930 | "A\n", 931 | "B\n", 932 | "C\n", 933 | "A\n", 934 | "B\n", 935 | "------------------------------\n", 936 | "ABC\n", 937 | "ABC\n", 938 | "ABC\n", 939 | "ABC\n", 940 | "ABC\n" 941 | ] 942 | } 943 | ] 944 | }, 945 | { 946 | "cell_type": "code", 947 | "metadata": { 948 | "colab": { 949 | "base_uri": "https://localhost:8080/" 950 | }, 951 | "id": "sCnRkCu3LUMC", 952 | "outputId": "197e7961-dc36-4ce6-8df3-171bad20b49b" 953 | }, 954 | "source": [ 955 | "from itertools import zip_longest, accumulate\n", 956 | "\n", 957 | "z = zip_longest('ABCD', 'xy', fillvalue='-')\n", 958 | "\n", 959 | "for a, b in z:\n", 960 | " print(a, b)\n", 961 | "\n", 962 | "print('-' * 30)\n", 963 | "\n", 964 | "a = accumulate([1, 2, 3, 4])\n", 965 | "print(next(a))\n", 966 | "print(next(a))\n", 967 | "print(next(a))\n", 968 | "print(next(a))\n" 969 | ], 970 | "execution_count": null, 971 | "outputs": [ 972 | { 973 | "output_type": "stream", 974 | "name": "stdout", 975 | "text": [ 976 | "A x\n", 977 | "B y\n", 978 | "C -\n", 979 | "D -\n", 980 | "------------------------------\n", 981 | "1\n", 982 | "3\n", 983 | "6\n", 984 | "10\n" 985 | ] 986 | } 987 | ] 988 | }, 989 | { 990 | "cell_type": "markdown", 991 | "metadata": { 992 | "id": "FttrJXZlMpnN" 993 | }, 994 | "source": [ 995 | "Но самое интересное - это комбинаторные итераторы:\n", 996 | "\n", 997 | "* product(iter, repeat) - repeat число декартово произведение элементов iter\n", 998 | "* permutations(iter, r) - все перестановки длины r из iter\n", 999 | "* combinations(iter, r) - все комбинации длины r из iter (упорядоченные)\n", 1000 | "* combinations_with_replacement(iter, r) - все комбинации с повторениями длины r (упорядоченные)" 1001 | ] 1002 | }, 1003 | { 1004 | "cell_type": "code", 1005 | "metadata": { 1006 | "colab": { 1007 | "base_uri": "https://localhost:8080/" 1008 | }, 1009 | "id": "HrmFcTymNjAS", 1010 | "outputId": "2fef013a-d9ba-40fe-902b-c0dae7a4f648" 1011 | }, 1012 | "source": [ 1013 | "from itertools import product, permutations, combinations, combinations_with_replacement\n", 1014 | "\n", 1015 | "a = product('ABCD', repeat=3)\n", 1016 | "print(next(a))\n", 1017 | "print(next(a))\n", 1018 | "print(next(a))\n", 1019 | "print(next(a))\n", 1020 | "\n", 1021 | "print('-' * 30)\n", 1022 | "\n", 1023 | "a = permutations([1, 2, 3], r=3)\n", 1024 | "print(next(a))\n", 1025 | "print(next(a))\n", 1026 | "print(next(a))\n", 1027 | "print(next(a))\n", 1028 | "print(next(a))\n", 1029 | "print(next(a))\n", 1030 | "\n", 1031 | "print('-' * 30)\n", 1032 | "\n", 1033 | "a = combinations('ABACD', r=3)\n", 1034 | "print(next(a))\n", 1035 | "print(next(a))\n", 1036 | "print(next(a))\n", 1037 | "print(next(a))\n", 1038 | "\n", 1039 | "print('-' * 30)\n", 1040 | "\n", 1041 | "a = combinations_with_replacement('ABCD', r=3)\n", 1042 | "print(next(a))\n", 1043 | "print(next(a))\n", 1044 | "print(next(a))\n", 1045 | "print(next(a))\n", 1046 | "\n", 1047 | "print('-' * 30)" 1048 | ], 1049 | "execution_count": null, 1050 | "outputs": [ 1051 | { 1052 | "output_type": "stream", 1053 | "name": "stdout", 1054 | "text": [ 1055 | "('A', 'A', 'A')\n", 1056 | "('A', 'A', 'B')\n", 1057 | "('A', 'A', 'C')\n", 1058 | "('A', 'A', 'D')\n", 1059 | "------------------------------\n", 1060 | "(1, 2, 3)\n", 1061 | "(1, 3, 2)\n", 1062 | "(2, 1, 3)\n", 1063 | "(2, 3, 1)\n", 1064 | "(3, 1, 2)\n", 1065 | "(3, 2, 1)\n", 1066 | "------------------------------\n", 1067 | "('A', 'B', 'A')\n", 1068 | "('A', 'B', 'C')\n", 1069 | "('A', 'B', 'D')\n", 1070 | "('A', 'A', 'C')\n", 1071 | "------------------------------\n", 1072 | "('A', 'A', 'A')\n", 1073 | "('A', 'A', 'B')\n", 1074 | "('A', 'A', 'C')\n", 1075 | "('A', 'A', 'D')\n", 1076 | "------------------------------\n" 1077 | ] 1078 | } 1079 | ] 1080 | }, 1081 | { 1082 | "cell_type": "markdown", 1083 | "source": [ 1084 | "Дополнительно: https://habr.com/ru/companies/otus/articles/529356/" 1085 | ], 1086 | "metadata": { 1087 | "id": "FqzyU72SRFqj" 1088 | } 1089 | }, 1090 | { 1091 | "cell_type": "markdown", 1092 | "source": [ 1093 | "# Попугай дня" 1094 | ], 1095 | "metadata": { 1096 | "id": "gMFY_bf533vm" 1097 | } 1098 | }, 1099 | { 1100 | "cell_type": "markdown", 1101 | "source": [ 1102 | "![Жако](https://petshop-vrn.ru/wp-content/uploads/6/c/a/6ca4dd99334ae553c70fbc4ed4165506.jpeg)" 1103 | ], 1104 | "metadata": { 1105 | "id": "16jPvyffWRlR" 1106 | } 1107 | }, 1108 | { 1109 | "cell_type": "markdown", 1110 | "source": [ 1111 | "А это Жако, или серый попугай. Считаются самыми умными попугаями в мире, потому что они способны не просто на подражание звуков (как это делают многие попугаи)\n", 1112 | "\n", 1113 | "В 1980-х годах ученая Ирэн Пепперберг проводила исследования по языковому мышлению различных животных, и одним из подопытных был серый попугай по имени Алекс. По результатам эксперимента Алекс мог произносить очень много слов, причем он верно отвечал на вопросы и в целом коммуницировал исходя не из подражания, а из логики. В целом было показано, что у него было мышление, как у шестилетнего ребенка, что стало полным открытием для ученых.\n", 1114 | "\n", 1115 | "Хотя, на самом деле, сравнивать мышление попугаев и людей сложно, потому что мышление животных и не должно быть похожим на человеческое" 1116 | ], 1117 | "metadata": { 1118 | "id": "l7vAW4LpWacC" 1119 | } 1120 | } 1121 | ] 1122 | } -------------------------------------------------------------------------------- /Lectures/Lecture_09.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "source": [ 20 | "#Python-1, лекция 9\n", 21 | "\n", 22 | "Лектор: Петров Тимур, Фролов Андрей" 23 | ], 24 | "metadata": { 25 | "id": "tOKHW-Unyexe" 26 | } 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "source": [ 31 | "Сегодня говорим про декораторы, как их создать и как их кушать" 32 | ], 33 | "metadata": { 34 | "id": "5Wwb8TS4y0ah" 35 | } 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "source": [ 40 | "## Пытаемся понять декораторы" 41 | ], 42 | "metadata": { 43 | "id": "MWARMmZK1ITu" 44 | } 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "source": [ 49 | "Итак, первое, что у нас есть - это функция. Функция может создавать функции внутри себя, а также умеет возвращать функции:" 50 | ], 51 | "metadata": { 52 | "id": "koLgufze1Lcg" 53 | } 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 9, 58 | "metadata": { 59 | "colab": { 60 | "base_uri": "https://localhost:8080/" 61 | }, 62 | "id": "XTc7hTZ_yZNM", 63 | "outputId": "503dab48-e546-4389-97ba-0cf59461ab90" 64 | }, 65 | "outputs": [ 66 | { 67 | "output_type": "stream", 68 | "name": "stdout", 69 | "text": [ 70 | "6 17\n", 71 | "0\n" 72 | ] 73 | } 74 | ], 75 | "source": [ 76 | "def lineq(*args):\n", 77 | "\n", 78 | " def get_x(x):\n", 79 | " return sum([args[i] * x**i for i in range(len(args))])\n", 80 | "\n", 81 | " return get_x\n", 82 | "\n", 83 | "a = lineq(1, 2, 3)\n", 84 | "print(a(1), a(2))\n", 85 | "b = lineq(0, 0, 0)\n", 86 | "print(b(100))" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "source": [ 92 | "Что мы здесь сделали?\n", 93 | "\n", 94 | "Шаг 1: функция lineq, которая принимает в себя значения аргументов и возвращает функцию\n", 95 | "\n", 96 | "Шаг 2: внутри функции мы оформили функцию, принимающую один аргумент, а значения args он берет из своего окружения - в данном случае в lineq\n", 97 | "\n", 98 | "Шаг 3: так как мы присваиваем переменной функцию, то ее можно выдавать и передавать аргументы" 99 | ], 100 | "metadata": { 101 | "id": "wPWadlyJ2-hK" 102 | } 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "source": [ 107 | "А как у нас функция понимает, какие значения ему брать? Давайте на другом примере вспомним:" 108 | ], 109 | "metadata": { 110 | "id": "J1A-rQYu4Mso" 111 | } 112 | }, 113 | { 114 | "cell_type": "code", 115 | "source": [ 116 | "def f():\n", 117 | " print(c)\n", 118 | "\n", 119 | "c = 5\n", 120 | "f()" 121 | ], 122 | "metadata": { 123 | "colab": { 124 | "base_uri": "https://localhost:8080/" 125 | }, 126 | "id": "R42aPCa94SjJ", 127 | "outputId": "80ce7936-6c9c-4386-ce18-c72609cc1683" 128 | }, 129 | "execution_count": 11, 130 | "outputs": [ 131 | { 132 | "output_type": "stream", 133 | "name": "stdout", 134 | "text": [ 135 | "5\n" 136 | ] 137 | } 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "source": [ 143 | "Что делает функция, когда вызывается переменная? Он ее ищет: в локальной области видимости (внутри функции), если нет, то ищет снаружи (в нашем случае - в основной программе).\n", 144 | "\n", 145 | "В функции внутри функции происходит то же самое, только мы добавили еще один слой: слой функции внутри функции. Вот такая штука называется замыканием (closure)" 146 | ], 147 | "metadata": { 148 | "id": "iwqly5r14XYR" 149 | } 150 | }, 151 | { 152 | "cell_type": "markdown", 153 | "source": [ 154 | "Также в качестве аргумента мы умеем принимать и использовать сами функции:" 155 | ], 156 | "metadata": { 157 | "id": "Ernq6ufB6CUt" 158 | } 159 | }, 160 | { 161 | "cell_type": "code", 162 | "source": [ 163 | "import math\n", 164 | "\n", 165 | "def func(f):\n", 166 | " def get_x(x):\n", 167 | " return f(x)\n", 168 | " return get_x\n", 169 | "\n", 170 | "a = func(math.sin)\n", 171 | "print(a(5))\n", 172 | "b = func(math.cos)\n", 173 | "print(b(5))" 174 | ], 175 | "metadata": { 176 | "colab": { 177 | "base_uri": "https://localhost:8080/" 178 | }, 179 | "id": "VW5ypCom6HVe", 180 | "outputId": "0db1ce9f-6625-4198-f558-5b82e0bd7ebc" 181 | }, 182 | "execution_count": 13, 183 | "outputs": [ 184 | { 185 | "output_type": "stream", 186 | "name": "stdout", 187 | "text": [ 188 | "-0.9589242746631385\n", 189 | "0.28366218546322625\n" 190 | ] 191 | } 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "source": [ 197 | "А теперь что такое декоратор? Это обертка вокруг функции, которая сама из себя представляет функцию, принимающая на вход функцию (то есть буквально мы делаем то же самое, что и делали до этого, но красиво обернули, дабы не копироваться)" 198 | ], 199 | "metadata": { 200 | "id": "L8KIiQy65QBv" 201 | } 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "source": [ 206 | "## Пишем примитивный декоратор" 207 | ], 208 | "metadata": { 209 | "id": "2qzhTxoh58AD" 210 | } 211 | }, 212 | { 213 | "cell_type": "code", 214 | "source": [ 215 | "def our_decorator(func): # наш прекрасный и бесполезный декоратор\n", 216 | "\n", 217 | " def function_wrapper(x):\n", 218 | " print(\"Before calling \" + func.__name__)\n", 219 | " print(func(x))\n", 220 | " print(\"After calling \" + func.__name__)\n", 221 | "\n", 222 | " return function_wrapper\n", 223 | "\n", 224 | "def foo(x):\n", 225 | " return f\"Our value {x}\"\n", 226 | "\n", 227 | "foo(5)\n", 228 | "print('-' * 30)\n", 229 | "foo = our_decorator(foo)\n", 230 | "foo(5)" 231 | ], 232 | "metadata": { 233 | "colab": { 234 | "base_uri": "https://localhost:8080/" 235 | }, 236 | "id": "6GaL-QA05-fa", 237 | "outputId": "3ed4ae05-039b-47af-fa24-edff8d11093f" 238 | }, 239 | "execution_count": 24, 240 | "outputs": [ 241 | { 242 | "output_type": "stream", 243 | "name": "stdout", 244 | "text": [ 245 | "------------------------------\n", 246 | "Before calling foo\n", 247 | "Our value 5\n", 248 | "After calling foo\n" 249 | ] 250 | } 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "source": [ 256 | "А теперь добавим немного дополнительного сахара:" 257 | ], 258 | "metadata": { 259 | "id": "cA0WKBTm7WRk" 260 | } 261 | }, 262 | { 263 | "cell_type": "code", 264 | "source": [ 265 | "def our_decorator(func): # наш прекрасный и бесполезный декоратор\n", 266 | "\n", 267 | " def function_wrapper(x):\n", 268 | " print(\"Before calling \" + func.__name__)\n", 269 | " print(func(x))\n", 270 | " print(\"After calling \" + func.__name__)\n", 271 | "\n", 272 | " return function_wrapper\n", 273 | "\n", 274 | "@our_decorator # вот так обозначаются декораторы (название - по функции)\n", 275 | "def g(x):\n", 276 | " return x\n", 277 | "\n", 278 | "g(5)" 279 | ], 280 | "metadata": { 281 | "colab": { 282 | "base_uri": "https://localhost:8080/" 283 | }, 284 | "id": "gwm_Bp_17acp", 285 | "outputId": "7a8b70be-d59d-4941-f482-e219c46a94be" 286 | }, 287 | "execution_count": 23, 288 | "outputs": [ 289 | { 290 | "output_type": "stream", 291 | "name": "stdout", 292 | "text": [ 293 | "Before calling g\n", 294 | "5\n", 295 | "After calling g\n" 296 | ] 297 | } 298 | ] 299 | }, 300 | { 301 | "cell_type": "markdown", 302 | "source": [ 303 | "Вы декораторы уже видели - @lru_cache, @staticmethod и так далее. Это все, по существу - вот такие обертки\n", 304 | "\n", 305 | "Обратите внимание: декораторы можно использовать не только на свои функции, но и в целом на любые другие. Другое дело, что тогда это надо делать с помощью первого случая:" 306 | ], 307 | "metadata": { 308 | "id": "nQmjgSkB7wNS" 309 | } 310 | }, 311 | { 312 | "cell_type": "code", 313 | "source": [ 314 | "from math import sin\n", 315 | "\n", 316 | "sin = our_decorator(sin)\n", 317 | "sin(5)" 318 | ], 319 | "metadata": { 320 | "colab": { 321 | "base_uri": "https://localhost:8080/" 322 | }, 323 | "id": "vRXbx0i88J5S", 324 | "outputId": "ef98593f-6539-4f9d-bc84-3ed68c40de15" 325 | }, 326 | "execution_count": 26, 327 | "outputs": [ 328 | { 329 | "output_type": "stream", 330 | "name": "stdout", 331 | "text": [ 332 | "Before calling sin\n", 333 | "-0.9589242746631385\n", 334 | "After calling sin\n" 335 | ] 336 | } 337 | ] 338 | }, 339 | { 340 | "cell_type": "markdown", 341 | "source": [ 342 | "## Идем дальше - создаем полезные декораторы" 343 | ], 344 | "metadata": { 345 | "id": "221gX-j89LHi" 346 | } 347 | }, 348 | { 349 | "cell_type": "markdown", 350 | "source": [ 351 | "Пример 1: пытаемся посчитать время выполнения функции\n", 352 | "\n", 353 | "Когда мы пишем код, мы часто хотим знать, а сколько у нас длился тот или иной кусок. Можем навесить отдельно на функцию декоратор, которые будет считать время выполнения:" 354 | ], 355 | "metadata": { 356 | "id": "nwA0AE9y9mXC" 357 | } 358 | }, 359 | { 360 | "cell_type": "code", 361 | "source": [ 362 | "import time\n", 363 | "\n", 364 | "def count_time(f):\n", 365 | " def wrapper():\n", 366 | " start = time.time()\n", 367 | " f()\n", 368 | " end = time.time()\n", 369 | " print(f\"Function {f.__name__} took {end - start} seconds\")\n", 370 | "\n", 371 | " return wrapper\n", 372 | "\n", 373 | "@count_time\n", 374 | "def fibonacci(n):\n", 375 | " if n in (1, 2):\n", 376 | " return 1\n", 377 | " return fibonacci(n - 1) + fibonacci(n - 2)\n", 378 | "\n", 379 | "fibonacci(10)" 380 | ], 381 | "metadata": { 382 | "colab": { 383 | "base_uri": "https://localhost:8080/", 384 | "height": 188 385 | }, 386 | "id": "1cpWTO0D96Nk", 387 | "outputId": "6d011d8d-8379-456e-a5bb-9fdae7cbe5f5" 388 | }, 389 | "execution_count": 31, 390 | "outputs": [ 391 | { 392 | "output_type": "error", 393 | "ename": "TypeError", 394 | "evalue": "count_time..wrapper() takes 0 positional arguments but 1 was given", 395 | "traceback": [ 396 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 397 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 398 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mfibonacci\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mfibonacci\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0mfibonacci\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 399 | "\u001b[0;31mTypeError\u001b[0m: count_time..wrapper() takes 0 positional arguments but 1 was given" 400 | ] 401 | } 402 | ] 403 | }, 404 | { 405 | "cell_type": "markdown", 406 | "source": [ 407 | "Чет не получается, как так, что же делать, как-то не очень универсально...\n", 408 | "\n", 409 | "В чем тут проблема - в описании самого декоратора нужно передавать аргументы, это получается для любого декоратора это надо делать?\n", 410 | "\n", 411 | "Нууу нет конечно, давайте править:" 412 | ], 413 | "metadata": { 414 | "id": "cvo1oEBC-14U" 415 | } 416 | }, 417 | { 418 | "cell_type": "code", 419 | "source": [ 420 | "import time\n", 421 | "\n", 422 | "def count_time(f):\n", 423 | " def wrapper(*args, **kwargs):\n", 424 | " start = time.time()\n", 425 | " res = f(*args, **kwargs)\n", 426 | " end = time.time()\n", 427 | " print(f\"Function {f.__name__} took {end - start} seconds\")\n", 428 | " return res\n", 429 | "\n", 430 | " return wrapper\n", 431 | "\n", 432 | "@count_time\n", 433 | "def fibonacci(n=30):\n", 434 | " a = [1 for i_ in range(n)]\n", 435 | " for i in range(2, n):\n", 436 | " a[i] = a[i - 1] + a[i - 2]\n", 437 | " return a[-1]\n", 438 | "\n", 439 | "fibonacci(10)" 440 | ], 441 | "metadata": { 442 | "colab": { 443 | "base_uri": "https://localhost:8080/" 444 | }, 445 | "id": "hKengA-K_KqZ", 446 | "outputId": "b5cc151b-246c-4e2c-f72f-9e232bb96c02" 447 | }, 448 | "execution_count": 37, 449 | "outputs": [ 450 | { 451 | "output_type": "stream", 452 | "name": "stdout", 453 | "text": [ 454 | "Function fibonacci took 7.152557373046875e-06 seconds\n" 455 | ] 456 | }, 457 | { 458 | "output_type": "execute_result", 459 | "data": { 460 | "text/plain": [ 461 | "55" 462 | ] 463 | }, 464 | "metadata": {}, 465 | "execution_count": 37 466 | } 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "source": [ 472 | "fibonacci()" 473 | ], 474 | "metadata": { 475 | "colab": { 476 | "base_uri": "https://localhost:8080/" 477 | }, 478 | "id": "GdiP30LRAggk", 479 | "outputId": "d689dac5-3938-4496-a90e-7a10db76f27d" 480 | }, 481 | "execution_count": 38, 482 | "outputs": [ 483 | { 484 | "output_type": "stream", 485 | "name": "stdout", 486 | "text": [ 487 | "Function fibonacci took 1.6689300537109375e-05 seconds\n" 488 | ] 489 | }, 490 | { 491 | "output_type": "execute_result", 492 | "data": { 493 | "text/plain": [ 494 | "832040" 495 | ] 496 | }, 497 | "metadata": {}, 498 | "execution_count": 38 499 | } 500 | ] 501 | }, 502 | { 503 | "cell_type": "code", 504 | "source": [ 505 | "@count_time\n", 506 | "def fetch_webpage():\n", 507 | " import requests\n", 508 | " webpage = requests.get('https://google.com')\n", 509 | " return webpage\n", 510 | "\n", 511 | "wb = fetch_webpage()\n", 512 | "print(wb)" 513 | ], 514 | "metadata": { 515 | "colab": { 516 | "base_uri": "https://localhost:8080/" 517 | }, 518 | "id": "yaGmYW_dAp0E", 519 | "outputId": "dddf45ac-ea24-4cb6-d3a2-8ac324477c09" 520 | }, 521 | "execution_count": 44, 522 | "outputs": [ 523 | { 524 | "output_type": "stream", 525 | "name": "stdout", 526 | "text": [ 527 | "Function fetch_webpage took 0.06714630126953125 seconds\n", 528 | "\n" 529 | ] 530 | } 531 | ] 532 | }, 533 | { 534 | "cell_type": "markdown", 535 | "source": [ 536 | "Ура, теперь функцию можно использовать где угодно!" 537 | ], 538 | "metadata": { 539 | "id": "FM31PteuA_Sd" 540 | } 541 | }, 542 | { 543 | "cell_type": "markdown", 544 | "source": [ 545 | "## Усложняем декоратор" 546 | ], 547 | "metadata": { 548 | "id": "-gLU31Z0BGb3" 549 | } 550 | }, 551 | { 552 | "cell_type": "markdown", 553 | "source": [ 554 | "Так, ну окей, время считать умеем. Но только 1 раз пока что. А запуски штуки такие, результат может разниться. Можем ли добавить в декоратор параметры?\n", 555 | "\n", 556 | "Да, но тут нужно сделать важное дополнение: декоратор - это функция, которая принимает и возвращает в качестве результата функцию и только функцию. Почему так - давайте на примере:" 557 | ], 558 | "metadata": { 559 | "id": "JmNmgH62C8As" 560 | } 561 | }, 562 | { 563 | "cell_type": "code", 564 | "source": [ 565 | "import time\n", 566 | "\n", 567 | "def count_time(f, iters=10):\n", 568 | " def wrapper(*args, **kwargs):\n", 569 | " timings = []\n", 570 | " for _ in range(iters):\n", 571 | " start = time.time()\n", 572 | " res = f(*args, **kwargs)\n", 573 | " end = time.time()\n", 574 | " timings.append(end - start)\n", 575 | " print(f\"Function {f.__name__} took {sum(timings) / iters} seconds\")\n", 576 | " return res\n", 577 | "\n", 578 | " return wrapper\n", 579 | "\n", 580 | "@count_time(iters=5)\n", 581 | "def fibonacci_new(n=30):\n", 582 | " a = [1 for i_ in range(n)]\n", 583 | " for i in range(2, n):\n", 584 | " a[i] = a[i - 1] + a[i - 2]\n", 585 | " return a[-1]\n", 586 | "\n", 587 | "fibonacci_new(10)" 588 | ], 589 | "metadata": { 590 | "colab": { 591 | "base_uri": "https://localhost:8080/", 592 | "height": 226 593 | }, 594 | "id": "2hocoyVWDSTP", 595 | "outputId": "be9c58b5-1b8a-4a83-d050-fe62b4ebe43a" 596 | }, 597 | "execution_count": 47, 598 | "outputs": [ 599 | { 600 | "output_type": "error", 601 | "ename": "TypeError", 602 | "evalue": "count_time() missing 1 required positional argument: 'f'", 603 | "traceback": [ 604 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 605 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 606 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0;34m@\u001b[0m\u001b[0mcount_time\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miters\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 17\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mfibonacci_new\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m30\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 607 | "\u001b[0;31mTypeError\u001b[0m: count_time() missing 1 required positional argument: 'f'" 608 | ] 609 | } 610 | ] 611 | }, 612 | { 613 | "cell_type": "code", 614 | "source": [ 615 | "def fibonacci_new(n=30):\n", 616 | " a = [1 for i_ in range(n)]\n", 617 | " for i in range(2, n):\n", 618 | " a[i] = a[i - 1] + a[i - 2]\n", 619 | " return a[-1]" 620 | ], 621 | "metadata": { 622 | "id": "uUZonuWCFH_u" 623 | }, 624 | "execution_count": 48, 625 | "outputs": [] 626 | }, 627 | { 628 | "cell_type": "code", 629 | "source": [ 630 | "f = count_time(fibonacci_new, 10) # Придется тогда вот так писать и каждый раз\n", 631 | "f()" 632 | ], 633 | "metadata": { 634 | "colab": { 635 | "base_uri": "https://localhost:8080/" 636 | }, 637 | "id": "AcSTsmnYEHHF", 638 | "outputId": "a353f9ed-ae97-46e6-8ea3-a68520de4df3" 639 | }, 640 | "execution_count": 50, 641 | "outputs": [ 642 | { 643 | "output_type": "stream", 644 | "name": "stdout", 645 | "text": [ 646 | "Function fibonacci_new took 6.008148193359375e-06 seconds\n" 647 | ] 648 | }, 649 | { 650 | "output_type": "execute_result", 651 | "data": { 652 | "text/plain": [ 653 | "832040" 654 | ] 655 | }, 656 | "metadata": {}, 657 | "execution_count": 50 658 | } 659 | ] 660 | }, 661 | { 662 | "cell_type": "markdown", 663 | "source": [ 664 | "Выглядит некрасиво. Давайте поправим через гениальное решение - добавим еще одну обертку:" 665 | ], 666 | "metadata": { 667 | "id": "1UHLUw4AFQFe" 668 | } 669 | }, 670 | { 671 | "cell_type": "code", 672 | "source": [ 673 | "import time\n", 674 | "\n", 675 | "def batch_count(iters=10):\n", 676 | " def count_time(f):\n", 677 | " def wrapper(*args, **kwargs):\n", 678 | " timings = []\n", 679 | " for _ in range(iters):\n", 680 | " start = time.time()\n", 681 | " res = f(*args, **kwargs)\n", 682 | " end = time.time()\n", 683 | " timings.append(end - start)\n", 684 | " print(f\"Function {f.__name__} took {sum(timings) / iters} seconds in {iters} iteations\")\n", 685 | " return res\n", 686 | "\n", 687 | " return wrapper\n", 688 | " return count_time\n", 689 | "\n", 690 | "@batch_count(iters=10)\n", 691 | "def fibonacci(n=30):\n", 692 | " a = [1 for i_ in range(n)]\n", 693 | " for i in range(2, n):\n", 694 | " a[i] = a[i - 1] + a[i - 2]\n", 695 | " return a[-1]\n", 696 | "\n", 697 | "fibonacci(10)" 698 | ], 699 | "metadata": { 700 | "colab": { 701 | "base_uri": "https://localhost:8080/" 702 | }, 703 | "id": "BmpJ3nr1FWR8", 704 | "outputId": "bc22d58d-b3fd-469e-cbe9-e123d989c830" 705 | }, 706 | "execution_count": 56, 707 | "outputs": [ 708 | { 709 | "output_type": "stream", 710 | "name": "stdout", 711 | "text": [ 712 | "Function fibonacci took 3.4809112548828124e-06 seconds in 10 iteations\n" 713 | ] 714 | }, 715 | { 716 | "output_type": "execute_result", 717 | "data": { 718 | "text/plain": [ 719 | "55" 720 | ] 721 | }, 722 | "metadata": {}, 723 | "execution_count": 56 724 | } 725 | ] 726 | }, 727 | { 728 | "cell_type": "markdown", 729 | "source": [ 730 | "А вот так можно, легко и незатейливо! Почему так можно?\n", 731 | "\n", 732 | "Если приглядеться, что batch_count - это обычная функция, которая возвращает декоратор. Так как у нас тут есть скобки (то есть происходит вызов), то он в качестве декоратора запихивает выход - что и есть декоратор." 733 | ], 734 | "metadata": { 735 | "id": "ycBnXlosFsRj" 736 | } 737 | }, 738 | { 739 | "cell_type": "markdown", 740 | "source": [ 741 | "Вопрос на засыпку: а можно ли теперь вызвать функцию без декоратора?\n", 742 | "\n", 743 | "Можно, для этого есть отдельная библиотека undecorated:\n" 744 | ], 745 | "metadata": { 746 | "id": "TbHfRCjvGNqA" 747 | } 748 | }, 749 | { 750 | "cell_type": "code", 751 | "source": [ 752 | "!pip install undecorated" 753 | ], 754 | "metadata": { 755 | "colab": { 756 | "base_uri": "https://localhost:8080/" 757 | }, 758 | "id": "p1jfkEphGgoE", 759 | "outputId": "0179bdf0-1f6b-407e-a3ef-9a126052ac35" 760 | }, 761 | "execution_count": 52, 762 | "outputs": [ 763 | { 764 | "output_type": "stream", 765 | "name": "stdout", 766 | "text": [ 767 | "Collecting undecorated\n", 768 | " Downloading undecorated-0.3.0-py3-none-any.whl.metadata (2.5 kB)\n", 769 | "Downloading undecorated-0.3.0-py3-none-any.whl (4.8 kB)\n", 770 | "Installing collected packages: undecorated\n", 771 | "Successfully installed undecorated-0.3.0\n" 772 | ] 773 | } 774 | ] 775 | }, 776 | { 777 | "cell_type": "code", 778 | "source": [ 779 | "from undecorated import undecorated\n", 780 | "print(fibonacci(10))\n", 781 | "print('-' * 30)\n", 782 | "f = undecorated(fibonacci)\n", 783 | "f(10)" 784 | ], 785 | "metadata": { 786 | "colab": { 787 | "base_uri": "https://localhost:8080/" 788 | }, 789 | "id": "FOLHbtdlGixs", 790 | "outputId": "b644f621-623c-4d89-c179-fd676b946711" 791 | }, 792 | "execution_count": 57, 793 | "outputs": [ 794 | { 795 | "output_type": "stream", 796 | "name": "stdout", 797 | "text": [ 798 | "Function fibonacci took 4.315376281738282e-06 seconds in 10 iteations\n", 799 | "55\n", 800 | "------------------------------\n" 801 | ] 802 | }, 803 | { 804 | "output_type": "execute_result", 805 | "data": { 806 | "text/plain": [ 807 | "55" 808 | ] 809 | }, 810 | "metadata": {}, 811 | "execution_count": 57 812 | } 813 | ] 814 | }, 815 | { 816 | "cell_type": "markdown", 817 | "source": [ 818 | "## Ломаем мозги - атрибуты функции" 819 | ], 820 | "metadata": { 821 | "id": "n7TmrX88I2jt" 822 | } 823 | }, 824 | { 825 | "cell_type": "markdown", 826 | "source": [ 827 | "Помните, мы говорили, что у классов и объектов класса есть атрибуты? (по сути, где мы можем хранить значения)\n", 828 | "\n", 829 | "Внимание: у функций они тоже ЕСТЬ (https://peps.python.org/pep-0232/)\n", 830 | "\n", 831 | "А это значит, что их тоже можно использовать!\n", 832 | "\n", 833 | "Давайте сделаем новый полезный декоратор, который будет считать число вызовов функции (зачем надо - допустим наша функция обращается к дорогому API, а денег у нас мало)" 834 | ], 835 | "metadata": { 836 | "id": "w4LcyV7iJCNR" 837 | } 838 | }, 839 | { 840 | "cell_type": "code", 841 | "source": [ 842 | "def call_counter(func):\n", 843 | " def helper(*args, **kwargs):\n", 844 | " helper.calls += 1\n", 845 | " return func(*args, **kwargs)\n", 846 | " helper.calls = 0\n", 847 | "\n", 848 | " return helper\n", 849 | "\n", 850 | "@call_counter\n", 851 | "def high_price():\n", 852 | " print(f\"You have paid 100$, goodbye\")\n", 853 | "\n", 854 | "@call_counter\n", 855 | "def super_high_price():\n", 856 | " print(f\"You have paid 1000$, goodbye\")\n", 857 | "\n", 858 | "high_price()\n", 859 | "high_price()\n", 860 | "super_high_price()\n", 861 | "high_price()\n", 862 | "super_high_price()\n", 863 | "print(high_price.calls, super_high_price.calls)" 864 | ], 865 | "metadata": { 866 | "colab": { 867 | "base_uri": "https://localhost:8080/" 868 | }, 869 | "id": "u-NoDdoEJ66v", 870 | "outputId": "3db06d1c-62e5-417d-fdd9-5f2cffac36f1" 871 | }, 872 | "execution_count": 60, 873 | "outputs": [ 874 | { 875 | "output_type": "stream", 876 | "name": "stdout", 877 | "text": [ 878 | "You have paid 100$, goodbye\n", 879 | "You have paid 100$, goodbye\n", 880 | "You have paid 1000$, goodbye\n", 881 | "You have paid 100$, goodbye\n", 882 | "You have paid 1000$, goodbye\n", 883 | "3 2\n" 884 | ] 885 | } 886 | ] 887 | }, 888 | { 889 | "cell_type": "markdown", 890 | "source": [ 891 | "Зачем нам это надо? Ну в целом мы можем использовать параметр, чтобы ограничить число вызовов:" 892 | ], 893 | "metadata": { 894 | "id": "gK57BPg6K5ys" 895 | } 896 | }, 897 | { 898 | "cell_type": "code", 899 | "source": [ 900 | "def call_counter_new(func):\n", 901 | " def helper(*args, **kwargs):\n", 902 | " if helper.calls > 2:\n", 903 | " print(\"No more money\")\n", 904 | " return None\n", 905 | " else:\n", 906 | " helper.calls += 1\n", 907 | " return func(*args, **kwargs)\n", 908 | " helper.calls = 0\n", 909 | "\n", 910 | " return helper\n", 911 | "\n", 912 | "@call_counter_new\n", 913 | "def high_price():\n", 914 | " print(f\"You have paid 100$, goodbye\")\n", 915 | "\n", 916 | "@call_counter_new\n", 917 | "def super_high_price():\n", 918 | " print(f\"You have paid 1000$, goodbye\")\n", 919 | "\n", 920 | "high_price()\n", 921 | "high_price()\n", 922 | "super_high_price()\n", 923 | "high_price()\n", 924 | "super_high_price()\n", 925 | "print(high_price.calls, super_high_price.calls)\n", 926 | "high_price()" 927 | ], 928 | "metadata": { 929 | "colab": { 930 | "base_uri": "https://localhost:8080/" 931 | }, 932 | "id": "7l3S9kLsK_4j", 933 | "outputId": "150cbb9c-065a-4f6f-a681-4c4c4460d329" 934 | }, 935 | "execution_count": 64, 936 | "outputs": [ 937 | { 938 | "output_type": "stream", 939 | "name": "stdout", 940 | "text": [ 941 | "You have paid 100$, goodbye\n", 942 | "You have paid 100$, goodbye\n", 943 | "You have paid 1000$, goodbye\n", 944 | "You have paid 100$, goodbye\n", 945 | "You have paid 1000$, goodbye\n", 946 | "3 2\n", 947 | "No more money\n" 948 | ] 949 | } 950 | ] 951 | }, 952 | { 953 | "cell_type": "markdown", 954 | "source": [ 955 | "Поиграли в капитализм и хватит\n", 956 | "\n", 957 | "В связи с этим есть одна большая проблема - описание и название функций, давайте на нее посмотрим:" 958 | ], 959 | "metadata": { 960 | "id": "bnEdX4CiLZ5G" 961 | } 962 | }, 963 | { 964 | "cell_type": "code", 965 | "source": [ 966 | "def another_super_high_price():\n", 967 | " '''Connect to API, pay money and do smth'''\n", 968 | " print(f\"You have paid 1000$, goodbye\")\n", 969 | "\n", 970 | "another_super_high_price.__doc__ # Наша документация" 971 | ], 972 | "metadata": { 973 | "colab": { 974 | "base_uri": "https://localhost:8080/", 975 | "height": 36 976 | }, 977 | "id": "bfBoX9QzLn5b", 978 | "outputId": "e93ed726-0efe-4cf5-e4f4-9ab790912b4f" 979 | }, 980 | "execution_count": 65, 981 | "outputs": [ 982 | { 983 | "output_type": "execute_result", 984 | "data": { 985 | "text/plain": [ 986 | "'Connect to API, pay money and do smth'" 987 | ], 988 | "application/vnd.google.colaboratory.intrinsic+json": { 989 | "type": "string" 990 | } 991 | }, 992 | "metadata": {}, 993 | "execution_count": 65 994 | } 995 | ] 996 | }, 997 | { 998 | "cell_type": "code", 999 | "source": [ 1000 | "@call_counter_new\n", 1001 | "def another_super_high_price():\n", 1002 | " '''Connect to API, pay money and do smth'''\n", 1003 | " print(f\"You have paid 1000$, goodbye\")\n", 1004 | "\n", 1005 | "print(another_super_high_price.__doc__) # Наша документация, пропала\n", 1006 | "print(another_super_high_price.__name__) # Название функции - пропало\n", 1007 | "print(another_super_high_price.__module__) # В нашей ситуации все в одном месте, но тем не менее, оно тоже пропадет" 1008 | ], 1009 | "metadata": { 1010 | "colab": { 1011 | "base_uri": "https://localhost:8080/" 1012 | }, 1013 | "id": "BuG0BKwoL0O-", 1014 | "outputId": "362b18a6-f659-4c6e-e229-85d6d85801a6" 1015 | }, 1016 | "execution_count": 69, 1017 | "outputs": [ 1018 | { 1019 | "output_type": "stream", 1020 | "name": "stdout", 1021 | "text": [ 1022 | "None\n", 1023 | "helper\n", 1024 | "__main__\n" 1025 | ] 1026 | } 1027 | ] 1028 | }, 1029 | { 1030 | "cell_type": "markdown", 1031 | "source": [ 1032 | "Что же делать? Для этого мы обратимся к замечательной бибилотеке [functools](https://docs.python.org/3/library/functools.html), к которой мы уже обращались за кешем.\n", 1033 | "\n", 1034 | "По существу functools - это библиотека с определенным полезными декраторами, которые можно использовать сразу из коробки. В данном случае нам потребуется wraps - допонлительный декоратор, который нужен для сохранения properties\n", 1035 | "\n", 1036 | "Применяем его, получается, внутри самого декоратора (да, декоратор внутри декоратора, по-моему это гениально):" 1037 | ], 1038 | "metadata": { 1039 | "id": "xA8ZBfe_MNuQ" 1040 | } 1041 | }, 1042 | { 1043 | "cell_type": "code", 1044 | "source": [ 1045 | "from functools import wraps\n", 1046 | "\n", 1047 | "def call_counter_new(func):\n", 1048 | " @wraps(func)\n", 1049 | " def helper(*args, **kwargs):\n", 1050 | " if helper.calls > 2:\n", 1051 | " print(\"No more money\")\n", 1052 | " return None\n", 1053 | " else:\n", 1054 | " helper.calls += 1\n", 1055 | " return func(*args, **kwargs)\n", 1056 | " helper.calls = 0\n", 1057 | "\n", 1058 | " return helper\n", 1059 | "\n", 1060 | "@call_counter_new\n", 1061 | "def another_super_high_price():\n", 1062 | " '''Connect to API, pay money and do smth'''\n", 1063 | " print(f\"You have paid 1000$, goodbye\")\n", 1064 | "\n", 1065 | "print(another_super_high_price.__doc__) # Наша документация, пропала\n", 1066 | "print(another_super_high_price.__name__) # Название функции - пропало\n", 1067 | "print(another_super_high_price.__module__) # В нашей ситуации все в одном месте, но тем не менее, оно тоже пропадет" 1068 | ], 1069 | "metadata": { 1070 | "colab": { 1071 | "base_uri": "https://localhost:8080/" 1072 | }, 1073 | "id": "SYnVSeGTPHGn", 1074 | "outputId": "fee6fc30-5de0-433b-ab3d-bfbac601d5da" 1075 | }, 1076 | "execution_count": 70, 1077 | "outputs": [ 1078 | { 1079 | "output_type": "stream", 1080 | "name": "stdout", 1081 | "text": [ 1082 | "Connect to API, pay money and do smth\n", 1083 | "another_super_high_price\n", 1084 | "__main__\n" 1085 | ] 1086 | } 1087 | ] 1088 | }, 1089 | { 1090 | "cell_type": "markdown", 1091 | "source": [ 1092 | "И вуаля, теперь у нас опять все есть!" 1093 | ], 1094 | "metadata": { 1095 | "id": "nvzP9ISTPVcX" 1096 | } 1097 | }, 1098 | { 1099 | "cell_type": "markdown", 1100 | "source": [ 1101 | "## Применяем несколько декораторов" 1102 | ], 1103 | "metadata": { 1104 | "id": "lQNT3iTJXLlF" 1105 | } 1106 | }, 1107 | { 1108 | "cell_type": "markdown", 1109 | "source": [ 1110 | "Можно ли использовать одновременно несколько декораторов? Вообще можно, почему нет (оборачивать можно сколько душе угодно)\n", 1111 | "\n", 1112 | "Единственное - важен порядок. Зададим достаточно интересную последовательность:" 1113 | ], 1114 | "metadata": { 1115 | "id": "jzmbhKlKXOeS" 1116 | } 1117 | }, 1118 | { 1119 | "cell_type": "code", 1120 | "source": [ 1121 | "def red(fn):\n", 1122 | " fn.color = 'red'\n", 1123 | " return fn\n", 1124 | "\n", 1125 | "def blue(fn):\n", 1126 | " fn.color = 'blue'\n", 1127 | " return fn\n", 1128 | "\n", 1129 | "def change_by_color(f):\n", 1130 | " def helper():\n", 1131 | " if hasattr(f, 'color') and f.color == 'blue':\n", 1132 | " f()\n", 1133 | " else:\n", 1134 | " print(\"Wow\")\n", 1135 | " f()\n", 1136 | " return helper\n", 1137 | "\n", 1138 | "@change_by_color\n", 1139 | "@red\n", 1140 | "def a():\n", 1141 | " print(\"Hello\")\n", 1142 | "\n", 1143 | "@change_by_color\n", 1144 | "@blue\n", 1145 | "def b():\n", 1146 | " print(\"Hi\")" 1147 | ], 1148 | "metadata": { 1149 | "id": "9AwNO5-nXW8S" 1150 | }, 1151 | "execution_count": 87, 1152 | "outputs": [] 1153 | }, 1154 | { 1155 | "cell_type": "code", 1156 | "source": [ 1157 | "a()\n", 1158 | "b()" 1159 | ], 1160 | "metadata": { 1161 | "colab": { 1162 | "base_uri": "https://localhost:8080/" 1163 | }, 1164 | "id": "XeaV8AMsYtiC", 1165 | "outputId": "c575da64-9e78-46d2-8119-d1b47126fb99" 1166 | }, 1167 | "execution_count": 88, 1168 | "outputs": [ 1169 | { 1170 | "output_type": "stream", 1171 | "name": "stdout", 1172 | "text": [ 1173 | "Wow\n", 1174 | "Hello\n", 1175 | "Hi\n" 1176 | ] 1177 | } 1178 | ] 1179 | }, 1180 | { 1181 | "cell_type": "code", 1182 | "source": [ 1183 | "@red\n", 1184 | "@change_by_color\n", 1185 | "def a():\n", 1186 | " print(\"Hello\")\n", 1187 | "\n", 1188 | "@blue\n", 1189 | "@change_by_color\n", 1190 | "def b():\n", 1191 | " print(\"Hi\")" 1192 | ], 1193 | "metadata": { 1194 | "id": "nqQGA71JYU8S" 1195 | }, 1196 | "execution_count": 89, 1197 | "outputs": [] 1198 | }, 1199 | { 1200 | "cell_type": "code", 1201 | "source": [ 1202 | "a()\n", 1203 | "b()" 1204 | ], 1205 | "metadata": { 1206 | "colab": { 1207 | "base_uri": "https://localhost:8080/" 1208 | }, 1209 | "id": "7kzV7EENYu8M", 1210 | "outputId": "40b46480-d3e8-47cb-fda6-c00e937ae9a2" 1211 | }, 1212 | "execution_count": 90, 1213 | "outputs": [ 1214 | { 1215 | "output_type": "stream", 1216 | "name": "stdout", 1217 | "text": [ 1218 | "Wow\n", 1219 | "Hello\n", 1220 | "Wow\n", 1221 | "Hi\n" 1222 | ] 1223 | } 1224 | ] 1225 | }, 1226 | { 1227 | "cell_type": "markdown", 1228 | "source": [ 1229 | "Логика идет снизу вверх (иначе может получить не то, что хотели)" 1230 | ], 1231 | "metadata": { 1232 | "id": "-d8haFJcYzZB" 1233 | } 1234 | }, 1235 | { 1236 | "cell_type": "markdown", 1237 | "source": [ 1238 | "## Вернемся к классам, мы же их зачем-то проходили" 1239 | ], 1240 | "metadata": { 1241 | "id": "-hNVVrMgPfK_" 1242 | } 1243 | }, 1244 | { 1245 | "cell_type": "markdown", 1246 | "source": [ 1247 | "Как вы можете помнить, класс может быть callable (то есть вызываться как функция, используя метод \\_\\_call\\_\\_)\n", 1248 | "\n", 1249 | "А что это значит? Правильно, значит класс можно тоже сделать декоратором!\n", 1250 | "\n", 1251 | "Для того, чтобы класс был декоратором, ему достаточно иметь \\_\\_call\\_\\_ и \\_\\_init\\_\\_, чтобы стать декоратором!\n", 1252 | "\n", 1253 | "Казалось бы, а зачем? А давайте попробуем написать собственный кэш\n" 1254 | ], 1255 | "metadata": { 1256 | "id": "A4cdqTRDPjIj" 1257 | } 1258 | }, 1259 | { 1260 | "cell_type": "code", 1261 | "source": [ 1262 | "from collections import deque\n", 1263 | "\n", 1264 | "class Memoized:\n", 1265 | " def __init__(self, cache_size=100):\n", 1266 | " self.cache_size = cache_size\n", 1267 | " self.call_args_queue = deque()\n", 1268 | " self.call_args_to_result = {}\n", 1269 | "\n", 1270 | " def __call__(self, fn):\n", 1271 | " def new_func(*args, **kwargs):\n", 1272 | " memoization_key = self._convert_call_arguments_to_hash(args, kwargs)\n", 1273 | " if memoization_key not in self.call_args_to_result:\n", 1274 | " result = fn(*args, **kwargs)\n", 1275 | " self._update_cache_key_with_value(memoization_key, result)\n", 1276 | " self._evict_cache_if_necessary()\n", 1277 | " return self.call_args_to_result[memoization_key]\n", 1278 | " return new_func\n", 1279 | "\n", 1280 | " def _update_cache_key_with_value(self, key, value):\n", 1281 | " self.call_args_to_result[key] = value\n", 1282 | " self.call_args_queue.append(key)\n", 1283 | "\n", 1284 | " def _evict_cache_if_necessary(self):\n", 1285 | " if len(self.call_args_queue) > self.cache_size:\n", 1286 | " oldest_key = self.call_args_queue.popleft()\n", 1287 | " del self.call_args_to_result[oldest_key]\n", 1288 | "\n", 1289 | " @staticmethod\n", 1290 | " def _convert_call_arguments_to_hash(args, kwargs):\n", 1291 | " return hash(str(args) + str(kwargs))\n", 1292 | "\n", 1293 | "\n", 1294 | "@Memoized(cache_size=5)\n", 1295 | "def get_not_so_random_number_with_max(max_value):\n", 1296 | " import random\n", 1297 | " return random.random() * max_value" 1298 | ], 1299 | "metadata": { 1300 | "id": "rMQvvNlQUzYI" 1301 | }, 1302 | "execution_count": null, 1303 | "outputs": [] 1304 | }, 1305 | { 1306 | "cell_type": "markdown", 1307 | "source": [ 1308 | "Это можно написать в виде функции, но как будто иногда проще иметь отдельную обертку, в которой будет храниться отдельно все" 1309 | ], 1310 | "metadata": { 1311 | "id": "ScEAVC8xVna6" 1312 | } 1313 | }, 1314 | { 1315 | "cell_type": "markdown", 1316 | "source": [ 1317 | "И финальный тейк: декоратор - это возможность взять нечто вызываемое и получить результат.\n", 1318 | "\n", 1319 | "Если говорить математически, то логика такая:\n", 1320 | "\n", 1321 | "@d и @e - декораторы\n", 1322 | "\n", 1323 | "x - то, что мы хотим передать (функция)\n", 1324 | "\n", 1325 | "Тогда результат декоратора - это d(x), которая, на самом деле, не обязана быть функцией. А результатом применения\n", 1326 | "\n", 1327 | "@e\n", 1328 | "@d\n", 1329 | "def x():\n", 1330 | "\n", 1331 | "Будет, по сути, e(d(x)). И опять-таки, необязательно функция\n", 1332 | "\n", 1333 | " И вот пример:" 1334 | ], 1335 | "metadata": { 1336 | "id": "kPIcXorhZ89H" 1337 | } 1338 | }, 1339 | { 1340 | "cell_type": "code", 1341 | "source": [ 1342 | "def func_name(function):\n", 1343 | " return function.__name__ # Возвращаем строку\n", 1344 | "\n", 1345 | "@len\n", 1346 | "@func_name\n", 1347 | "def nineteen_characters():\n", 1348 | " pass\n", 1349 | "\n", 1350 | "nineteen_characters" 1351 | ], 1352 | "metadata": { 1353 | "colab": { 1354 | "base_uri": "https://localhost:8080/" 1355 | }, 1356 | "id": "w2AtoO0Wa4xt", 1357 | "outputId": "4297e8f5-02a6-40ea-b038-87cd4691decb" 1358 | }, 1359 | "execution_count": 91, 1360 | "outputs": [ 1361 | { 1362 | "output_type": "execute_result", 1363 | "data": { 1364 | "text/plain": [ 1365 | "19" 1366 | ] 1367 | }, 1368 | "metadata": {}, 1369 | "execution_count": 91 1370 | } 1371 | ] 1372 | }, 1373 | { 1374 | "cell_type": "markdown", 1375 | "source": [ 1376 | "Что здесь творится?\n", 1377 | "\n", 1378 | "* func_name - возвращает название функции\n", 1379 | "\n", 1380 | "* len - это длина\n", 1381 | "\n", 1382 | "Берем функцию, из нее получаем строку. Из этой строки мы высчитываем длину!\n", 1383 | "\n", 1384 | "И из этого получается следующее:\n", 1385 | "\n", 1386 | "1. Декоратор не обязан принимать функцию (в нашем случае len() не принимает функцию)\n", 1387 | "\n", 1388 | "2. Декоратор не обязан выдавать функцию (в нашем случае func_name не возращает функцию)\n", 1389 | "\n", 1390 | "Другое дело, чтобы это все работало, все надо запихнуть в функцию)" 1391 | ], 1392 | "metadata": { 1393 | "id": "MOtE0goNbVsV" 1394 | } 1395 | }, 1396 | { 1397 | "cell_type": "markdown", 1398 | "source": [ 1399 | "## Птица дня" 1400 | ], 1401 | "metadata": { 1402 | "id": "-iCtqEWj5D1j" 1403 | } 1404 | }, 1405 | { 1406 | "cell_type": "markdown", 1407 | "source": [ 1408 | "![](https://mtdata.ru/u16/photoE47C/20790968880-0/original.jpeg)" 1409 | ], 1410 | "metadata": { 1411 | "id": "_8BIx7go5YWE" 1412 | } 1413 | }, 1414 | { 1415 | "cell_type": "markdown", 1416 | "source": [ 1417 | "А это кетцаль (тревога: это не попугай!). Священная птица для майя и ацтеков (и в целом для мезоамериканских народов, не зря же Кетцалькоатль)\n", 1418 | "\n", 1419 | "Их ловили, но никогда не убивали. Единственное, что от них было нужно - это красивые перья, которые использовались в качестве украшений и для ритуалов. Их перья были символом власти и сверхъестественного. Местные жители считают, что в неволе птица умирает от разрыва сердца\n", 1420 | "\n", 1421 | "Во времена испанского правления в кетцаль был символом свободы для местных жителей и даже есть легенда, что его грудь и брюхо окрашены кровью павших борцов за независимость. И сейчас в Гватемале это государственный символ (и валюта)" 1422 | ], 1423 | "metadata": { 1424 | "id": "-Gy6RTHD5iRv" 1425 | } 1426 | }, 1427 | { 1428 | "cell_type": "markdown", 1429 | "source": [ 1430 | "![](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Feather_headdress_Moctezuma_II.JPG/1920px-Feather_headdress_Moctezuma_II.JPG)" 1431 | ], 1432 | "metadata": { 1433 | "id": "vJo4sgGG57X-" 1434 | } 1435 | } 1436 | ] 1437 | } -------------------------------------------------------------------------------- /Lectures/Lecture_04.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "source": [ 20 | "# Python-1, Лекция 4\n", 21 | "\n", 22 | "Лекторы: Петров Тимур, Фролов Андрей" 23 | ], 24 | "metadata": { 25 | "id": "vNu_IYXVKq7F" 26 | } 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "source": [ 31 | "Сегодня поговорим про функции и рекурсии" 32 | ], 33 | "metadata": { 34 | "id": "QvBOchSFKwMR" 35 | } 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "source": [ 40 | "## Функции" 41 | ], 42 | "metadata": { 43 | "id": "xGR5BWjwyWFm" 44 | } 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "source": [ 49 | "Что такое функция? Функция - это некоторый объект, который принимает на вход значения и выполняющий некоторые действия (возможно, возвращая что-то). Почему на это нужно обратить внимание?\n", 50 | "\n", 51 | "Внутри многих языков (например, C++) есть разница между *функцией* и *процедурой*. В чем глобальная разница? Функция что-то возвращает, процедура - нет. Так вот:\n", 52 | "\n", 53 | "**В Python между процедурой и функцией нет совершенно никакой разницы**" 54 | ], 55 | "metadata": { 56 | "id": "27ksqJSCy6JC" 57 | } 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "source": [ 62 | "Нотация:\n", 63 | "\n", 64 | "```\n", 65 | "def (args): #название функции (то, что это функция - говорит название def, args - это аргументы)\n", 66 | " \n", 67 | " [return ] #(вернуть какое-то значение)\n", 68 | "```" 69 | ], 70 | "metadata": { 71 | "id": "7IZsyVtbzrpy" 72 | } 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": { 78 | "colab": { 79 | "base_uri": "https://localhost:8080/", 80 | "height": 36 81 | }, 82 | "id": "6C4pHYxJKn23", 83 | "outputId": "bac3ca59-da53-4f6f-e603-b4865e94ff55" 84 | }, 85 | "outputs": [ 86 | { 87 | "output_type": "execute_result", 88 | "data": { 89 | "text/plain": [ 90 | "'Hello!'" 91 | ], 92 | "application/vnd.google.colaboratory.intrinsic+json": { 93 | "type": "string" 94 | } 95 | }, 96 | "metadata": {}, 97 | "execution_count": 1 98 | } 99 | ], 100 | "source": [ 101 | "def hello():\n", 102 | " return \"Hello!\" # В качестве return может быть что угодно\n", 103 | "\n", 104 | "hello()" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "source": [ 110 | "Что такое аргументы и какие они бывают?\n", 111 | "\n", 112 | "Аргументы - это значения, которые принимает функция и использует их\n", 113 | "\n", 114 | "Аргументы бывают:\n", 115 | "\n", 116 | "* позиционные\n", 117 | "\n", 118 | "* именованные\n", 119 | "\n", 120 | "В чем различие? Именованные имеют некоторое значение по умолчанию, позицонные - нет" 121 | ], 122 | "metadata": { 123 | "id": "eQGrAVNZ0G9g" 124 | } 125 | }, 126 | { 127 | "cell_type": "code", 128 | "source": [ 129 | "def hello(name, surname=\"Mr/Mrs\"): # первый аргумент - позиционный, второй - именованный\n", 130 | " return \"Hello, \" + surname + \" \" + name\n", 131 | "\n", 132 | "hello(\"Timur\", \"Petrov\")" 133 | ], 134 | "metadata": { 135 | "colab": { 136 | "base_uri": "https://localhost:8080/", 137 | "height": 36 138 | }, 139 | "id": "RNLflXDq0vJS", 140 | "outputId": "2c309b56-6333-4a12-d569-0aad52e1b7de" 141 | }, 142 | "execution_count": null, 143 | "outputs": [ 144 | { 145 | "output_type": "execute_result", 146 | "data": { 147 | "text/plain": [ 148 | "'Hello, Petrov Timur'" 149 | ], 150 | "application/vnd.google.colaboratory.intrinsic+json": { 151 | "type": "string" 152 | } 153 | }, 154 | "metadata": {}, 155 | "execution_count": 2 156 | } 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "source": [ 162 | "Зачем делать такое различие? На то есть несколько причин:\n", 163 | "\n", 164 | "1. Порядок. Позиционные аргументы всегда идут перед именованными! Также и при вызове: вначале указываем позиционные аргументы, а только потом именованные\n" 165 | ], 166 | "metadata": { 167 | "id": "Q_N-5v9T1CIc" 168 | } 169 | }, 170 | { 171 | "cell_type": "code", 172 | "source": [ 173 | "def hello(surname=\"Mr/Mrs\", name): # первый аргумент - позиционный, второй - именованный\n", 174 | " return \"Hello, \" + surname + \" \" + name\n", 175 | "\n", 176 | "hello(\"Timur\", \"Petrov\")" 177 | ], 178 | "metadata": { 179 | "colab": { 180 | "base_uri": "https://localhost:8080/", 181 | "height": 147 182 | }, 183 | "id": "ObBP7Def1NSO", 184 | "outputId": "52e22db0-5acc-4019-f851-d3f9340b26d0" 185 | }, 186 | "execution_count": null, 187 | "outputs": [ 188 | { 189 | "output_type": "error", 190 | "ename": "SyntaxError", 191 | "evalue": "ignored", 192 | "traceback": [ 193 | "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m def hello(surname=\"Mr/Mrs\", name): # первый аргумент - позиционный, второй - именованный\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m non-default argument follows default argument\n" 194 | ] 195 | } 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "source": [ 201 | "def hello(name, surname=\"Mr/Mrs\"): # первый аргумент - позиционный, второй - именованный\n", 202 | " return \"Hello, \" + surname + \" \" + name\n", 203 | "\n", 204 | "hello(surname = \"Petrov\", \"Timur\")" 205 | ], 206 | "metadata": { 207 | "colab": { 208 | "base_uri": "https://localhost:8080/", 209 | "height": 147 210 | }, 211 | "id": "d7joo66G1Xax", 212 | "outputId": "8584192c-b33a-4a29-a07f-0de8d306af5d" 213 | }, 214 | "execution_count": null, 215 | "outputs": [ 216 | { 217 | "output_type": "error", 218 | "ename": "SyntaxError", 219 | "evalue": "ignored", 220 | "traceback": [ 221 | "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m4\u001b[0m\n\u001b[0;31m hello(surname = \"Petrov\", \"Timur\")\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m positional argument follows keyword argument\n" 222 | ] 223 | } 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "source": [ 229 | "def hello(name, surname=\"Mr/Mrs\"): # первый аргумент - позиционный, второй - именованный\n", 230 | " return \"Hello, \" + surname + \" \" + name\n", 231 | "\n", 232 | "hello(surname = \"Petrov\", name = \"Timur\") # а вот так сработает\n", 233 | "# Вне зависимости от того, позицонные или именованный аргумент, значение можно дать через обращение к названию аргументы" 234 | ], 235 | "metadata": { 236 | "colab": { 237 | "base_uri": "https://localhost:8080/", 238 | "height": 36 239 | }, 240 | "id": "juKQUC0-1dfc", 241 | "outputId": "9231ec70-a729-4c76-a62e-4cb2ea125e2f" 242 | }, 243 | "execution_count": null, 244 | "outputs": [ 245 | { 246 | "output_type": "execute_result", 247 | "data": { 248 | "text/plain": [ 249 | "'Hello, Petrov Timur'" 250 | ], 251 | "application/vnd.google.colaboratory.intrinsic+json": { 252 | "type": "string" 253 | } 254 | }, 255 | "metadata": {}, 256 | "execution_count": 5 257 | } 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "source": [ 263 | "2. Необходимость указывать его при вызове функции. В случае, если для позицонного обязательно надо задать значение, то для именованного - необязательно, тогда он подставит то значение, которое было по дефолту" 264 | ], 265 | "metadata": { 266 | "id": "lCS6smOt1sKx" 267 | } 268 | }, 269 | { 270 | "cell_type": "code", 271 | "source": [ 272 | "def hello(name, surname=\"Mr/Mrs\"): # первый аргумент - позиционный, второй - именованный\n", 273 | " return \"Hello, \" + surname + \" \" + name\n", 274 | "\n", 275 | "hello(\"Timur\")" 276 | ], 277 | "metadata": { 278 | "colab": { 279 | "base_uri": "https://localhost:8080/", 280 | "height": 36 281 | }, 282 | "id": "EUIutSt413GW", 283 | "outputId": "23a083d8-e026-4ccf-f319-9d45b8c5bfd6" 284 | }, 285 | "execution_count": null, 286 | "outputs": [ 287 | { 288 | "output_type": "execute_result", 289 | "data": { 290 | "text/plain": [ 291 | "'Hello, Mr/Mrs Timur'" 292 | ], 293 | "application/vnd.google.colaboratory.intrinsic+json": { 294 | "type": "string" 295 | } 296 | }, 297 | "metadata": {}, 298 | "execution_count": 6 299 | } 300 | ] 301 | }, 302 | { 303 | "cell_type": "markdown", 304 | "source": [ 305 | "Таким образом мы можем задавать определенное число аргументов, которое можно передавать в функцию\n", 306 | "\n", 307 | "Но допустим, что мы передали неизвестное число аргументов, что тогда делать? Для этого еще есть args и kwargs:" 308 | ], 309 | "metadata": { 310 | "id": "nrNz5N5C2B3f" 311 | } 312 | }, 313 | { 314 | "cell_type": "code", 315 | "source": [ 316 | "def func(*args, **kwargs):\n", 317 | " print(args, kwargs)\n", 318 | "\n", 319 | "func(1, 2, 3, 4, a = 5, b = 6)\n", 320 | "\n", 321 | "def func_new(a, b=2, *args, **kwargs):\n", 322 | " print(a, b, args, kwargs)\n", 323 | "\n", 324 | "func_new(1, 3, 4, 5, k = 2, l = 3)" 325 | ], 326 | "metadata": { 327 | "colab": { 328 | "base_uri": "https://localhost:8080/" 329 | }, 330 | "id": "qJ91Twi12Vrf", 331 | "outputId": "e92f75f8-5ba3-4b90-bdb6-397cbf1341b2" 332 | }, 333 | "execution_count": null, 334 | "outputs": [ 335 | { 336 | "output_type": "stream", 337 | "name": "stdout", 338 | "text": [ 339 | "(1, 2, 3, 4) {'a': 5, 'b': 6}\n", 340 | "1 3 (4, 5) {'k': 2, 'l': 3}\n" 341 | ] 342 | } 343 | ] 344 | }, 345 | { 346 | "cell_type": "markdown", 347 | "source": [ 348 | "Что вообще происходит?\n", 349 | "\n", 350 | "*args - принимает все позиционные аргументы, которые не вошли в те значения, которые у нас есть\n", 351 | "\n", 352 | "**kwargs - принимает все именованные аргументы, которые не вошли в те значения, которые у нас есть" 353 | ], 354 | "metadata": { 355 | "id": "fB-JrMqy3k2U" 356 | } 357 | }, 358 | { 359 | "cell_type": "markdown", 360 | "source": [ 361 | "Вопрос на засыпку: что выведет вот этот код?" 362 | ], 363 | "metadata": { 364 | "id": "qdtNLnPI4CwU" 365 | } 366 | }, 367 | { 368 | "cell_type": "code", 369 | "source": [ 370 | "def func_new(a, b=2, *args, **kwargs):\n", 371 | " print(a, b, args, kwargs)\n", 372 | "\n", 373 | "func_new(1, 2, 3, b = 5, k = 2, l = 3)" 374 | ], 375 | "metadata": { 376 | "id": "jlQ0rJHC4FUG" 377 | }, 378 | "execution_count": null, 379 | "outputs": [] 380 | }, 381 | { 382 | "cell_type": "markdown", 383 | "source": [ 384 | "Что такое операция * и **? (args и kwargs - это просто конвенция как их называть, на самом деле можно подставить что угодно)\n", 385 | "\n", 386 | "*-принять в себя переменное число значений\n", 387 | "\n", 388 | "**-принять в себя переменное число именнованных значений" 389 | ], 390 | "metadata": { 391 | "id": "CoBNXwPx5hbW" 392 | } 393 | }, 394 | { 395 | "cell_type": "code", 396 | "source": [ 397 | "a, *b = 1, 2, 3, 4 #не путать с ссылкой, как это работает с C++\n", 398 | "print(a, b)" 399 | ], 400 | "metadata": { 401 | "colab": { 402 | "base_uri": "https://localhost:8080/" 403 | }, 404 | "id": "aVmloB6I54xU", 405 | "outputId": "39b0e0dd-c4a5-4148-c5a1-d01248e12dea" 406 | }, 407 | "execution_count": null, 408 | "outputs": [ 409 | { 410 | "output_type": "stream", 411 | "name": "stdout", 412 | "text": [ 413 | "1 [2, 3, 4]\n" 414 | ] 415 | } 416 | ] 417 | }, 418 | { 419 | "cell_type": "markdown", 420 | "source": [ 421 | "Можно ли вернуть сразу несколько значений? Конечно можно!" 422 | ], 423 | "metadata": { 424 | "id": "c-c3cOab_GFX" 425 | } 426 | }, 427 | { 428 | "cell_type": "code", 429 | "source": [ 430 | "def func(a, b):\n", 431 | " return a + 1, b + 1\n", 432 | "\n", 433 | "func(2, 3) #возвращается кортеж из значений, котоыре вы решили вернуть" 434 | ], 435 | "metadata": { 436 | "colab": { 437 | "base_uri": "https://localhost:8080/" 438 | }, 439 | "id": "VGAxhZJQ_Iq-", 440 | "outputId": "38c6bc6c-0081-4dbd-c52a-12925c1df540" 441 | }, 442 | "execution_count": null, 443 | "outputs": [ 444 | { 445 | "output_type": "execute_result", 446 | "data": { 447 | "text/plain": [ 448 | "(3, 4)" 449 | ] 450 | }, 451 | "metadata": {}, 452 | "execution_count": 42 453 | } 454 | ] 455 | }, 456 | { 457 | "cell_type": "markdown", 458 | "source": [ 459 | "### Локальные и глобальные переменные" 460 | ], 461 | "metadata": { 462 | "id": "0_N4A0CG7Zqy" 463 | } 464 | }, 465 | { 466 | "cell_type": "markdown", 467 | "source": [ 468 | "Каждый раз, когда мы говорим про функции, всегда всплывает вопрос: а какое тут разграничение между локальными и глобальными переменными?" 469 | ], 470 | "metadata": { 471 | "id": "mUjfK66v7dIg" 472 | } 473 | }, 474 | { 475 | "cell_type": "code", 476 | "source": [ 477 | "def f(a, b):\n", 478 | " c = a + b # локальная переменная\n", 479 | " k = [a, b] # локальная переменная\n", 480 | " return c\n", 481 | "\n", 482 | "d = f(1, 2)\n", 483 | "print(c)" 484 | ], 485 | "metadata": { 486 | "colab": { 487 | "base_uri": "https://localhost:8080/", 488 | "height": 222 489 | }, 490 | "id": "0LWu-b_w7kv3", 491 | "outputId": "61817108-dd42-4ba1-8499-74e0f0d59b4f" 492 | }, 493 | "execution_count": null, 494 | "outputs": [ 495 | { 496 | "output_type": "error", 497 | "ename": "NameError", 498 | "evalue": "ignored", 499 | "traceback": [ 500 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 501 | "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", 502 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0md\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 503 | "\u001b[0;31mNameError\u001b[0m: name 'c' is not defined" 504 | ] 505 | } 506 | ] 507 | }, 508 | { 509 | "cell_type": "markdown", 510 | "source": [ 511 | "Все переменные, которые были созданы внутри функции - это локальные переменные (это значит, что вне функции к ним нельзя обратиться).\n", 512 | "\n", 513 | "Что с аргументами?" 514 | ], 515 | "metadata": { 516 | "id": "bzFqwjIU7zen" 517 | } 518 | }, 519 | { 520 | "cell_type": "code", 521 | "source": [ 522 | "def func(a, b, c):\n", 523 | " a += 1\n", 524 | " b += \"a\"\n", 525 | " c.append(15)\n", 526 | " return 42\n", 527 | "\n", 528 | "a = 2\n", 529 | "b = \"a\"\n", 530 | "c = [1, 2]\n", 531 | "print(func(a, b, c))\n", 532 | "print(a, b, c)" 533 | ], 534 | "metadata": { 535 | "colab": { 536 | "base_uri": "https://localhost:8080/" 537 | }, 538 | "id": "0fW8xfLt7-vP", 539 | "outputId": "93e3703a-dfcd-453f-d23d-6b93ad193040" 540 | }, 541 | "execution_count": null, 542 | "outputs": [ 543 | { 544 | "output_type": "stream", 545 | "name": "stdout", 546 | "text": [ 547 | "42\n", 548 | "2 a [1, 2, 15]\n" 549 | ] 550 | } 551 | ] 552 | }, 553 | { 554 | "cell_type": "markdown", 555 | "source": [ 556 | "Хоба, что-то странное. Параметр a и параметр b не изменились, а вот c изменилось. Как так? Ну давайте посмотрим:" 557 | ], 558 | "metadata": { 559 | "id": "3JYBV2yN8T9s" 560 | } 561 | }, 562 | { 563 | "cell_type": "code", 564 | "source": [ 565 | "def func(a, b, c):\n", 566 | " print(\"inside func\")\n", 567 | " print(\"a: \", id(a))\n", 568 | " print(\"b: \", id(b))\n", 569 | " print(\"c: \", id(c))\n", 570 | " a += 1\n", 571 | " b += \"a\"\n", 572 | " c.append(15)\n", 573 | " return 42\n", 574 | "\n", 575 | "a = 2\n", 576 | "b = \"a\"\n", 577 | "c = [1, 2]\n", 578 | "print(\"outside func\")\n", 579 | "print(\"a: \", id(a))\n", 580 | "print(\"b: \", id(b))\n", 581 | "print(\"c: \", id(c))\n", 582 | "print('-' * 30)\n", 583 | "print(func(a, b, c))\n", 584 | "print(a, b, c)" 585 | ], 586 | "metadata": { 587 | "colab": { 588 | "base_uri": "https://localhost:8080/" 589 | }, 590 | "id": "uDzh22dY7rkk", 591 | "outputId": "2faf0fd4-fc93-4075-b91a-a5a442eb1623" 592 | }, 593 | "execution_count": null, 594 | "outputs": [ 595 | { 596 | "output_type": "stream", 597 | "name": "stdout", 598 | "text": [ 599 | "outside func\n", 600 | "a: 137120898351376\n", 601 | "b: 137120897170864\n", 602 | "c: 137119626375808\n", 603 | "------------------------------\n", 604 | "inside func\n", 605 | "a: 137120898351376\n", 606 | "b: 137120897170864\n", 607 | "c: 137119626375808\n", 608 | "42\n", 609 | "2 a [1, 2, 15]\n" 610 | ] 611 | } 612 | ] 613 | }, 614 | { 615 | "cell_type": "markdown", 616 | "source": [ 617 | "Что происходит при передаче аргументов в функцию? Мы передаем ссылку на место, откуда брать данные. А что дальше?\n", 618 | "\n", 619 | "А дальше все зависит от того, является ли объект изменяемым или нет. Если он неизменяемый - то при любой операции мы создаем новый объект. В случае изменяемого - то при операции мы не создаем новый объект\n", 620 | "\n", 621 | "Поэтому в одном случае у нас исходное значение не меняется, а вот в другом - меняется. С этим же связан еще один \"баг\":" 622 | ], 623 | "metadata": { 624 | "id": "BQ0tCTts800j" 625 | } 626 | }, 627 | { 628 | "cell_type": "code", 629 | "source": [ 630 | "def add_product(products=[]):\n", 631 | " print(id(products))\n", 632 | " products.append(\"Jiafey sexy product\")\n", 633 | " return products\n", 634 | "\n", 635 | "print(add_product())" 636 | ], 637 | "metadata": { 638 | "colab": { 639 | "base_uri": "https://localhost:8080/" 640 | }, 641 | "id": "b7pLGImT9YmV", 642 | "outputId": "142bda87-9e60-4abd-82ae-faef1295a28f" 643 | }, 644 | "execution_count": null, 645 | "outputs": [ 646 | { 647 | "output_type": "stream", 648 | "name": "stdout", 649 | "text": [ 650 | "137120196726784\n", 651 | "['Jiafey sexy product']\n" 652 | ] 653 | } 654 | ] 655 | }, 656 | { 657 | "cell_type": "code", 658 | "source": [ 659 | "print(add_product())" 660 | ], 661 | "metadata": { 662 | "colab": { 663 | "base_uri": "https://localhost:8080/" 664 | }, 665 | "id": "6nKkky9j9rKy", 666 | "outputId": "95b5cae4-aa14-4a03-8de3-d83a226c444e" 667 | }, 668 | "execution_count": null, 669 | "outputs": [ 670 | { 671 | "output_type": "stream", 672 | "name": "stdout", 673 | "text": [ 674 | "137120196726784\n", 675 | "['Jiafey sexy product', 'Jiafey sexy product']\n" 676 | ] 677 | } 678 | ] 679 | }, 680 | { 681 | "cell_type": "markdown", 682 | "source": [ 683 | "Зашибись, правда? Дефолтное значение имеет свою ячейку памяти! А это значит, что если в качестве дефолтного параметра передать что-то изменяемое, то вот, пожалуйста, оно будет храниться. Как с этим бороться?" 684 | ], 685 | "metadata": { 686 | "id": "NfX-VIwm941f" 687 | } 688 | }, 689 | { 690 | "cell_type": "code", 691 | "source": [ 692 | "def add_product(products=None):\n", 693 | " if products is None:\n", 694 | " products = [] # так мы всегда уверены, что создаем новый список\n", 695 | " print(id(products))\n", 696 | " products.append(\"Jiafey sexy product\")\n", 697 | " return products\n", 698 | "\n", 699 | "print(add_product())\n", 700 | "print(add_product())" 701 | ], 702 | "metadata": { 703 | "colab": { 704 | "base_uri": "https://localhost:8080/" 705 | }, 706 | "id": "o5FIEVHA-ePu", 707 | "outputId": "f562b702-0927-4348-dd1c-dc18921ed6de" 708 | }, 709 | "execution_count": null, 710 | "outputs": [ 711 | { 712 | "output_type": "stream", 713 | "name": "stdout", 714 | "text": [ 715 | "137119627370496\n", 716 | "['Jiafey sexy product']\n", 717 | "137119626810432\n", 718 | "['Jiafey sexy product']\n" 719 | ] 720 | } 721 | ] 722 | }, 723 | { 724 | "cell_type": "markdown", 725 | "source": [ 726 | "Продолжаем с локальными и глобальными переменными:" 727 | ], 728 | "metadata": { 729 | "id": "FbMt_U7__aKV" 730 | } 731 | }, 732 | { 733 | "cell_type": "code", 734 | "source": [ 735 | "def country():\n", 736 | " s = \"USA\" # здесь локальная\n", 737 | " print(s)\n", 738 | "\n", 739 | "s = \"Russia\"\n", 740 | "country()\n", 741 | "print(s) #здесь глобальная" 742 | ], 743 | "metadata": { 744 | "colab": { 745 | "base_uri": "https://localhost:8080/" 746 | }, 747 | "id": "XEtO_jtmBH2r", 748 | "outputId": "0d6e898a-2616-4c34-c101-1ffd9aeb9c37" 749 | }, 750 | "execution_count": null, 751 | "outputs": [ 752 | { 753 | "output_type": "stream", 754 | "name": "stdout", 755 | "text": [ 756 | "USA\n", 757 | "Russia\n" 758 | ] 759 | } 760 | ] 761 | }, 762 | { 763 | "cell_type": "code", 764 | "source": [ 765 | "def country():\n", 766 | " print(s) # Выведет ошибку, потому что видит, что такая локальная переменная будет\n", 767 | " s = \"USA\" # здесь локальная\n", 768 | " print(s)\n", 769 | "\n", 770 | "s = \"Russia\"\n", 771 | "country()\n", 772 | "print(s) #здесь глобальная" 773 | ], 774 | "metadata": { 775 | "colab": { 776 | "base_uri": "https://localhost:8080/", 777 | "height": 373 778 | }, 779 | "id": "F8oJtqJkBTtE", 780 | "outputId": "b0e0ac72-7323-4d77-fcc3-3cb46915cc49" 781 | }, 782 | "execution_count": null, 783 | "outputs": [ 784 | { 785 | "output_type": "error", 786 | "ename": "UnboundLocalError", 787 | "evalue": "ignored", 788 | "traceback": [ 789 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 790 | "\u001b[0;31mUnboundLocalError\u001b[0m Traceback (most recent call last)", 791 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0ms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"Russia\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mcountry\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\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", 792 | "\u001b[0;32m\u001b[0m in \u001b[0;36mcountry\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcountry\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0ms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"USA\"\u001b[0m \u001b[0;31m# здесь локальная\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 793 | "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 's' referenced before assignment" 794 | ] 795 | } 796 | ] 797 | }, 798 | { 799 | "cell_type": "code", 800 | "source": [ 801 | "def country():\n", 802 | " print(s) # Если локальной нет, то выведет глобальную\n", 803 | "\n", 804 | "s = \"Russia\"\n", 805 | "country()\n", 806 | "print(s) #здесь глобальная" 807 | ], 808 | "metadata": { 809 | "colab": { 810 | "base_uri": "https://localhost:8080/" 811 | }, 812 | "id": "0xXQ7y1OBZck", 813 | "outputId": "da44efef-df6a-4ed3-90b4-9cb8f7c02b5b" 814 | }, 815 | "execution_count": null, 816 | "outputs": [ 817 | { 818 | "output_type": "stream", 819 | "name": "stdout", 820 | "text": [ 821 | "Russia\n", 822 | "Russia\n" 823 | ] 824 | } 825 | ] 826 | }, 827 | { 828 | "cell_type": "markdown", 829 | "source": [ 830 | "Что здесь важно? Функция \"просматривает\" локальные переменные, и если такая переменная есть, то она считается только локальной. Если такой нет, то берем глобальную\n", 831 | "\n", 832 | "Что можно сделать? Отдельно объявить переменную \"глобальной\" (но делая ее глобальной, учитывайте, что она будет меняться и вне)" 833 | ], 834 | "metadata": { 835 | "id": "s_5nQSoBBfCw" 836 | } 837 | }, 838 | { 839 | "cell_type": "code", 840 | "source": [ 841 | "def country():\n", 842 | " global s\n", 843 | " print(s)\n", 844 | " s = \"USA\"\n", 845 | " print(s)\n", 846 | "\n", 847 | "s = \"Russia\"\n", 848 | "country()\n", 849 | "print(s) #здесь глобальная" 850 | ], 851 | "metadata": { 852 | "colab": { 853 | "base_uri": "https://localhost:8080/" 854 | }, 855 | "id": "3Qj9FtggByCT", 856 | "outputId": "ed7f5f8c-cc56-4af5-ec5b-b56da34411a8" 857 | }, 858 | "execution_count": null, 859 | "outputs": [ 860 | { 861 | "output_type": "stream", 862 | "name": "stdout", 863 | "text": [ 864 | "Russia\n", 865 | "USA\n", 866 | "USA\n" 867 | ] 868 | } 869 | ] 870 | }, 871 | { 872 | "cell_type": "markdown", 873 | "source": [ 874 | "### DocString" 875 | ], 876 | "metadata": { 877 | "id": "D3J8wqBmd27e" 878 | } 879 | }, 880 | { 881 | "cell_type": "markdown", 882 | "source": [ 883 | "Мы написали кучу функций, порадовались, закрыли проект. Приходит через неделю новый человек, которому надо в вашем коде что-то исправить или в целом использовать ваш код. Он смотрит на функции... И ничего не понимает: что, куда, как использовать. Что же делать?\n", 884 | "\n", 885 | "Наверное, нужно как-то описать функцию (помимо названия). Для этого существуют docstringи! Что это такое?\n", 886 | "\n", 887 | "Это описание функции!" 888 | ], 889 | "metadata": { 890 | "id": "csMdfUsVd4x1" 891 | } 892 | }, 893 | { 894 | "cell_type": "code", 895 | "source": [ 896 | "def f(x):\n", 897 | " ''' Add 1 to our number''' # вот это docstring\n", 898 | " return x + 1\n", 899 | "\n", 900 | "print(f(0))" 901 | ], 902 | "metadata": { 903 | "colab": { 904 | "base_uri": "https://localhost:8080/" 905 | }, 906 | "id": "k3wMbcROeQOX", 907 | "outputId": "9f4743fd-e830-4574-c240-fd7b6fcd5852" 908 | }, 909 | "execution_count": null, 910 | "outputs": [ 911 | { 912 | "output_type": "stream", 913 | "name": "stdout", 914 | "text": [ 915 | "1\n" 916 | ] 917 | } 918 | ] 919 | }, 920 | { 921 | "cell_type": "markdown", 922 | "source": [ 923 | "Для большинства функций всегда есть docstring:" 924 | ], 925 | "metadata": { 926 | "id": "Kr3MqjOzedBd" 927 | } 928 | }, 929 | { 930 | "cell_type": "code", 931 | "source": [ 932 | "import numpy as np\n", 933 | "\n", 934 | "np.dot()" 935 | ], 936 | "metadata": { 937 | "id": "JFgi2qwjegi_" 938 | }, 939 | "execution_count": null, 940 | "outputs": [] 941 | }, 942 | { 943 | "cell_type": "markdown", 944 | "source": [ 945 | "### Лямбда-функции" 946 | ], 947 | "metadata": { 948 | "id": "NtYyEBzq7Jzz" 949 | } 950 | }, 951 | { 952 | "cell_type": "markdown", 953 | "source": [ 954 | "Иногда наши фукции состоят из всего 1 строки, типа такого:" 955 | ], 956 | "metadata": { 957 | "id": "8HssTw237Lnl" 958 | } 959 | }, 960 | { 961 | "cell_type": "code", 962 | "source": [ 963 | "def pol(x, a, b, c):\n", 964 | " return a * x ** 2 + b * x + c\n", 965 | "\n", 966 | "def make_input(s):\n", 967 | " return list(map(int, s.split()))\n", 968 | "\n", 969 | "print(pol(1, 2, 3, 4))\n", 970 | "print(make_input(\"1 2 3 4\"))" 971 | ], 972 | "metadata": { 973 | "colab": { 974 | "base_uri": "https://localhost:8080/" 975 | }, 976 | "id": "KlZCEXLUCydG", 977 | "outputId": "9d74334e-50bd-4a20-f2bf-e60e9d63e054" 978 | }, 979 | "execution_count": null, 980 | "outputs": [ 981 | { 982 | "output_type": "stream", 983 | "name": "stdout", 984 | "text": [ 985 | "9\n", 986 | "[1, 2, 3, 4]\n" 987 | ] 988 | } 989 | ] 990 | }, 991 | { 992 | "cell_type": "markdown", 993 | "source": [ 994 | "Делать для нее отдельное название - удлинять код (хоть и выглядит достаточно логично и читабельно). Вот для таких штук созданы так называемые анонимные (или лямбда) функции. Как это выглядит?\n", 995 | "\n", 996 | "```\n", 997 | "lambda : \n", 998 | "```\n", 999 | "\n", 1000 | "Для чего это удобно? Например, в ситуации, когда функция требуется нам всего лишь один раз" 1001 | ], 1002 | "metadata": { 1003 | "id": "OFwv25grC_DS" 1004 | } 1005 | }, 1006 | { 1007 | "cell_type": "code", 1008 | "source": [ 1009 | "import math as m\n", 1010 | "\n", 1011 | "a = lambda x: x + m.sin(x)\n", 1012 | "print(a(5))" 1013 | ], 1014 | "metadata": { 1015 | "colab": { 1016 | "base_uri": "https://localhost:8080/" 1017 | }, 1018 | "id": "XPXUPeozD4VS", 1019 | "outputId": "a668da3a-a596-491e-e614-c946c5816cd6" 1020 | }, 1021 | "execution_count": null, 1022 | "outputs": [ 1023 | { 1024 | "output_type": "stream", 1025 | "name": "stdout", 1026 | "text": [ 1027 | "4.041075725336862\n" 1028 | ] 1029 | } 1030 | ] 1031 | }, 1032 | { 1033 | "cell_type": "markdown", 1034 | "source": [ 1035 | "Чем это удобно? Допустим, что у нас есть ввод, содержащий числа, а нам надо вывести все квадраты чисел\n", 1036 | "\n", 1037 | "Решаем традиционным способом:" 1038 | ], 1039 | "metadata": { 1040 | "id": "BY7gzmfbErhi" 1041 | } 1042 | }, 1043 | { 1044 | "cell_type": "code", 1045 | "source": [ 1046 | "%%time\n", 1047 | "\n", 1048 | "s = '1 2 3 4 5 6 7 8 9 10'\n", 1049 | "res = list(map(int, s.split()))\n", 1050 | "for i in range(0, len(res)):\n", 1051 | " res[i] **= 2\n", 1052 | "print(res)" 1053 | ], 1054 | "metadata": { 1055 | "colab": { 1056 | "base_uri": "https://localhost:8080/" 1057 | }, 1058 | "id": "bgM7FeU-Ewar", 1059 | "outputId": "e5518b99-6228-411d-f6d9-c1ee6e6de5a2" 1060 | }, 1061 | "execution_count": null, 1062 | "outputs": [ 1063 | { 1064 | "output_type": "stream", 1065 | "name": "stdout", 1066 | "text": [ 1067 | "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]\n", 1068 | "CPU times: user 0 ns, sys: 924 µs, total: 924 µs\n", 1069 | "Wall time: 821 µs\n" 1070 | ] 1071 | } 1072 | ] 1073 | }, 1074 | { 1075 | "cell_type": "markdown", 1076 | "source": [ 1077 | "Делать лишний for - ну такое. А давайте вот так:" 1078 | ], 1079 | "metadata": { 1080 | "id": "mVhfJe_xFJJf" 1081 | } 1082 | }, 1083 | { 1084 | "cell_type": "code", 1085 | "source": [ 1086 | "%%time\n", 1087 | "\n", 1088 | "s = '1 2 3 4 5 6 7 8 9 10'\n", 1089 | "res = list(map(lambda x: int(x) ** 2, s.split()))\n", 1090 | "print(res)" 1091 | ], 1092 | "metadata": { 1093 | "colab": { 1094 | "base_uri": "https://localhost:8080/" 1095 | }, 1096 | "id": "6PuQLpwCFNJ0", 1097 | "outputId": "7316ab7c-7fb7-49fe-fb9c-a1b51914b37e" 1098 | }, 1099 | "execution_count": null, 1100 | "outputs": [ 1101 | { 1102 | "output_type": "stream", 1103 | "name": "stdout", 1104 | "text": [ 1105 | "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]\n", 1106 | "CPU times: user 120 µs, sys: 0 ns, total: 120 µs\n", 1107 | "Wall time: 125 µs\n" 1108 | ] 1109 | } 1110 | ] 1111 | }, 1112 | { 1113 | "cell_type": "markdown", 1114 | "source": [ 1115 | "Хоба! А мы тут функцию написали, и все сработало! (А еще лямбда-функция в целом быстрее)" 1116 | ], 1117 | "metadata": { 1118 | "id": "2Hx93hhmFxaM" 1119 | } 1120 | }, 1121 | { 1122 | "cell_type": "code", 1123 | "source": [ 1124 | "%%time\n", 1125 | "\n", 1126 | "def f(x):\n", 1127 | " return int(x) ** 2\n", 1128 | "\n", 1129 | "s = '1 2 3 4 5 6 7 8 9 10'\n", 1130 | "res = list(map(f, s.split()))\n", 1131 | "print(res)" 1132 | ], 1133 | "metadata": { 1134 | "colab": { 1135 | "base_uri": "https://localhost:8080/" 1136 | }, 1137 | "id": "s-_nNRODF0zw", 1138 | "outputId": "686125e3-3234-43f6-8aea-09e016f9f7a0" 1139 | }, 1140 | "execution_count": null, 1141 | "outputs": [ 1142 | { 1143 | "output_type": "stream", 1144 | "name": "stdout", 1145 | "text": [ 1146 | "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]\n", 1147 | "CPU times: user 485 µs, sys: 30 µs, total: 515 µs\n", 1148 | "Wall time: 465 µs\n" 1149 | ] 1150 | } 1151 | ] 1152 | }, 1153 | { 1154 | "cell_type": "markdown", 1155 | "source": [ 1156 | "Для каких еще функций хорошо подходят лямбда-функции? Разберем еще 2 функции:\n", 1157 | "\n", 1158 | "* filter(f, values) - отфильтровать значения с помощью функции f" 1159 | ], 1160 | "metadata": { 1161 | "id": "abnYKO-MDdCs" 1162 | } 1163 | }, 1164 | { 1165 | "cell_type": "code", 1166 | "source": [ 1167 | "a = [1, 2, 3, 4, 5]\n", 1168 | "list(filter(lambda x: (x % 3 == 0) or (x % 2 == 0), a))" 1169 | ], 1170 | "metadata": { 1171 | "colab": { 1172 | "base_uri": "https://localhost:8080/" 1173 | }, 1174 | "id": "RAZkRnpGEh8W", 1175 | "outputId": "96ea504d-a1bf-4689-f7c9-9ddb8c428097" 1176 | }, 1177 | "execution_count": null, 1178 | "outputs": [ 1179 | { 1180 | "output_type": "execute_result", 1181 | "data": { 1182 | "text/plain": [ 1183 | "[2, 3, 4]" 1184 | ] 1185 | }, 1186 | "metadata": {}, 1187 | "execution_count": 9 1188 | } 1189 | ] 1190 | }, 1191 | { 1192 | "cell_type": "markdown", 1193 | "source": [ 1194 | "* reduce(f, values) - поэлементная операция. Тут проще пояснить на примере (эту функцию ненавид даже создатель Python, Гвидо ван Россум)" 1195 | ], 1196 | "metadata": { 1197 | "id": "1fGXTcqlEItj" 1198 | } 1199 | }, 1200 | { 1201 | "cell_type": "code", 1202 | "source": [ 1203 | "from functools import reduce\n", 1204 | "\n", 1205 | "a = [1, 2, 3, 4, 5]\n", 1206 | "reduce(lambda x, y: x + y, a) #аналогично сумме всех элементов в списке" 1207 | ], 1208 | "metadata": { 1209 | "colab": { 1210 | "base_uri": "https://localhost:8080/" 1211 | }, 1212 | "id": "lJ9tnlBwEtE2", 1213 | "outputId": "7224cde5-0284-4e7d-8b6f-2db1e0c4df3e" 1214 | }, 1215 | "execution_count": null, 1216 | "outputs": [ 1217 | { 1218 | "output_type": "execute_result", 1219 | "data": { 1220 | "text/plain": [ 1221 | "15" 1222 | ] 1223 | }, 1224 | "metadata": {}, 1225 | "execution_count": 6 1226 | } 1227 | ] 1228 | }, 1229 | { 1230 | "cell_type": "code", 1231 | "source": [ 1232 | "a = [1, 2, 3, 4, 5]\n", 1233 | "reduce(lambda x, y: x + y if x + y < 5 else 5, a)" 1234 | ], 1235 | "metadata": { 1236 | "colab": { 1237 | "base_uri": "https://localhost:8080/" 1238 | }, 1239 | "id": "ZRgIXLI-FfoR", 1240 | "outputId": "390d9d2b-c43e-4659-fc5d-35d6fc6041f4" 1241 | }, 1242 | "execution_count": null, 1243 | "outputs": [ 1244 | { 1245 | "output_type": "execute_result", 1246 | "data": { 1247 | "text/plain": [ 1248 | "5" 1249 | ] 1250 | }, 1251 | "metadata": {}, 1252 | "execution_count": 10 1253 | } 1254 | ] 1255 | }, 1256 | { 1257 | "cell_type": "markdown", 1258 | "source": [ 1259 | "## Рекурсия" 1260 | ], 1261 | "metadata": { 1262 | "id": "cMWicYHVyXcx" 1263 | } 1264 | }, 1265 | { 1266 | "cell_type": "markdown", 1267 | "source": [ 1268 | "Итак, у нас теперь есть функции, а значит мы можем делать рекурсии!\n", 1269 | "\n", 1270 | "Что такое рекурсия? Это функция, которая вызывает сама себя. А зачем это надо?\n", 1271 | "\n", 1272 | "Давайте разберем следующую задачу:\n", 1273 | "\n", 1274 | "У нас есть доска, 8x8. И есть кузнечик, который начинает в левом нижнем углу. он умеет ходить только на один шаг вправо или на 1 шаг вверх. Сколько вариантов у кузнечика дойти до правого верхнего угла?\n", 1275 | "\n", 1276 | "Вот здесь нам и помогают рекурсии!" 1277 | ], 1278 | "metadata": { 1279 | "id": "STGzQ6j-EoVk" 1280 | } 1281 | }, 1282 | { 1283 | "cell_type": "code", 1284 | "source": [ 1285 | "def jump_comb(f_x = 0, f_y = 0, l_x = 7, l_y = 7):\n", 1286 | " if (f_x == l_x) and (f_y == l_y):\n", 1287 | " return 1\n", 1288 | " elif f_x == l_x:\n", 1289 | " return jump_comb(f_x, f_y + 1, l_x, l_y)\n", 1290 | " elif f_y == l_y:\n", 1291 | " return jump_comb(f_x + 1, f_y, l_x, l_y)\n", 1292 | " return jump_comb(f_x + 1, f_y, l_x, l_y) + jump_comb(f_x, f_y + 1, l_x, l_y)\n", 1293 | "\n", 1294 | "print(jump_comb())" 1295 | ], 1296 | "metadata": { 1297 | "colab": { 1298 | "base_uri": "https://localhost:8080/" 1299 | }, 1300 | "id": "W2aBSj-4VDs0", 1301 | "outputId": "af5716ee-573f-4498-bce7-d799e129231e" 1302 | }, 1303 | "execution_count": null, 1304 | "outputs": [ 1305 | { 1306 | "output_type": "stream", 1307 | "name": "stdout", 1308 | "text": [ 1309 | "3432\n" 1310 | ] 1311 | } 1312 | ] 1313 | }, 1314 | { 1315 | "cell_type": "markdown", 1316 | "source": [ 1317 | "То есть это хорошо работает в ситуациях, когда у нас решение задачи зависит от решения **подзадач**, которые по существу то же самое, но с другим набором начальнго положения. Что важно для рекурсии?\n", 1318 | "\n", 1319 | "* Наличие критерия остановы (то есть некоторой ситуации, когда рекурсия кончается)\n", 1320 | "\n", 1321 | "* Решение исходной задачи зависит от подзадач" 1322 | ], 1323 | "metadata": { 1324 | "id": "WGKIHYx_V9Te" 1325 | } 1326 | }, 1327 | { 1328 | "cell_type": "markdown", 1329 | "source": [ 1330 | "Что нам важно в контексте Python с точки зрения рекурсии?\n", 1331 | "\n", 1332 | "Давайте попробуем запустить вот такой код:" 1333 | ], 1334 | "metadata": { 1335 | "id": "6AwNOFU6WYV3" 1336 | } 1337 | }, 1338 | { 1339 | "cell_type": "code", 1340 | "source": [ 1341 | "def add(x):\n", 1342 | " if x == 10000:\n", 1343 | " return x\n", 1344 | " return add(x + 1)\n", 1345 | "\n", 1346 | "add(0)" 1347 | ], 1348 | "metadata": { 1349 | "colab": { 1350 | "base_uri": "https://localhost:8080/", 1351 | "height": 416 1352 | }, 1353 | "id": "HD7AddMEWip5", 1354 | "outputId": "cdd24da9-e900-41a3-88ed-0d22f280bbad" 1355 | }, 1356 | "execution_count": null, 1357 | "outputs": [ 1358 | { 1359 | "output_type": "error", 1360 | "ename": "RecursionError", 1361 | "evalue": "ignored", 1362 | "traceback": [ 1363 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 1364 | "\u001b[0;31mRecursionError\u001b[0m Traceback (most recent call last)", 1365 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 1366 | "\u001b[0;32m\u001b[0m in \u001b[0;36madd\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m10000\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 1367 | "... last 1 frames repeated, from the frame below ...\n", 1368 | "\u001b[0;32m\u001b[0m in \u001b[0;36madd\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m10000\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 1369 | "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded in comparison" 1370 | ] 1371 | } 1372 | ] 1373 | }, 1374 | { 1375 | "cell_type": "markdown", 1376 | "source": [ 1377 | "Код валидный, все нормально работает, что пошло не так? Внутри Python есть ограничение на глубину рекурсий (то есть сколько можно вызвать внутри себя функцию)" 1378 | ], 1379 | "metadata": { 1380 | "id": "V0J-IZSvWqhb" 1381 | } 1382 | }, 1383 | { 1384 | "cell_type": "code", 1385 | "source": [ 1386 | "import sys #библиотека sys позволяет посмотреть на различные специфические для системы значения\n", 1387 | "# Более подробно: https://docs.python.org/3/library/sys.html\n", 1388 | "\n", 1389 | "print(sys.getrecursionlimit()) # позволяет получить максимальную глубину рекурсии" 1390 | ], 1391 | "metadata": { 1392 | "colab": { 1393 | "base_uri": "https://localhost:8080/" 1394 | }, 1395 | "id": "XjpAjjpyW4uH", 1396 | "outputId": "fb754e5e-9217-4110-a2cc-0bacebdad9db" 1397 | }, 1398 | "execution_count": null, 1399 | "outputs": [ 1400 | { 1401 | "output_type": "stream", 1402 | "name": "stdout", 1403 | "text": [ 1404 | "1000\n" 1405 | ] 1406 | } 1407 | ] 1408 | }, 1409 | { 1410 | "cell_type": "markdown", 1411 | "source": [ 1412 | "Внутреннее ограничение Python - 1000 (где-то может быть другим, можете посмотреть у себя, но обычно 1000)\n", 1413 | "\n", 1414 | "Допустим, что мы с вами знаем, что нам нужно больше (точно нельзя лучше). Что тогда делать? Праивльно - установить собственный лимит!" 1415 | ], 1416 | "metadata": { 1417 | "id": "CxRCSaZGW5rx" 1418 | } 1419 | }, 1420 | { 1421 | "cell_type": "code", 1422 | "source": [ 1423 | "sys.setrecursionlimit(100000)\n", 1424 | "print(sys.getrecursionlimit())" 1425 | ], 1426 | "metadata": { 1427 | "colab": { 1428 | "base_uri": "https://localhost:8080/" 1429 | }, 1430 | "id": "vOUn6lrfXYX8", 1431 | "outputId": "1dce6041-ee57-471f-e64a-fd6e8edb8383" 1432 | }, 1433 | "execution_count": null, 1434 | "outputs": [ 1435 | { 1436 | "output_type": "stream", 1437 | "name": "stdout", 1438 | "text": [ 1439 | "100000\n" 1440 | ] 1441 | } 1442 | ] 1443 | }, 1444 | { 1445 | "cell_type": "code", 1446 | "source": [ 1447 | "def add(x):\n", 1448 | " if x == 10000:\n", 1449 | " return x\n", 1450 | " return add(x + 1)\n", 1451 | "\n", 1452 | "add(0)" 1453 | ], 1454 | "metadata": { 1455 | "colab": { 1456 | "base_uri": "https://localhost:8080/" 1457 | }, 1458 | "id": "QsT6ULYTXdHg", 1459 | "outputId": "fb984192-2d9e-4835-8902-f62a7963fa35" 1460 | }, 1461 | "execution_count": null, 1462 | "outputs": [ 1463 | { 1464 | "output_type": "execute_result", 1465 | "data": { 1466 | "text/plain": [ 1467 | "10000" 1468 | ] 1469 | }, 1470 | "metadata": {}, 1471 | "execution_count": 72 1472 | } 1473 | ] 1474 | }, 1475 | { 1476 | "cell_type": "markdown", 1477 | "source": [ 1478 | "А вот теперь запустилось!\n", 1479 | "\n", 1480 | "Какие есть плюсы у рекурсии? Это достаточно просто написать)\n", 1481 | "\n", 1482 | "Какие минусы у рекурсии? Скорость\n", 1483 | "\n", 1484 | "То есть система запускает много вызов, их надо поддерживать, следить и так далее. Поэтому если вы знаете, что можно что-то сделать не рекурсией, то не делайте так\n", 1485 | "\n", 1486 | "На примере вычисления чисел Фибоначчи:" 1487 | ], 1488 | "metadata": { 1489 | "id": "DTYddAqHXe22" 1490 | } 1491 | }, 1492 | { 1493 | "cell_type": "code", 1494 | "source": [ 1495 | "def recursive_fib(n):\n", 1496 | " if n in (1, 2):\n", 1497 | " return 1\n", 1498 | " return recursive_fib(n - 1) + recursive_fib(n - 2)\n", 1499 | "\n", 1500 | "def func_fib(n):\n", 1501 | " if n in (1, 2):\n", 1502 | " return 1\n", 1503 | " res = [0 for _ in range(n)]\n", 1504 | " res[0], res[1] = 1, 1\n", 1505 | " for i in range(2, n):\n", 1506 | " res[i] = res[i - 1] + res[i - 2]\n", 1507 | " return res[n - 1]" 1508 | ], 1509 | "metadata": { 1510 | "id": "9T9FJjZxX_bF" 1511 | }, 1512 | "execution_count": null, 1513 | "outputs": [] 1514 | }, 1515 | { 1516 | "cell_type": "code", 1517 | "source": [ 1518 | "%%time\n", 1519 | "\n", 1520 | "print(recursive_fib(30))" 1521 | ], 1522 | "metadata": { 1523 | "colab": { 1524 | "base_uri": "https://localhost:8080/" 1525 | }, 1526 | "id": "ZJF1QaKxYtbP", 1527 | "outputId": "4c95d150-3eb2-4a41-92c2-821170170fd3" 1528 | }, 1529 | "execution_count": null, 1530 | "outputs": [ 1531 | { 1532 | "output_type": "stream", 1533 | "name": "stdout", 1534 | "text": [ 1535 | "832040\n", 1536 | "CPU times: user 226 ms, sys: 0 ns, total: 226 ms\n", 1537 | "Wall time: 230 ms\n" 1538 | ] 1539 | } 1540 | ] 1541 | }, 1542 | { 1543 | "cell_type": "code", 1544 | "source": [ 1545 | "%%time\n", 1546 | "\n", 1547 | "print(func_fib(30))" 1548 | ], 1549 | "metadata": { 1550 | "colab": { 1551 | "base_uri": "https://localhost:8080/" 1552 | }, 1553 | "id": "Y3VQn2nGYyjt", 1554 | "outputId": "75ea45db-83af-4aad-e09d-51563fd1cf26" 1555 | }, 1556 | "execution_count": null, 1557 | "outputs": [ 1558 | { 1559 | "output_type": "stream", 1560 | "name": "stdout", 1561 | "text": [ 1562 | "832040\n", 1563 | "CPU times: user 1.87 ms, sys: 0 ns, total: 1.87 ms\n", 1564 | "Wall time: 1.87 ms\n" 1565 | ] 1566 | } 1567 | ] 1568 | }, 1569 | { 1570 | "cell_type": "markdown", 1571 | "source": [ 1572 | "Разница в 200 раз... Ну вот как-то так)\n", 1573 | "\n", 1574 | "Можно ли каким-нибудь образом ускорить выполнение рекурсивной функции? На самом деле да, если мы будем запоминать те подфункции, которые уже выполняли (обычно это и называется динамическим программированием)\n", 1575 | "\n", 1576 | "Внутри Python есть замечательная библиотека, которая называется [functools](https://docs.python.org/3/library/functools.html), внутри которого есть несколько полезных декораторов (про них мы будем говорить позже)\n", 1577 | "\n", 1578 | "Что нам сейчас важно? Что есть вот такая штука, как @cache и @lru_cache (least recent used cache). Что она делает? Запоминает результаты вызова функции и если мы делаем вызов, который делали до этого, то забирает просто из памяти результат и выдает его" 1579 | ], 1580 | "metadata": { 1581 | "id": "KK6bvay9zAEt" 1582 | } 1583 | }, 1584 | { 1585 | "cell_type": "code", 1586 | "source": [ 1587 | "from functools import cache, lru_cache\n", 1588 | "\n", 1589 | "@lru_cache(maxsize=32) ## имеет в качестве аргумента, сколько мы должны запоминать\n", 1590 | "def recursive_fib(n):\n", 1591 | " if n in (1, 2):\n", 1592 | " return 1\n", 1593 | " return recursive_fib(n - 1) + recursive_fib(n - 2)\n", 1594 | "\n", 1595 | "def func_fib(n):\n", 1596 | " if n in (1, 2):\n", 1597 | " return 1\n", 1598 | " res = [0 for _ in range(n)]\n", 1599 | " res[0], res[1] = 1, 1\n", 1600 | " for i in range(2, n):\n", 1601 | " res[i] = res[i - 1] + res[i - 2]\n", 1602 | " return res[n - 1]" 1603 | ], 1604 | "metadata": { 1605 | "id": "APqNXqWi0Ri2" 1606 | }, 1607 | "execution_count": 2, 1608 | "outputs": [] 1609 | }, 1610 | { 1611 | "cell_type": "code", 1612 | "source": [ 1613 | "%%time\n", 1614 | "\n", 1615 | "print(recursive_fib(30)) ## А почему такой долгий wall time?" 1616 | ], 1617 | "metadata": { 1618 | "colab": { 1619 | "base_uri": "https://localhost:8080/" 1620 | }, 1621 | "id": "jPeMFjwR0gF8", 1622 | "outputId": "49f51703-1e4e-40b2-d1bb-a870007a730e" 1623 | }, 1624 | "execution_count": 3, 1625 | "outputs": [ 1626 | { 1627 | "output_type": "stream", 1628 | "name": "stdout", 1629 | "text": [ 1630 | "832040\n", 1631 | "CPU times: user 2.36 ms, sys: 0 ns, total: 2.36 ms\n", 1632 | "Wall time: 4.19 ms\n" 1633 | ] 1634 | } 1635 | ] 1636 | }, 1637 | { 1638 | "cell_type": "code", 1639 | "source": [ 1640 | "%%time\n", 1641 | "\n", 1642 | "print(func_fib(30))" 1643 | ], 1644 | "metadata": { 1645 | "colab": { 1646 | "base_uri": "https://localhost:8080/" 1647 | }, 1648 | "id": "mkG5HTVq0iVL", 1649 | "outputId": "a5a1ecc1-3ff4-45bb-d55a-208f44ce5eb7" 1650 | }, 1651 | "execution_count": 4, 1652 | "outputs": [ 1653 | { 1654 | "output_type": "stream", 1655 | "name": "stdout", 1656 | "text": [ 1657 | "832040\n", 1658 | "CPU times: user 2.07 ms, sys: 0 ns, total: 2.07 ms\n", 1659 | "Wall time: 2.06 ms\n" 1660 | ] 1661 | } 1662 | ] 1663 | }, 1664 | { 1665 | "cell_type": "markdown", 1666 | "source": [ 1667 | "Давайте решим еще одну задачу (достаточно известную) - задачу о Ханойской башне (если успеем)\n", 1668 | "\n", 1669 | "![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Tower_of_Hanoi.jpeg/600px-Tower_of_Hanoi.jpeg)" 1670 | ], 1671 | "metadata": { 1672 | "id": "vzgl3YucY8YB" 1673 | } 1674 | }, 1675 | { 1676 | "cell_type": "code", 1677 | "source": [ 1678 | "# number of third disk: 6 - from_ - to_\n", 1679 | "\n", 1680 | "def hanoi(n, from_=1, to_=3):\n", 1681 | " if n == 1:\n", 1682 | " print(f'Disk {1} from {from_} to {to_}')\n", 1683 | " return\n", 1684 | " hanoi(n - 1, from_, 6 - from_ - to_)\n", 1685 | " print(f'Disk {n} from {from_} to {to_}')\n", 1686 | " hanoi(n - 1, 6 - from_ - to_, to_)\n", 1687 | "\n", 1688 | "hanoi(5)" 1689 | ], 1690 | "metadata": { 1691 | "id": "bwQIdBEjF18J" 1692 | }, 1693 | "execution_count": null, 1694 | "outputs": [] 1695 | }, 1696 | { 1697 | "cell_type": "markdown", 1698 | "source": [ 1699 | "## Попугай дня" 1700 | ], 1701 | "metadata": { 1702 | "id": "y8hJCsx4yaZ2" 1703 | } 1704 | }, 1705 | { 1706 | "cell_type": "markdown", 1707 | "source": [ 1708 | "![Monk](https://upload.wikimedia.org/wikipedia/commons/b/b3/MonkParakeetsSantaPonsa.jpg)" 1709 | ], 1710 | "metadata": { 1711 | "id": "XIdmYkJouOVd" 1712 | } 1713 | }, 1714 | { 1715 | "cell_type": "markdown", 1716 | "source": [ 1717 | "А это Калита (или же попугай-монах)\n", 1718 | "\n", 1719 | "Примечательны эти попугаи несколькими вещами:\n", 1720 | "\n", 1721 | "1. Эти попугаи изначально заселяли только Южную Америку (Парагвай, южная часть Бразилии). Однако в 1970-х годах их начали массово привозить в Европу оттуда и пытались содержать как домашних животных. Но проблема в том, что они до боли крикливые, и поэтому их просто выпускали, что привело к тому, что они стали размножаться и жить в Европе и стали что-то типа голубей (в той же Барселоне или Мадриде)\n", 1722 | "\n", 1723 | "2. Единственные попугаи, которые гнездятся на ветвях деревьях (а не в дуплах или укрытиях). Строят они их коллектиквом (получается типа коммуналки), которая может весить до 200кг\n", 1724 | "\n", 1725 | "3. А называются они монахами, потому что их окрас напоминает одежду квакеров (это религиозный орден, но подходяшей картинки для сравнения я не нашел). Собственно, в Аргентине их и зовут \"попугаи квакеры\"" 1726 | ], 1727 | "metadata": { 1728 | "id": "1wfTwtZ9uQML" 1729 | } 1730 | }, 1731 | { 1732 | "cell_type": "markdown", 1733 | "source": [ 1734 | "![](https://image.jimcdn.com/app/cms/image/transf/dimension=1280x10000:format=jpg/path/s6b61d3476b988e81/image/ied0b14179f0e9857/version/1611582975/image.jpg)" 1735 | ], 1736 | "metadata": { 1737 | "id": "5fEzGg86um1j" 1738 | } 1739 | } 1740 | ] 1741 | } --------------------------------------------------------------------------------