[{"data":1,"prerenderedAt":52762},["ShallowReactive",2],{"navigation":3,"blog-page-python":386,"python":398},[4],{"title":5,"path":6,"stem":7,"children":8,"page":114},"Blog","\u002Fblog","blog",[9,115,184,329],{"title":10,"path":11,"stem":12,"children":13,"page":114},"Ege","\u002Fblog\u002Fege","blog\u002Fege",[14,18,22,26,30,34,38,42,46,50,54,58,62,66,70,74,78,82,86,90,94,98,102,106,110],{"title":15,"path":16,"stem":17},"ЕГЭ Задание 1","\u002Fblog\u002Fege\u002Ftask1","blog\u002Fege\u002Ftask1",{"title":19,"path":20,"stem":21},"ЕГЭ Задание 10","\u002Fblog\u002Fege\u002Ftask10","blog\u002Fege\u002Ftask10",{"title":23,"path":24,"stem":25},"ЕГЭ Задание 11","\u002Fblog\u002Fege\u002Ftask11","blog\u002Fege\u002Ftask11",{"title":27,"path":28,"stem":29},"ЕГЭ Задание 12","\u002Fblog\u002Fege\u002Ftask12","blog\u002Fege\u002Ftask12",{"title":31,"path":32,"stem":33},"ЕГЭ Задание 13","\u002Fblog\u002Fege\u002Ftask13","blog\u002Fege\u002Ftask13",{"title":35,"path":36,"stem":37},"ЕГЭ Задание 14","\u002Fblog\u002Fege\u002Ftask14","blog\u002Fege\u002Ftask14",{"title":39,"path":40,"stem":41},"ЕГЭ Задание 15","\u002Fblog\u002Fege\u002Ftask15","blog\u002Fege\u002Ftask15",{"title":43,"path":44,"stem":45},"ЕГЭ Задание 16","\u002Fblog\u002Fege\u002Ftask16","blog\u002Fege\u002Ftask16",{"title":47,"path":48,"stem":49},"ЕГЭ Задание 17","\u002Fblog\u002Fege\u002Ftask17","blog\u002Fege\u002Ftask17",{"title":51,"path":52,"stem":53},"ЕГЭ Задание 18","\u002Fblog\u002Fege\u002Ftask18","blog\u002Fege\u002Ftask18",{"title":55,"path":56,"stem":57},"ЕГЭ Задание 19, 20, 21","\u002Fblog\u002Fege\u002Ftask19_20_21","blog\u002Fege\u002Ftask19_20_21",{"title":59,"path":60,"stem":61},"ЕГЭ Задание 2","\u002Fblog\u002Fege\u002Ftask2","blog\u002Fege\u002Ftask2",{"title":63,"path":64,"stem":65},"ЕГЭ Задание 22","\u002Fblog\u002Fege\u002Ftask22","blog\u002Fege\u002Ftask22",{"title":67,"path":68,"stem":69},"ЕГЭ Задание 23","\u002Fblog\u002Fege\u002Ftask23","blog\u002Fege\u002Ftask23",{"title":71,"path":72,"stem":73},"ЕГЭ Задание 24","\u002Fblog\u002Fege\u002Ftask24","blog\u002Fege\u002Ftask24",{"title":75,"path":76,"stem":77},"ЕГЭ Задание 25","\u002Fblog\u002Fege\u002Ftask25","blog\u002Fege\u002Ftask25",{"title":79,"path":80,"stem":81},"ЕГЭ Задание 26","\u002Fblog\u002Fege\u002Ftask26","blog\u002Fege\u002Ftask26",{"title":83,"path":84,"stem":85},"ЕГЭ Задание 27","\u002Fblog\u002Fege\u002Ftask27","blog\u002Fege\u002Ftask27",{"title":87,"path":88,"stem":89},"ЕГЭ Задание 3","\u002Fblog\u002Fege\u002Ftask3","blog\u002Fege\u002Ftask3",{"title":91,"path":92,"stem":93},"ЕГЭ Задание 4","\u002Fblog\u002Fege\u002Ftask4","blog\u002Fege\u002Ftask4",{"title":95,"path":96,"stem":97},"ЕГЭ Задание 5","\u002Fblog\u002Fege\u002Ftask5","blog\u002Fege\u002Ftask5",{"title":99,"path":100,"stem":101},"ЕГЭ Задание 6","\u002Fblog\u002Fege\u002Ftask6","blog\u002Fege\u002Ftask6",{"title":103,"path":104,"stem":105},"ЕГЭ Задание 7","\u002Fblog\u002Fege\u002Ftask7","blog\u002Fege\u002Ftask7",{"title":107,"path":108,"stem":109},"ЕГЭ Задание 8","\u002Fblog\u002Fege\u002Ftask8","blog\u002Fege\u002Ftask8",{"title":111,"path":112,"stem":113},"ЕГЭ Задание 9","\u002Fblog\u002Fege\u002Ftask9","blog\u002Fege\u002Ftask9",false,{"title":116,"path":117,"stem":118,"children":119,"page":114},"Oge","\u002Fblog\u002Foge","blog\u002Foge",[120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180],{"title":121,"path":122,"stem":123},"ОГЭ Задание 1","\u002Fblog\u002Foge\u002Ftask1","blog\u002Foge\u002Ftask1",{"title":125,"path":126,"stem":127},"ОГЭ Задание 10","\u002Fblog\u002Foge\u002Ftask10","blog\u002Foge\u002Ftask10",{"title":129,"path":130,"stem":131},"ОГЭ Задание 11","\u002Fblog\u002Foge\u002Ftask11","blog\u002Foge\u002Ftask11",{"title":133,"path":134,"stem":135},"ОГЭ Задание 12","\u002Fblog\u002Foge\u002Ftask12","blog\u002Foge\u002Ftask12",{"title":137,"path":138,"stem":139},"ОГЭ Задание 13","\u002Fblog\u002Foge\u002Ftask13","blog\u002Foge\u002Ftask13",{"title":141,"path":142,"stem":143},"ОГЭ Задание 14","\u002Fblog\u002Foge\u002Ftask14","blog\u002Foge\u002Ftask14",{"title":145,"path":146,"stem":147},"ОГЭ Задание 15","\u002Fblog\u002Foge\u002Ftask15","blog\u002Foge\u002Ftask15",{"title":149,"path":150,"stem":151},"ОГЭ Задание 16","\u002Fblog\u002Foge\u002Ftask16","blog\u002Foge\u002Ftask16",{"title":153,"path":154,"stem":155},"ОГЭ Задание 2","\u002Fblog\u002Foge\u002Ftask2","blog\u002Foge\u002Ftask2",{"title":157,"path":158,"stem":159},"ОГЭ Задание 3","\u002Fblog\u002Foge\u002Ftask3","blog\u002Foge\u002Ftask3",{"title":161,"path":162,"stem":163},"ОГЭ Задание 4","\u002Fblog\u002Foge\u002Ftask4","blog\u002Foge\u002Ftask4",{"title":165,"path":166,"stem":167},"ОГЭ Задание 5","\u002Fblog\u002Foge\u002Ftask5","blog\u002Foge\u002Ftask5",{"title":169,"path":170,"stem":171},"ОГЭ Задание 6","\u002Fblog\u002Foge\u002Ftask6","blog\u002Foge\u002Ftask6",{"title":173,"path":174,"stem":175},"ОГЭ Задание 7","\u002Fblog\u002Foge\u002Ftask7","blog\u002Foge\u002Ftask7",{"title":177,"path":178,"stem":179},"ОГЭ Задание 8","\u002Fblog\u002Foge\u002Ftask8","blog\u002Foge\u002Ftask8",{"title":181,"path":182,"stem":183},"ОГЭ Задание 9","\u002Fblog\u002Foge\u002Ftask9","blog\u002Foge\u002Ftask9",{"title":185,"path":186,"stem":187,"children":188,"page":114},"Python","\u002Fblog\u002Fpython","blog\u002Fpython",[189,193,197,201,205,209,213,217,221,225,229,233,237,241,245,249,253,257,261,265,269,273,277,281,285,289,293,297,301,305,309,313,317,321,325],{"title":190,"path":191,"stem":192},"Знакомство с синтаксисом","\u002Fblog\u002Fpython\u002Fst1","blog\u002Fpython\u002Fst1",{"title":194,"path":195,"stem":196},"Отладка","\u002Fblog\u002Fpython\u002Fst10","blog\u002Fpython\u002Fst10",{"title":198,"path":199,"stem":200},"Модули и пакеты","\u002Fblog\u002Fpython\u002Fst11","blog\u002Fpython\u002Fst11",{"title":202,"path":203,"stem":204},"Кортежи","\u002Fblog\u002Fpython\u002Fst12","blog\u002Fpython\u002Fst12",{"title":206,"path":207,"stem":208},"Знакомство со списками","\u002Fblog\u002Fpython\u002Fst13","blog\u002Fpython\u002Fst13",{"title":210,"path":211,"stem":212},"Списки и циклы","\u002Fblog\u002Fpython\u002Fst14","blog\u002Fpython\u002Fst14",{"title":214,"path":215,"stem":216},"Использование списков ч.1","\u002Fblog\u002Fpython\u002Fst15","blog\u002Fpython\u002Fst15",{"title":218,"path":219,"stem":220},"Использование списков ч.2","\u002Fblog\u002Fpython\u002Fst16","blog\u002Fpython\u002Fst16",{"title":222,"path":223,"stem":224},"Использование списков ч.3","\u002Fblog\u002Fpython\u002Fst17","blog\u002Fpython\u002Fst17",{"title":226,"path":227,"stem":228},"Словари","\u002Fblog\u002Fpython\u002Fst18","blog\u002Fpython\u002Fst18",{"title":230,"path":231,"stem":232},"Множества","\u002Fblog\u002Fpython\u002Fst19","blog\u002Fpython\u002Fst19",{"title":234,"path":235,"stem":236},"Переменные","\u002Fblog\u002Fpython\u002Fst2","blog\u002Fpython\u002Fst2",{"title":238,"path":239,"stem":240},"Хеш-таблицы","\u002Fblog\u002Fpython\u002Fst20","blog\u002Fpython\u002Fst20",{"title":242,"path":243,"stem":244},"Решето Эратосфена","\u002Fblog\u002Fpython\u002Fst21","blog\u002Fpython\u002Fst21",{"title":246,"path":247,"stem":248},"Длинная арифметика","\u002Fblog\u002Fpython\u002Fst22","blog\u002Fpython\u002Fst22",{"title":250,"path":251,"stem":252},"Декораторы функций","\u002Fblog\u002Fpython\u002Fst23","blog\u002Fpython\u002Fst23",{"title":254,"path":255,"stem":256},"Знакомство с алгоритмами","\u002Fblog\u002Fpython\u002Fst24","blog\u002Fpython\u002Fst24",{"title":258,"path":259,"stem":260},"Бинарный поиск – примеры задач","\u002Fblog\u002Fpython\u002Fst25","blog\u002Fpython\u002Fst25",{"title":262,"path":263,"stem":264},"Сортировка выбором","\u002Fblog\u002Fpython\u002Fst26","blog\u002Fpython\u002Fst26",{"title":266,"path":267,"stem":268},"Рекурсия и стек","\u002Fblog\u002Fpython\u002Fst27","blog\u002Fpython\u002Fst27",{"title":270,"path":271,"stem":272},"Быстрая сортировка","\u002Fblog\u002Fpython\u002Fst28","blog\u002Fpython\u002Fst28",{"title":274,"path":275,"stem":276},"Поиск в ширину","\u002Fblog\u002Fpython\u002Fst29","blog\u002Fpython\u002Fst29",{"title":278,"path":279,"stem":280},"Работа со строками","\u002Fblog\u002Fpython\u002Fst3","blog\u002Fpython\u002Fst3",{"title":282,"path":283,"stem":284},"Поиск в глубину","\u002Fblog\u002Fpython\u002Fst30","blog\u002Fpython\u002Fst30",{"title":286,"path":287,"stem":288},"Сбалансированные деревья","\u002Fblog\u002Fpython\u002Fst31","blog\u002Fpython\u002Fst31",{"title":290,"path":291,"stem":292},"Алгоритм Дейкстры","\u002Fblog\u002Fpython\u002Fst32","blog\u002Fpython\u002Fst32",{"title":294,"path":295,"stem":296},"Жадные алгоритмы","\u002Fblog\u002Fpython\u002Fst33","blog\u002Fpython\u002Fst33",{"title":298,"path":299,"stem":300},"Динамическое программирование","\u002Fblog\u002Fpython\u002Fst34","blog\u002Fpython\u002Fst34",{"title":302,"path":303,"stem":304},"Алгоритм k ближайших соседей","\u002Fblog\u002Fpython\u002Fst35","blog\u002Fpython\u002Fst35",{"title":306,"path":307,"stem":308},"Типы данных","\u002Fblog\u002Fpython\u002Fst4","blog\u002Fpython\u002Fst4",{"title":310,"path":311,"stem":312},"О функциях","\u002Fblog\u002Fpython\u002Fst5","blog\u002Fpython\u002Fst5",{"title":314,"path":315,"stem":316},"Свойства и методы","\u002Fblog\u002Fpython\u002Fst6","blog\u002Fpython\u002Fst6",{"title":318,"path":319,"stem":320},"Определение функций","\u002Fblog\u002Fpython\u002Fst7","blog\u002Fpython\u002Fst7",{"title":322,"path":323,"stem":324},"Логика","\u002Fblog\u002Fpython\u002Fst8","blog\u002Fpython\u002Fst8",{"title":326,"path":327,"stem":328},"Циклы","\u002Fblog\u002Fpython\u002Fst9","blog\u002Fpython\u002Fst9",{"title":330,"path":331,"stem":332,"children":333,"page":114},"Toi","\u002Fblog\u002Ftoi","blog\u002Ftoi",[334,338,342,346,350,354,358,362,366,370,374,378,382],{"title":335,"path":336,"stem":337},"Информация и информационные процессы","\u002Fblog\u002Ftoi\u002Fst1","blog\u002Ftoi\u002Fst1",{"title":339,"path":340,"stem":341},"Электронные таблицы","\u002Fblog\u002Ftoi\u002Fst10","blog\u002Ftoi\u002Fst10",{"title":343,"path":344,"stem":345},"Система, её свойства и компоненты. Моделирование","\u002Fblog\u002Ftoi\u002Fst11","blog\u002Ftoi\u002Fst11",{"title":347,"path":348,"stem":349},"Представление информации в компьютере","\u002Fblog\u002Ftoi\u002Fst12","blog\u002Ftoi\u002Fst12",{"title":351,"path":352,"stem":353},"Средства информационно-коммуникационных технологий. Файловая система","\u002Fblog\u002Ftoi\u002Fst13","blog\u002Ftoi\u002Fst13",{"title":355,"path":356,"stem":357},"Комбинаторика","\u002Fblog\u002Ftoi\u002Fst2","blog\u002Ftoi\u002Fst2",{"title":359,"path":360,"stem":361},"Адресация в интернете","\u002Fblog\u002Ftoi\u002Fst3","blog\u002Ftoi\u002Fst3",{"title":363,"path":364,"stem":365},"Измерение количества информации","\u002Fblog\u002Ftoi\u002Fst4","blog\u002Ftoi\u002Fst4",{"title":367,"path":368,"stem":369},"Системы счисления","\u002Fblog\u002Ftoi\u002Fst5","blog\u002Ftoi\u002Fst5",{"title":371,"path":372,"stem":373},"Диаграммы Эйлера — Венна","\u002Fblog\u002Ftoi\u002Fst6","blog\u002Ftoi\u002Fst6",{"title":375,"path":376,"stem":377},"Условие Фано","\u002Fblog\u002Ftoi\u002Fst7","blog\u002Ftoi\u002Fst7",{"title":379,"path":380,"stem":381},"Теория графов","\u002Fblog\u002Ftoi\u002Fst8","blog\u002Ftoi\u002Fst8",{"title":383,"path":384,"stem":385},"Алгебра логики","\u002Fblog\u002Ftoi\u002Fst9","blog\u002Ftoi\u002Fst9",{"id":387,"title":388,"body":389,"description":390,"extension":391,"links":389,"meta":392,"navigation":393,"path":394,"seo":395,"stem":396,"__hash__":397},"pages\u002Fpython.yml","Статьи по Python",null,"Здесь вы найдёте статьи по программированию на языке Python","yml",{},true,"\u002Fpython",{"title":388,"description":390},"python","fiZQAchrpyOBdVnH7Sf53W96mN-RDzhQgRT6-Y1RL6E",[399,1893,2877,4089,4762,5458,6224,8385,12485,15019,15359,16570,17353,18568,21142,23012,24272,26263,27739,29120,30479,30949,32126,33699,35304,40732,41326,42220,43893,44907,45555,45963,47535,48850,51906],{"id":400,"title":190,"author":401,"body":406,"date":1885,"description":1886,"extension":1887,"image":1888,"meta":1889,"minRead":1890,"navigation":393,"num":434,"path":191,"seo":1891,"stem":192,"__hash__":1892},"python\u002Fblog\u002Fpython\u002Fst1.md",{"name":402,"avatar":403},"Штана Альберт Игоревич",{"src":404,"alt":405},"me.jpg","@ashtana",{"type":407,"value":408,"toc":1865},"minimark",[409,414,418,421,457,462,465,468,489,492,507,510,530,534,537,540,543,546,549,588,591,625,628,631,636,639,642,659,662,665,668,671,693,696,726,729,792,796,812,831,834,837,840,862,865,869,872,875,879,882,913,916,919,923,926,952,955,958,1039,1042,1045,1128,1131,1135,1138,1141,1144,1158,1161,1164,1168,1171,1174,1177,1198,1201,1210,1214,1217,1248,1251,1262,1266,1269,1272,1288,1291,1316,1319,1322,1338,1341,1344,1347,1359,1396,1399,1402,1427,1431,1434,1451,1454,1475,1478,1485,1488,1508,1511,1514,1521,1524,1556,1559,1584,1587,1596,1645,1648,1668,1676,1702,1705,1709,1712,1715,1744,1747,1788,1791,1794,1847,1858,1861],[410,411,413],"h2",{"id":412},"hello-world","Hello World!",[415,416,417],"p",{},"Изучение нового языка программирования традиционно начинается с 'Hello, World!'. Это простая программа, которая выводит приветствие на экран и заодно знакомит с новым языком — его синтаксисом.",[415,419,420],{},"Этой традиции уже больше сорока пяти лет, поэтому и мы не будем нарушать ее. Напишем программу Hello, World!. Чтобы сделать это, нужно дать компьютеру специальную команду на вывод. В языке Python это — print():",[422,423,427],"pre",{"className":424,"code":425,"language":396,"meta":426,"style":426},"language-python shiki shiki-themes github-light","print('Hello, World!')\n# => Hello, World!\n","",[428,429,430,450],"code",{"__ignoreMap":426},[431,432,435,439,443,447],"span",{"class":433,"line":434},"line",1,[431,436,438],{"class":437},"sYu0t","print",[431,440,442],{"class":441},"sgsFI","(",[431,444,446],{"class":445},"sYBdl","'Hello, World!'",[431,448,449],{"class":441},")\n",[431,451,453],{"class":433,"line":452},2,[431,454,456],{"class":455},"sAwPA","# => Hello, World!\n",[458,459,461],"h4",{"id":460},"как-работают-комментарии","Как работают комментарии",[415,463,464],{},"Практически все языки программирования позволяют оставлять в коде комментарии. Они никак не используются интерпретатором Python. Они нужны исключительно для людей, чтобы программист оставлял пометки для себя и для других программистов.",[415,466,467],{},"С их помощью добавляют пояснения, как работает код, какие ошибки нужно поправить или не забыть что-то добавить позже:",[422,469,471],{"className":424,"code":470,"language":396,"meta":426,"style":426},"# Удалить строку ниже после реализации задачи по регистрации\nprint(\"Сделайте регистрацию\")\n",[428,472,473,478],{"__ignoreMap":426},[431,474,475],{"class":433,"line":434},[431,476,477],{"class":455},"# Удалить строку ниже после реализации задачи по регистрации\n",[431,479,480,482,484,487],{"class":433,"line":452},[431,481,438],{"class":437},[431,483,442],{"class":441},[431,485,486],{"class":445},"\"Сделайте регистрацию\"",[431,488,449],{"class":441},[415,490,491],{},"Комментарии в Python начинаются со знака # и могут появляться в любом месте программы. Они могут занимать всю строку. Если одной строки мало, то создается несколько комментариев:",[422,493,495],{"className":424,"code":494,"language":396,"meta":426,"style":426},"# Это первый комментарий!\n# Это второй комментарий!\n",[428,496,497,502],{"__ignoreMap":426},[431,498,499],{"class":433,"line":434},[431,500,501],{"class":455},"# Это первый комментарий!\n",[431,503,504],{"class":433,"line":452},[431,505,506],{"class":455},"# Это второй комментарий!\n",[415,508,509],{},"Комментарий может находиться на строке после кода:",[422,511,513],{"className":424,"code":512,"language":396,"meta":426,"style":426},"print('Hello World!')  # Подробности тут: https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002FHello,_world!\n",[428,514,515],{"__ignoreMap":426},[431,516,517,519,521,524,527],{"class":433,"line":434},[431,518,438],{"class":437},[431,520,442],{"class":441},[431,522,523],{"class":445},"'Hello World!'",[431,525,526],{"class":441},")  ",[431,528,529],{"class":455},"# Подробности тут: https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002FHello,_world!\n",[458,531,533],{"id":532},"инструкции","Инструкции",[415,535,536],{},"Когда мы оплачиваем покупки в магазине, то четко следуем инструкции по оплате. Иначе нам не продадут товар или услугу. Также и в программировании важно соблюдать инструкции.",[415,538,539],{},"Чтобы увидеть на экране ожидаемый результат, нужно дать компьютеру четкие и пошаговые указания. Это можно сделать с помощью инструкций. Инструкция — это команда для компьютера, единица выполнения. Код на Python в этом случае — это набор инструкций. Его можно представить в виде пошагового алгоритма действий компьютера.",[415,541,542],{},"Код на Python запускает интерпретатор — программу, которая выполняет инструкции строго по очереди. Как и шаги в рецепте, наборы инструкций для интерпретатора пишутся по порядку и отделяются друг от друга переходом на следующую строку.",[415,544,545],{},"Разработчики должны понимать порядок действий в коде и уметь мысленно разделять программу на независимые части, удобные для анализа.",[415,547,548],{},"Посмотрим на пример кода с двумя инструкциями. При его запуске на экран последовательно выводятся два предложения:",[422,550,552],{"className":424,"code":551,"language":396,"meta":426,"style":426},"print('Выводи это сообщение первым.')\nprint('А это выводи вторым на экран!')\n# => Выводи это сообщение первым.\n# => А это выводи вторым на экран!\n",[428,553,554,565,576,582],{"__ignoreMap":426},[431,555,556,558,560,563],{"class":433,"line":434},[431,557,438],{"class":437},[431,559,442],{"class":441},[431,561,562],{"class":445},"'Выводи это сообщение первым.'",[431,564,449],{"class":441},[431,566,567,569,571,574],{"class":433,"line":452},[431,568,438],{"class":437},[431,570,442],{"class":441},[431,572,573],{"class":445},"'А это выводи вторым на экран!'",[431,575,449],{"class":441},[431,577,579],{"class":433,"line":578},3,[431,580,581],{"class":455},"# => Выводи это сообщение первым.\n",[431,583,585],{"class":433,"line":584},4,[431,586,587],{"class":455},"# => А это выводи вторым на экран!\n",[415,589,590],{},"Выше мы говорили, что инструкции отделяются друг от друга переходом на новую строку. Но есть и другой способ: их можно разделить точкой с запятой — ;:",[422,592,594],{"className":424,"code":593,"language":396,"meta":426,"style":426},"print('Выводи это сообщение первым.'); print('Подробнее об интерпретаторах тут: https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002FИнтерпретатор')\n# => Выводи это сообщение первым.\n# => Подробнее об интерпретаторах тут: https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002FИнтерпретатор\n",[428,595,596,616,620],{"__ignoreMap":426},[431,597,598,600,602,604,607,609,611,614],{"class":433,"line":434},[431,599,438],{"class":437},[431,601,442],{"class":441},[431,603,562],{"class":445},[431,605,606],{"class":441},"); ",[431,608,438],{"class":437},[431,610,442],{"class":441},[431,612,613],{"class":445},"'Подробнее об интерпретаторах тут: https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002FИнтерпретатор'",[431,615,449],{"class":441},[431,617,618],{"class":433,"line":452},[431,619,581],{"class":455},[431,621,622],{"class":433,"line":578},[431,623,624],{"class":455},"# => Подробнее об интерпретаторах тут: https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002FИнтерпретатор\n",[415,626,627],{},"Технической разницы между первым и вторым вариантом нет — интерпретатор поймет инструкции одинаково. Разница только в том, что человеку будет неудобно читать второй вариант.",[415,629,630],{},"Лучше инструкции располагать друг под другом. Так всем будет удобнее читать код, обслуживать его и вносить изменения.",[632,633,635],"h3",{"id":634},"арифметические-операции","Арифметические операции",[415,637,638],{},"На базовом уровне компьютеры оперируют только числами. Даже в прикладных программах на высокоуровневых языках внутри много чисел и операций над ними. Но для старта достаточно знать обычную арифметику — с нее и начнем.",[415,640,641],{},"Например, для сложения двух чисел в математике мы пишем: 2 + 2. В программировании — то же самое. Вот программа, которая складывает два числа:",[422,643,645],{"className":424,"code":644,"language":396,"meta":426,"style":426},"2 + 2\n",[428,646,647],{"__ignoreMap":426},[431,648,649,652,656],{"class":433,"line":434},[431,650,651],{"class":437},"2",[431,653,655],{"class":654},"sD7c4"," +",[431,657,658],{"class":437}," 2\n",[415,660,661],{},"Арифметика в программировании практически не отличается от школьной арифметики.",[415,663,664],{},"Строчка кода 2 + 2 заставит интерпретатор сложить числа и узнать результат. Эта программа будет работать, но в ней нет смысла. По сути, мы не даем команду интерпретатору, мы просто говорим ему: «Смотри, сумма два и два». В реальной работе недостаточно сообщать интерпретатору о математическом выражении.",[415,666,667],{},"Например, если создавать интернет-магазин, недостаточно просить интерпретатор посчитать стоимость товаров в корзине. Нужно просить посчитать стоимость и показать цену покупателю.",[415,669,670],{},"Нам нужно попросить интерпретатор сложить 2 + 2 и дать команду сделать что-то с результатом. Например, вывести его на экран:",[422,672,674],{"className":424,"code":673,"language":396,"meta":426,"style":426},"# Сначала вычисляется сумма, затем она передается в функцию печати\n2 + 2  # => 4\n",[428,675,676,681],{"__ignoreMap":426},[431,677,678],{"class":433,"line":434},[431,679,680],{"class":455},"# Сначала вычисляется сумма, затем она передается в функцию печати\n",[431,682,683,685,687,690],{"class":433,"line":452},[431,684,651],{"class":437},[431,686,655],{"class":654},[431,688,689],{"class":437}," 2",[431,691,692],{"class":455},"  # => 4\n",[415,694,695],{},"Кроме сложения, доступны следующие операции:",[697,698,699,707,714,717,720,723],"ul",{},[700,701,702],"li",{},[697,703,704],{},[700,705,706],{},"— вычитание",[700,708,709],{},[697,710,711],{},[700,712,713],{},"— умножение",[700,715,716],{},"** — возведение в степень",[700,718,719],{},"\u002F — деление",[700,721,722],{},"\u002F\u002F — целочисленное деление",[700,724,725],{},"% — остаток от деления",[415,727,728],{},"Теперь выведем на экран результат деления, результат возведения в степень и результат получения остатка от деления:",[422,730,732],{"className":424,"code":731,"language":396,"meta":426,"style":426},"print(6 \u002F 2)   # => 3.0 (При делении двух чисел получается тип данных float)\nprint(4 ** 2)  # => 16\nprint(7 % 2)   # => 1\n",[428,733,734,754,773],{"__ignoreMap":426},[431,735,736,738,740,743,746,748,751],{"class":433,"line":434},[431,737,438],{"class":437},[431,739,442],{"class":441},[431,741,742],{"class":437},"6",[431,744,745],{"class":654}," \u002F",[431,747,689],{"class":437},[431,749,750],{"class":441},")   ",[431,752,753],{"class":455},"# => 3.0 (При делении двух чисел получается тип данных float)\n",[431,755,756,758,760,763,766,768,770],{"class":433,"line":452},[431,757,438],{"class":437},[431,759,442],{"class":441},[431,761,762],{"class":437},"4",[431,764,765],{"class":654}," **",[431,767,689],{"class":437},[431,769,526],{"class":441},[431,771,772],{"class":455},"# => 16\n",[431,774,775,777,779,782,785,787,789],{"class":433,"line":578},[431,776,438],{"class":437},[431,778,442],{"class":441},[431,780,781],{"class":437},"7",[431,783,784],{"class":654}," %",[431,786,689],{"class":437},[431,788,750],{"class":441},[431,790,791],{"class":455},"# => 1\n",[458,793,795],{"id":794},"операторы-и-операнды","Операторы и операнды",[415,797,798,799,803,804,807,808,811],{},"Знак операции, такой как ",[800,801,802],"strong",{},"+",", называют ",[800,805,806],{},"оператором",". Операторы выполняют операции над определенными значениями, которые называются ",[800,809,810],{},"операндами",". Сами операторы — это обычно один или несколько символов. Реже — слово. Подавляющее большинство операторов соответствуют математическим операциям.",[422,813,815],{"className":424,"code":814,"language":396,"meta":426,"style":426},"print(2 + 2)\n",[428,816,817],{"__ignoreMap":426},[431,818,819,821,823,825,827,829],{"class":433,"line":434},[431,820,438],{"class":437},[431,822,442],{"class":441},[431,824,651],{"class":437},[431,826,655],{"class":654},[431,828,689],{"class":437},[431,830,449],{"class":441},[415,832,833],{},"В этом примере + — это оператор, а числа 2 и 2 — это операнды.",[415,835,836],{},"Когда мы складываем, у нас есть два операнда: один слева, другой справа от знака +. Операции, которые требуют наличия двух операндов, называются бинарными. Если пропустить хотя бы один операнд, например, 2 +, то программа завершится с синтаксической ошибкой.",[415,838,839],{},"Операции бывают не только бинарными, но и унарными — с одним операндом, и тернарными — с тремя операндами. Причем операторы могут выглядеть одинаково, но обозначать разные операции. Символы + и - используются не только как операторы. Когда речь идет про отрицательные числа, то знак минуса становится частью числа:",[422,841,843],{"className":424,"code":842,"language":396,"meta":426,"style":426},"print(-5)  # => -5\n",[428,844,845],{"__ignoreMap":426},[431,846,847,849,851,854,857,859],{"class":433,"line":434},[431,848,438],{"class":437},[431,850,442],{"class":441},[431,852,853],{"class":654},"-",[431,855,856],{"class":437},"5",[431,858,526],{"class":441},[431,860,861],{"class":455},"# => -5\n",[415,863,864],{},"Выше пример применения унарной операции к числу 5. Оператор минус перед тройкой говорит интерпретатору взять число 5 и найти противоположное, то есть -5. Это может сбить с толку, потому что -5 — это одновременно и число само по себе, и оператор с операндом. Но у языков программирования такая структура.",[458,866,868],{"id":867},"коммутативная-операция","Коммутативная операция",[415,870,871],{},"«От перемены мест слагаемых сумма не меняется» — это один из базовых законов арифметики, который также называется коммутативным законом. Бинарная операция считается коммутативной, если вы получаете тот же самый результат, поменяв местами операнды. В этом случае сложение — это коммутативная операция: 3 + 2 = 2 + 3.",[415,873,874],{},"Но вычитание — это не коммутативная операция: 2 - 3 ≠ 3 - 2. В программировании этот закон работает точно так же, как в арифметике. Более того, большинство операций, с которыми мы сталкиваемся в реальной жизни, не являются коммутативными. Отсюда вывод: всегда обращайте внимание на порядок того, с чем работаете.",[458,876,878],{"id":877},"композиция-операций","Композиция операций",[415,880,881],{},"Рассмотрим пример:",[422,883,885],{"className":424,"code":884,"language":396,"meta":426,"style":426},"print(2 * 3 * 4 * 5)\n",[428,886,887],{"__ignoreMap":426},[431,888,889,891,893,895,898,901,903,906,908,911],{"class":433,"line":434},[431,890,438],{"class":437},[431,892,442],{"class":441},[431,894,651],{"class":437},[431,896,897],{"class":654}," *",[431,899,900],{"class":437}," 3",[431,902,897],{"class":654},[431,904,905],{"class":437}," 4",[431,907,897],{"class":654},[431,909,910],{"class":437}," 5",[431,912,449],{"class":441},[415,914,915],{},"Операции можно соединять друг с другом и вычислять все более сложные составные выражения. Чтобы представить, как происходят вычисления внутри интерпретатора, разберем пример: 2 * 3 * 3 * 5.",[415,917,918],{},"Сначала вычисляется 2 * 3 и получается выражение 6 * 4 * 5\nЗатем 6 * 4. В итоге имеем 24 * 5\nВ итоге происходит последнее умножение, и получается результат 120\nОперации могут содержать разные операторы, из-за чего появляется вопрос об их приоритете.",[458,920,922],{"id":921},"приоритет-операций","Приоритет операций",[415,924,925],{},"Представим, что нужно вычислить такое выражение: 2 + 2 * 2. Именно так и запишем:",[422,927,929],{"className":424,"code":928,"language":396,"meta":426,"style":426},"print(2 + 2 * 2)  # => 6\n",[428,930,931],{"__ignoreMap":426},[431,932,933,935,937,939,941,943,945,947,949],{"class":433,"line":434},[431,934,438],{"class":437},[431,936,442],{"class":441},[431,938,651],{"class":437},[431,940,655],{"class":654},[431,942,689],{"class":437},[431,944,897],{"class":654},[431,946,689],{"class":437},[431,948,526],{"class":441},[431,950,951],{"class":455},"# => 6\n",[415,953,954],{},"В школьной математике есть понятие «приоритет операции». Приоритет определяет, в какой последовательности должны выполняться операции. Умножение и деление имеют больший приоритет, чем сложение и вычитание, а приоритет возведения в степень выше всех остальных арифметических операций. Например: 2 ** 3 * 2 вычислится в 16.",[415,956,957],{},"Но нередко вычисления должны происходить в порядке, отличном от стандартного приоритета. Тогда приоритет нужно задавать круглыми скобками. Так и в школе, например: (2 + 2) * 2. В скобки можно заключать любую операцию. Они могут вкладываться друг в друга сколько угодно раз. Вот примеры:",[422,959,961],{"className":424,"code":960,"language":396,"meta":426,"style":426},"print(3 ** (4 - 2))  # => 9\nprint(7 * 3 + (4 \u002F 2) - (8 + (2 - 1)))  # => 14.0\n",[428,962,963,990],{"__ignoreMap":426},[431,964,965,967,969,972,974,977,979,982,984,987],{"class":433,"line":434},[431,966,438],{"class":437},[431,968,442],{"class":441},[431,970,971],{"class":437},"3",[431,973,765],{"class":654},[431,975,976],{"class":441}," (",[431,978,762],{"class":437},[431,980,981],{"class":654}," -",[431,983,689],{"class":437},[431,985,986],{"class":441},"))  ",[431,988,989],{"class":455},"# => 9\n",[431,991,992,994,996,998,1000,1002,1004,1006,1008,1010,1012,1015,1017,1019,1022,1024,1026,1028,1030,1033,1036],{"class":433,"line":452},[431,993,438],{"class":437},[431,995,442],{"class":441},[431,997,781],{"class":437},[431,999,897],{"class":654},[431,1001,900],{"class":437},[431,1003,655],{"class":654},[431,1005,976],{"class":441},[431,1007,762],{"class":437},[431,1009,745],{"class":654},[431,1011,689],{"class":437},[431,1013,1014],{"class":441},") ",[431,1016,853],{"class":654},[431,1018,976],{"class":441},[431,1020,1021],{"class":437},"8",[431,1023,655],{"class":654},[431,1025,976],{"class":441},[431,1027,651],{"class":437},[431,1029,981],{"class":654},[431,1031,1032],{"class":437}," 1",[431,1034,1035],{"class":441},")))  ",[431,1037,1038],{"class":455},"# => 14.0\n",[415,1040,1041],{},"Главное при этом соблюдать парность — закрывать скобки в правильном порядке. Это часто становится причиной ошибок не только у новичков, но и у опытных программистов.",[415,1043,1044],{},"Иногда выражение сложно воспринимать визуально. Тогда можно расставить скобки, не повлияв на приоритет:",[422,1046,1048],{"className":424,"code":1047,"language":396,"meta":426,"style":426},"# Было\nprint(8 \u002F 2 + 5 - -3 \u002F 2)  # => 10.5\n# Стало\nprint(((8 \u002F 2) + 5) - (-3 \u002F 2))  # => 10.5\n",[428,1049,1050,1055,1086,1091],{"__ignoreMap":426},[431,1051,1052],{"class":433,"line":434},[431,1053,1054],{"class":455},"# Было\n",[431,1056,1057,1059,1061,1063,1065,1067,1069,1071,1073,1075,1077,1079,1081,1083],{"class":433,"line":452},[431,1058,438],{"class":437},[431,1060,442],{"class":441},[431,1062,1021],{"class":437},[431,1064,745],{"class":654},[431,1066,689],{"class":437},[431,1068,655],{"class":654},[431,1070,910],{"class":437},[431,1072,981],{"class":654},[431,1074,981],{"class":654},[431,1076,971],{"class":437},[431,1078,745],{"class":654},[431,1080,689],{"class":437},[431,1082,526],{"class":441},[431,1084,1085],{"class":455},"# => 10.5\n",[431,1087,1088],{"class":433,"line":578},[431,1089,1090],{"class":455},"# Стало\n",[431,1092,1093,1095,1098,1100,1102,1104,1106,1108,1110,1112,1114,1116,1118,1120,1122,1124,1126],{"class":433,"line":584},[431,1094,438],{"class":437},[431,1096,1097],{"class":441},"(((",[431,1099,1021],{"class":437},[431,1101,745],{"class":654},[431,1103,689],{"class":437},[431,1105,1014],{"class":441},[431,1107,802],{"class":654},[431,1109,910],{"class":437},[431,1111,1014],{"class":441},[431,1113,853],{"class":654},[431,1115,976],{"class":441},[431,1117,853],{"class":654},[431,1119,971],{"class":437},[431,1121,745],{"class":654},[431,1123,689],{"class":437},[431,1125,986],{"class":441},[431,1127,1085],{"class":455},[415,1129,1130],{},"Важно запомнить: код пишется для людей. Код будут читать люди, а машины будут только исполнять его. Для машин код — корректный или некорректный. Для них нет «более» понятного или «менее» понятного кода.",[632,1132,1134],{"id":1133},"ошибки-оформления-кода","Ошибки оформления кода",[415,1136,1137],{},"Если программа на Python написана синтаксически некорректно, то интерпретатор выводит на экран соответствующее сообщение. Также он указывает на файл и строчку, где произошла ошибка.",[415,1139,1140],{},"Синтаксическая ошибка возникает в том случае, когда код записали с нарушением грамматических правил. В естественных языках грамматика важна, но текст с ошибками обычно можно понять и прочитать. В программировании все строго. Мельчайшее нарушение — и программа даже не запустится. Примером может быть забытое двоеточие(:) неправильно расставленные скобки и другие детали.",[415,1142,1143],{},"Вот пример кода с синтаксической ошибкой:",[422,1145,1147],{"className":424,"code":1146,"language":396,"meta":426,"style":426},"print('Привет)\n",[428,1148,1149],{"__ignoreMap":426},[431,1150,1151,1153,1155],{"class":433,"line":434},[431,1152,438],{"class":437},[431,1154,442],{"class":441},[431,1156,1157],{"class":445},"'Привет)\n",[415,1159,1160],{},"Если запустить код выше, то мы увидим следующее сообщение: SyntaxError: EOL while scanning string literal",[415,1162,1163],{},"С одной стороны, ошибки синтаксиса — самые простые, потому что они связаны с грамматическими правилами написания кода, а не со смыслом кода. Их легко исправить: нужно лишь найти нарушение в записи. С другой стороны, интерпретатор не всегда может четко указать на это нарушение. Поэтому бывает, что забытую скобку нужно поставить не туда, куда указывает сообщение об ошибке.",[458,1165,1167],{"id":1166},"ошибки-линтера","Ошибки линтера",[415,1169,1170],{},"Код нужно оформлять определенным образом, чтобы он был понятным и простым в поддержке. Существуют специальные наборы правил, которые описывают различные аспекты написания кода — их называют стандартами кодирования. В Python стандарт один — PEP8. Он отвечает практически на все вопросы о том, как оформлять ту или иную часть кода. Этот документ содержит все правила, которых нужно придерживаться. Новичкам мы советуем завести привычку заглядывать в стандарт PEP8 и писать код по нему.",[415,1172,1173],{},"Сегодня не нужно помнить все правила из стандарта, потому что существуют специальные программы, которые проверяют код автоматически и сообщают о нарушениях. Такие программы называются линтерами. Они проверяют код на соответствие стандартам. В Python их достаточно много, и наиболее популярный из них — flake8.",[415,1175,1176],{},"Взгляните на пример:",[422,1178,1180],{"className":424,"code":1179,"language":396,"meta":426,"style":426},"x =1+ 3\n",[428,1181,1182],{"__ignoreMap":426},[431,1183,1184,1187,1190,1193,1195],{"class":433,"line":434},[431,1185,1186],{"class":441},"x ",[431,1188,1189],{"class":654},"=",[431,1191,1192],{"class":437},"1",[431,1194,802],{"class":654},[431,1196,1197],{"class":437}," 3\n",[415,1199,1200],{},"Линтер будет предупреждать на нарушение правила: E225 missing whitespace around operator. По стандарту, все операторы всегда должны отделяться пробелами от операндов.",[415,1202,1203,1204],{},"Выше мы увидели правило E225 — это одно из большого количества правил. Другие правила описывают отступы, названия, скобки, математические операции, длину строчек и множество иных аспектов. Каждое отдельное правило кажется неважным и мелким, но вместе они составляют основу хорошего кода. Список всех правил PEP8 доступен в документации на сайте:\n",[1205,1206,1207],"a",{"href":1207,"rel":1208},"https:\u002F\u002Fpeps.python.org\u002Fpep-0008\u002F",[1209],"nofollow",[632,1211,1213],{"id":1212},"немного-про-строки","Немного про строки",[415,1215,1216],{},"Определить строку довольно просто — это некий набор символов. Представим, что у нас есть такие записи:",[422,1218,1220],{"className":424,"code":1219,"language":396,"meta":426,"style":426},"'Hello'\n'Goodbye'\n'G'\n' '\n''\n",[428,1221,1222,1227,1232,1237,1242],{"__ignoreMap":426},[431,1223,1224],{"class":433,"line":434},[431,1225,1226],{"class":445},"'Hello'\n",[431,1228,1229],{"class":433,"line":452},[431,1230,1231],{"class":445},"'Goodbye'\n",[431,1233,1234],{"class":433,"line":578},[431,1235,1236],{"class":445},"'G'\n",[431,1238,1239],{"class":433,"line":584},[431,1240,1241],{"class":445},"' '\n",[431,1243,1245],{"class":433,"line":1244},5,[431,1246,1247],{"class":445},"''\n",[415,1249,1250],{},"Какие из этих вариантов — строки? На самом деле, все пять вариантов подходят:",[697,1252,1253,1256,1259],{},[700,1254,1255],{},"С 'Hello' и 'Goodbye' все очевидно — мы уже работали с подобными конструкциями и называли их строками",[700,1257,1258],{},"'G' и ' ' — тоже строки, просто в них всего по одному символу",[700,1260,1261],{},"'' — это пустая строка, потому что в ней ноль символов",[458,1263,1265],{"id":1264},"кавычки","Кавычки",[415,1267,1268],{},"Строкой мы считаем все, что находится внутри кавычек: даже если это пробел, один символ или вообще отсутствие символов.",[415,1270,1271],{},"Выше мы записывали строки в одинарных кавычках, но это не единственный способ. Можно использовать и двойные:",[422,1273,1275],{"className":424,"code":1274,"language":396,"meta":426,"style":426},"print(\"Это строка!\")\n",[428,1276,1277],{"__ignoreMap":426},[431,1278,1279,1281,1283,1286],{"class":433,"line":434},[431,1280,438],{"class":437},[431,1282,442],{"class":441},[431,1284,1285],{"class":445},"\"Это строка!\"",[431,1287,449],{"class":441},[415,1289,1290],{},"Теперь представьте, что вы хотите напечатать строчку Python's. Апостроф перед буквой s — это такой же символ, как одинарная кавычка. Попробуем:",[422,1292,1294],{"className":424,"code":1293,"language":396,"meta":426,"style":426},"print('Python's')\n# SyntaxError: invalid syntax\n",[428,1295,1296,1311],{"__ignoreMap":426},[431,1297,1298,1300,1302,1305,1308],{"class":433,"line":434},[431,1299,438],{"class":437},[431,1301,442],{"class":441},[431,1303,1304],{"class":445},"'Python'",[431,1306,1307],{"class":441},"s",[431,1309,1310],{"class":445},"')\n",[431,1312,1313],{"class":433,"line":452},[431,1314,1315],{"class":455},"# SyntaxError: invalid syntax\n",[415,1317,1318],{},"Такая программа не будет работать. С точки зрения Python, строчка началась с одинарной кавычки, а потом закончилась после слова Python. Дальше были символы s без кавычек — значит, это не строка. А потом была одна открывающая строку кавычка, которая так и не закрылась: '). Этот код содержит синтаксическую ошибку — это видно даже по тому, как подсвечен код.",[415,1320,1321],{},"Чтобы избежать этой ошибки, мы используем двойные кавычки. Такой вариант программы сработает верно:",[422,1323,1325],{"className":424,"code":1324,"language":396,"meta":426,"style":426},"print(\"Python's\")\n",[428,1326,1327],{"__ignoreMap":426},[431,1328,1329,1331,1333,1336],{"class":433,"line":434},[431,1330,438],{"class":437},[431,1332,442],{"class":441},[431,1334,1335],{"class":445},"\"Python's\"",[431,1337,449],{"class":441},[415,1339,1340],{},"Теперь интерпретатор знает, что строка началась с двойной кавычки и закончиться должна тоже на двойной кавычке. А одинарная кавычка внутри стала частью строки.",[415,1342,1343],{},"Верно и обратное. Если внутри строки мы хотим использовать двойные кавычки, то саму строку нужно заключать в одинарные. Причем количество кавычек внутри самой строки неважно.",[415,1345,1346],{},"Теперь представим, что мы хотим создать такую строку: Python's mother said \"No\". В ней есть и одинарные, и двойные кавычки. Нам нужно каким-то образом указать интерпретатору, что кавычки — это символы внутри строки, а не начало или конец строки.",[415,1348,1349,1350,1353,1354,1358],{},"Для этого используют ",[800,1351,1352],{},"символ экранирования",": *",[1355,1356,1357],"em",{},"*"," — обратный слэш. Если мы поставим \\ перед кавычкой (одинарной или двойной), то интерпретатор распознает кавычку как обычный символ внутри строки, а не начало или конец строки:",[422,1360,1362],{"className":424,"code":1361,"language":396,"meta":426,"style":426},"# Экранируем кавычки вокруг No, чтобы интерпретатор распознал их как часть строки\nprint(\"Python's mother said \\\"No\\\"\")\n# => Python's mother said \"No\"\n",[428,1363,1364,1369,1391],{"__ignoreMap":426},[431,1365,1366],{"class":433,"line":434},[431,1367,1368],{"class":455},"# Экранируем кавычки вокруг No, чтобы интерпретатор распознал их как часть строки\n",[431,1370,1371,1373,1375,1378,1381,1384,1386,1389],{"class":433,"line":452},[431,1372,438],{"class":437},[431,1374,442],{"class":441},[431,1376,1377],{"class":445},"\"Python's mother said ",[431,1379,1380],{"class":437},"\\\"",[431,1382,1383],{"class":445},"No",[431,1385,1380],{"class":437},[431,1387,1388],{"class":445},"\"",[431,1390,449],{"class":441},[431,1392,1393],{"class":433,"line":578},[431,1394,1395],{"class":455},"# => Python's mother said \"No\"\n",[415,1397,1398],{},"Обратите внимание, что в примере выше нам не пришлось экранировать одинарную кавычку (апостроф 's), потому что сама строка создана с двойными кавычками. Если бы строка создавалась с одинарными кавычками, то символ экранирования нужен был бы перед апострофом, но не перед двойными кавычками.",[415,1400,1401],{},"Если нужно вывести сам обратный слеш, то работает такое же правило. Как и любой другой специальный символ, его надо экранировать:",[422,1403,1405],{"className":424,"code":1404,"language":396,"meta":426,"style":426},"print(\"\\\\\")\n# => \\\n",[428,1406,1407,1422],{"__ignoreMap":426},[431,1408,1409,1411,1413,1415,1418,1420],{"class":433,"line":434},[431,1410,438],{"class":437},[431,1412,442],{"class":441},[431,1414,1388],{"class":445},[431,1416,1417],{"class":437},"\\\\",[431,1419,1388],{"class":445},[431,1421,449],{"class":441},[431,1423,1424],{"class":433,"line":452},[431,1425,1426],{"class":455},"# => \\\n",[458,1428,1430],{"id":1429},"экранированные-последовательности","Экранированные последовательности",[415,1432,1433],{},"Мы хотим показать вот такой диалог:",[422,1435,1439],{"className":1436,"code":1437,"language":1438,"meta":426,"style":426},"language-markdown shiki shiki-themes github-light","- Ты изучаешь Python?\n- Дааааа!\n","markdown",[428,1440,1441,1446],{"__ignoreMap":426},[431,1442,1443],{"class":433,"line":434},[431,1444,1445],{},"- Ты изучаешь Python?\n",[431,1447,1448],{"class":433,"line":452},[431,1449,1450],{},"- Дааааа!\n",[415,1452,1453],{},"Попробуем вывести на экран строку с таким текстом:",[422,1455,1457],{"className":424,"code":1456,"language":396,"meta":426,"style":426},"print(\"- Ты изучаешь Python? - Дааааа!\")\n# => - Ты изучаешь Python? - Дааааа!\n",[428,1458,1459,1470],{"__ignoreMap":426},[431,1460,1461,1463,1465,1468],{"class":433,"line":434},[431,1462,438],{"class":437},[431,1464,442],{"class":441},[431,1466,1467],{"class":445},"\"- Ты изучаешь Python? - Дааааа!\"",[431,1469,449],{"class":441},[431,1471,1472],{"class":433,"line":452},[431,1473,1474],{"class":455},"# => - Ты изучаешь Python? - Дааааа!\n",[415,1476,1477],{},"Результат получился не такой, как мы хотели. Строки расположились друг за другом, а не одна ниже другой. Нам нужно как-то сказать интерпретатору «нажать на Enter» — сделать перевод строки после вопросительного знака. Это можно сделать с помощью символа \\n:",[415,1479,1480,1481,1484],{},"\\n — это пример ",[800,1482,1483],{},"экранированной последовательности","(escape sequence). Такие последовательности еще называют управляющими конструкциями. Их нельзя увидеть в том же виде, в котором их набрали.",[415,1486,1487],{},"Набирая текст в Word, вы нажимаете на Enter в конце строчки. Редактор при этом ставит в конец строчки специальный невидимый символ, который называется LINE FEED (LF, перевод строчки). В некоторых редакторах можно даже включить отображение невидимых символов. Тогда текст будет выглядеть примерно так:",[422,1489,1491],{"className":1436,"code":1490,"language":1438,"meta":426,"style":426},"- Привет!¶\n- Добрый день сэр!¶\n- Как дела?\n",[428,1492,1493,1498,1503],{"__ignoreMap":426},[431,1494,1495],{"class":433,"line":434},[431,1496,1497],{},"- Привет!¶\n",[431,1499,1500],{"class":433,"line":452},[431,1501,1502],{},"- Добрый день сэр!¶\n",[431,1504,1505],{"class":433,"line":578},[431,1506,1507],{},"- Как дела?\n",[415,1509,1510],{},"Устройство, которое выводит соответствующий текст, учитывает этот символ. Например, принтер при встрече с LF протаскивает бумагу вверх на одну строку, а текстовый редактор переносит весь последующий текст ниже, также на одну строку.",[415,1512,1513],{},"Существует несколько десятков таких невидимых символов, но в программировании часто встречаются всего несколько. Кроме перевода строки, к таким символам относятся:",[415,1515,1516,1517,1520],{},"Табуляция \\t — разрыв, который получается при нажатии на кнопку Tab ",[1518,1519],"br",{},"\nВозврат каретки \\r — работает только в Windows",[415,1522,1523],{},"Распознать такую управляющую конструкцию в тексте можно по символу . Программисты часто используют перевод строки \\n, чтобы правильно форматировать текст. Например, напишем такой код:",[422,1525,1527],{"className":424,"code":1526,"language":396,"meta":426,"style":426},"print(\"Математика\\nИнформатика\\nФизика\\nХимия\")\n",[428,1528,1529],{"__ignoreMap":426},[431,1530,1531,1533,1535,1538,1541,1544,1546,1549,1551,1554],{"class":433,"line":434},[431,1532,438],{"class":437},[431,1534,442],{"class":441},[431,1536,1537],{"class":445},"\"Математика",[431,1539,1540],{"class":437},"\\n",[431,1542,1543],{"class":445},"Информатика",[431,1545,1540],{"class":437},[431,1547,1548],{"class":445},"Физика",[431,1550,1540],{"class":437},[431,1552,1553],{"class":445},"Химия\"",[431,1555,449],{"class":441},[415,1557,1558],{},"Тогда на экран выведется:",[422,1560,1562],{"className":1436,"code":1561,"language":1438,"meta":426,"style":426},"Математика\nИнформатика\nФизика\nХимия\n",[428,1563,1564,1569,1574,1579],{"__ignoreMap":426},[431,1565,1566],{"class":433,"line":434},[431,1567,1568],{},"Математика\n",[431,1570,1571],{"class":433,"line":452},[431,1572,1573],{},"Информатика\n",[431,1575,1576],{"class":433,"line":578},[431,1577,1578],{},"Физика\n",[431,1580,1581],{"class":433,"line":584},[431,1582,1583],{},"Химия\n",[415,1585,1586],{},"Когда работаете с символом перевода, учитывайте следующие моменты:",[1588,1589,1590,1593],"ol",{},[700,1591,1592],{},"Не важно, что стоит перед или после \\n: символ или пустая строка. Перевод обнаружится и выполнится в любом случае.",[700,1594,1595],{},"Строка может содержать только \\n:",[422,1597,1599],{"className":424,"code":1598,"language":396,"meta":426,"style":426},"print('Привет') # Строка с текстом\nprint(\"\\n\") # Строка с невидимыми символами перевода строки\nprint('Мир!') # Строка с текстом\n",[428,1600,1601,1615,1632],{"__ignoreMap":426},[431,1602,1603,1605,1607,1610,1612],{"class":433,"line":434},[431,1604,438],{"class":437},[431,1606,442],{"class":441},[431,1608,1609],{"class":445},"'Привет'",[431,1611,1014],{"class":441},[431,1613,1614],{"class":455},"# Строка с текстом\n",[431,1616,1617,1619,1621,1623,1625,1627,1629],{"class":433,"line":452},[431,1618,438],{"class":437},[431,1620,442],{"class":441},[431,1622,1388],{"class":445},[431,1624,1540],{"class":437},[431,1626,1388],{"class":445},[431,1628,1014],{"class":441},[431,1630,1631],{"class":455},"# Строка с невидимыми символами перевода строки\n",[431,1633,1634,1636,1638,1641,1643],{"class":433,"line":578},[431,1635,438],{"class":437},[431,1637,442],{"class":441},[431,1639,1640],{"class":445},"'Мир!'",[431,1642,1014],{"class":441},[431,1644,1614],{"class":455},[415,1646,1647],{},"Программа выведет на экран:",[422,1649,1651],{"className":1436,"code":1650,"language":1438,"meta":426,"style":426},"Привет\n\nМир!\n",[428,1652,1653,1658,1663],{"__ignoreMap":426},[431,1654,1655],{"class":433,"line":434},[431,1656,1657],{},"Привет\n",[431,1659,1660],{"class":433,"line":452},[431,1661,1662],{"emptyLinePlaceholder":393},"\n",[431,1664,1665],{"class":433,"line":578},[431,1666,1667],{},"Мир!\n",[1588,1669,1670,1673],{"start":578},[700,1671,1672],{},"В коде последовательность \\n выглядит как два символа, но с точки зрения интерпретатора — это один специальный символ",[700,1674,1675],{},"Если нужно вывести \\n как текст (два отдельных печатных символа), то можно воспользоваться экранированием — добавить еще один \\ в начале. Последовательность \\n отобразится как символы \\ и n, которые идут друг за другом:",[422,1677,1679],{"className":424,"code":1678,"language":396,"meta":426,"style":426},"print(\"Привет мир! \\\\n\")\n# => Привет мир! \\n\n",[428,1680,1681,1697],{"__ignoreMap":426},[431,1682,1683,1685,1687,1690,1692,1695],{"class":433,"line":434},[431,1684,438],{"class":437},[431,1686,442],{"class":441},[431,1688,1689],{"class":445},"\"Привет мир! ",[431,1691,1417],{"class":437},[431,1693,1694],{"class":445},"n\"",[431,1696,449],{"class":441},[431,1698,1699],{"class":433,"line":452},[431,1700,1701],{"class":455},"# => Привет мир! \\n\n",[415,1703,1704],{},"В Windows для перевода строк по умолчанию используется \\r\\n. Такая комбинация хорошо работает только в Windows, но создает проблемы при переносе в другие системы. Например, когда в команде разработчиков есть пользователи Linux.\nДело в том, что последовательность \\r\\n имеет разную трактовку в зависимости от выбранной кодировки. По этой причине в среде разработчиков принято всегда использовать \\n без \\r.\nВ таком случае перевод строки всегда трактуется одинаково и отлично работает в любой системе.",[458,1706,1708],{"id":1707},"конкатенация","Конкатенация",[415,1710,1711],{},"В веб-разработке программы постоянно оперируют строками. Все, что мы видим на сайтах, так или иначе представлено в виде текста. Этот текст чаще всего динамический — то есть он получается из разных частей, которые соединяются вместе.",[415,1713,1714],{},"Чтобы соединить строки, нужно выполнить конкатенацию:",[422,1716,1718],{"className":424,"code":1717,"language":396,"meta":426,"style":426},"# Оператор такой же, как и при сложении чисел, но здесь он имеет другой смысл\nprint('При' + 'вет')  # => Привет\n",[428,1719,1720,1725],{"__ignoreMap":426},[431,1721,1722],{"class":433,"line":434},[431,1723,1724],{"class":455},"# Оператор такой же, как и при сложении чисел, но здесь он имеет другой смысл\n",[431,1726,1727,1729,1731,1734,1736,1739,1741],{"class":433,"line":452},[431,1728,438],{"class":437},[431,1730,442],{"class":441},[431,1732,1733],{"class":445},"'При'",[431,1735,655],{"class":654},[431,1737,1738],{"class":445}," 'вет'",[431,1740,526],{"class":441},[431,1742,1743],{"class":455},"# => Привет\n",[415,1745,1746],{},"Склеивание строк всегда происходит в том же порядке, в котором записаны операнды. Левый операнд становится левой частью строки, а правый — правой. Вот еще несколько примеров:",[422,1748,1750],{"className":424,"code":1749,"language":396,"meta":426,"style":426},"print('Pyt' + 'hon')  # => Python\nprint(\"Pyt\" + 'hon')  # => Python\n",[428,1751,1752,1771],{"__ignoreMap":426},[431,1753,1754,1756,1758,1761,1763,1766,1768],{"class":433,"line":434},[431,1755,438],{"class":437},[431,1757,442],{"class":441},[431,1759,1760],{"class":445},"'Pyt'",[431,1762,655],{"class":654},[431,1764,1765],{"class":445}," 'hon'",[431,1767,526],{"class":441},[431,1769,1770],{"class":455},"# => Python\n",[431,1772,1773,1775,1777,1780,1782,1784,1786],{"class":433,"line":452},[431,1774,438],{"class":437},[431,1776,442],{"class":441},[431,1778,1779],{"class":445},"\"Pyt\"",[431,1781,655],{"class":654},[431,1783,1765],{"class":445},[431,1785,526],{"class":441},[431,1787,1770],{"class":455},[415,1789,1790],{},"Как видите, строки можно склеивать, даже если их записали с разными кавычками.",[415,1792,1793],{},"Пробел — такой же символ, как и другие, поэтому сколько пробелов поставите в строке, столько и получится в итоговой строке:",[422,1795,1797],{"className":424,"code":1796,"language":396,"meta":426,"style":426},"# Ставим пробел в левой части\nprint(\"Привет \" + 'мир!')  # => Привет мир!\n# Ставим пробел в правой части\nprint('Hello' + ' World!')  # => Hello World!\n",[428,1798,1799,1804,1823,1828],{"__ignoreMap":426},[431,1800,1801],{"class":433,"line":434},[431,1802,1803],{"class":455},"# Ставим пробел в левой части\n",[431,1805,1806,1808,1810,1813,1815,1818,1820],{"class":433,"line":452},[431,1807,438],{"class":437},[431,1809,442],{"class":441},[431,1811,1812],{"class":445},"\"Привет \"",[431,1814,655],{"class":654},[431,1816,1817],{"class":445}," 'мир!'",[431,1819,526],{"class":441},[431,1821,1822],{"class":455},"# => Привет мир!\n",[431,1824,1825],{"class":433,"line":578},[431,1826,1827],{"class":455},"# Ставим пробел в правой части\n",[431,1829,1830,1832,1834,1837,1839,1842,1844],{"class":433,"line":584},[431,1831,438],{"class":437},[431,1833,442],{"class":441},[431,1835,1836],{"class":445},"'Hello'",[431,1838,655],{"class":654},[431,1840,1841],{"class":445}," ' World!'",[431,1843,526],{"class":441},[431,1845,1846],{"class":455},"# => Hello World!\n",[415,1848,1849,1850,1853,1854,1857],{},"Попробуйте сами запустить код в окне ниже с интерпретатором Python и повторите примеры из статьи чтобы самим увидеть и понять как всё это работает.\nДля этого в ячейке с кодом нажмите клавиши на клавиатуре ",[800,1851,1852],{},"Shift+Enter"," или запустите код через ",[800,1855,1856],{},"кнопку Run"," по значку ▶.",[1859,1860],"jypiter",{},[1862,1863,1864],"style",{},"html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}",{"title":426,"searchDepth":452,"depth":1244,"links":1866},[1867],{"id":412,"depth":452,"text":413,"children":1868},[1869,1870,1871,1877,1880],{"id":460,"depth":584,"text":461},{"id":532,"depth":584,"text":533},{"id":634,"depth":578,"text":635,"children":1872},[1873,1874,1875,1876],{"id":794,"depth":584,"text":795},{"id":867,"depth":584,"text":868},{"id":877,"depth":584,"text":878},{"id":921,"depth":584,"text":922},{"id":1133,"depth":578,"text":1134,"children":1878},[1879],{"id":1166,"depth":584,"text":1167},{"id":1212,"depth":578,"text":1213,"children":1881},[1882,1883,1884],{"id":1264,"depth":584,"text":1265},{"id":1429,"depth":584,"text":1430},{"id":1707,"depth":584,"text":1708},"2025-01-19","Основы построения программ на Python. Арифметические операции. Ввод и вывод. Синтаксис","md","images\u002Fblog\u002Fpython\u002Fst1\u002Fimg.png",{},28,{"title":190,"description":1886},"5Jv-JZ7G3urqctPZW5iWszjSnQkyc2GlQM6h_pCi14U",{"id":1894,"title":234,"author":1895,"body":1897,"date":2870,"description":2871,"extension":1887,"image":2872,"meta":2873,"minRead":2874,"navigation":393,"num":452,"path":235,"seo":2875,"stem":236,"__hash__":2876},"python\u002Fblog\u002Fpython\u002Fst2.md",{"name":402,"avatar":1896},{"src":404,"alt":405},{"type":407,"value":1898,"toc":2854},[1899,1903,1906,1910,1913,1939,1942,1945,1988,1991,2046,2049,2053,2056,2095,2098,2102,2105,2124,2127,2131,2134,2163,2166,2170,2173,2177,2180,2183,2213,2216,2219,2298,2301,2304,2307,2335,2338,2365,2368,2423,2426,2501,2504,2508,2511,2539,2542,2579,2582,2630,2633,2637,2640,2660,2663,2666,2669,2672,2675,2678,2681,2692,2700,2703,2707,2710,2756,2759,2829,2832,2840,2843,2849,2851],[410,1900,1902],{"id":1901},"переменные-в-python","Переменные в Python",[415,1904,1905],{},"Разберемся, как работать с переменными в Python, какие ошибки часто допускают неопытные разработчики и как их исправлять.",[632,1907,1909],{"id":1908},"как-создать-переменную","Как создать переменную",[415,1911,1912],{},"Представьте, что нам нужно напечатать на экран фразу Привет! два раза. Эту задачу можно решить так:",[422,1914,1916],{"className":424,"code":1915,"language":396,"meta":426,"style":426},"print('Привет!')\nprint('Привет!')\n",[428,1917,1918,1929],{"__ignoreMap":426},[431,1919,1920,1922,1924,1927],{"class":433,"line":434},[431,1921,438],{"class":437},[431,1923,442],{"class":441},[431,1925,1926],{"class":445},"'Привет!'",[431,1928,449],{"class":441},[431,1930,1931,1933,1935,1937],{"class":433,"line":452},[431,1932,438],{"class":437},[431,1934,442],{"class":441},[431,1936,1926],{"class":445},[431,1938,449],{"class":441},[415,1940,1941],{},"В простейшем случае так и стоит поступить. Но если фраза Привет! будет использоваться чаще двух раз, да еще и в разных частях программы, то придется ее везде повторять — это неудобно.\nПроблемы с таким подходом начнутся, когда понадобится изменить фразу, а такое происходит довольно часто. Нам придется найти все места с этой фразой и выполнить необходимую замену.",[415,1943,1944],{},"А можно поступить по-другому. Чтобы не копировать выражение, достаточно создать с ним переменную:",[422,1946,1948],{"className":424,"code":1947,"language":396,"meta":426,"style":426},"# greeting - переводится как приветствие\ngreeting = 'Привет!'\nprint(greeting)\nprint(greeting)\n# => Привет!\n# => Привет!\n",[428,1949,1950,1955,1965,1972,1978,1983],{"__ignoreMap":426},[431,1951,1952],{"class":433,"line":434},[431,1953,1954],{"class":455},"# greeting - переводится как приветствие\n",[431,1956,1957,1960,1962],{"class":433,"line":452},[431,1958,1959],{"class":441},"greeting ",[431,1961,1189],{"class":654},[431,1963,1964],{"class":445}," 'Привет!'\n",[431,1966,1967,1969],{"class":433,"line":578},[431,1968,438],{"class":437},[431,1970,1971],{"class":441},"(greeting)\n",[431,1973,1974,1976],{"class":433,"line":584},[431,1975,438],{"class":437},[431,1977,1971],{"class":441},[431,1979,1980],{"class":433,"line":1244},[431,1981,1982],{"class":455},"# => Привет!\n",[431,1984,1986],{"class":433,"line":1985},6,[431,1987,1982],{"class":455},[415,1989,1990],{},"В строчке greeting = 'Привет!' мы берем переменную с именем greeting и присваиваем ей значение 'Привет!'. Переменная указывает на данные, которые в нее записали. Благодаря этому, данные можно использовать многократно и не дублировать их постоянно.\nКогда переменная создана, можно ее использовать. Она подставляется в те места, где раньше стояла наша фраза. Когда код выполняется, интерпретатор доходит до строчки print(greeting) и подставляет содержимое переменной, а затем выполняет код.\nДля имени переменной используется любой набор допустимых символов, к которым относятся буквы английского алфавита, цифры и знак нижнего подчёркивания(_). При этом цифру нельзя ставить в начале.\nИмена переменных зависят от регистра самих букв, то есть имя hello и имя Hello — это два разных имени для двух разных переменных. Регистр в Python имеет очень важное значение, никогда не забывайте про него.\nКоличество создаваемых переменных неограниченно(лишь бы у устройства хватало мощности и памяти). Большие программы содержат десятки и сотни тысяч имен переменных. Вот как выглядят две переменные внутри одной программы:",[422,1992,1994],{"className":424,"code":1993,"language":396,"meta":426,"style":426},"greeting1 = 'Привет!'\nprint(greeting1)\nprint(greeting1)\n\ngreeting2 = 'Пока!'\nprint(greeting2)\nprint(greeting2)\n",[428,1995,1996,2005,2012,2018,2022,2032,2039],{"__ignoreMap":426},[431,1997,1998,2001,2003],{"class":433,"line":434},[431,1999,2000],{"class":441},"greeting1 ",[431,2002,1189],{"class":654},[431,2004,1964],{"class":445},[431,2006,2007,2009],{"class":433,"line":452},[431,2008,438],{"class":437},[431,2010,2011],{"class":441},"(greeting1)\n",[431,2013,2014,2016],{"class":433,"line":578},[431,2015,438],{"class":437},[431,2017,2011],{"class":441},[431,2019,2020],{"class":433,"line":584},[431,2021,1662],{"emptyLinePlaceholder":393},[431,2023,2024,2027,2029],{"class":433,"line":1244},[431,2025,2026],{"class":441},"greeting2 ",[431,2028,1189],{"class":654},[431,2030,2031],{"class":445}," 'Пока!'\n",[431,2033,2034,2036],{"class":433,"line":1985},[431,2035,438],{"class":437},[431,2037,2038],{"class":441},"(greeting2)\n",[431,2040,2042,2044],{"class":433,"line":2041},7,[431,2043,438],{"class":437},[431,2045,2038],{"class":441},[415,2047,2048],{},"Чтобы программу было удобно читать, среди программистов принято создавать переменные как можно ближе к тому месту, где они используются. Теперь нужно разобраться, как их изменять.",[632,2050,2052],{"id":2051},"как-изменить-переменную","Как изменить переменную",[415,2054,2055],{},"Само слово «переменная» подсказывает, что ее можно менять. И действительно, со временем внутри программы значения переменных могут изменяться. Например:",[422,2057,2059],{"className":424,"code":2058,"language":396,"meta":426,"style":426},"greeting = 'Привет!'\nprint(greeting)  # => Привет!\ngreeting = 'Пока!'\nprint(greeting)  # => Пока!\n",[428,2060,2061,2069,2078,2086],{"__ignoreMap":426},[431,2062,2063,2065,2067],{"class":433,"line":434},[431,2064,1959],{"class":441},[431,2066,1189],{"class":654},[431,2068,1964],{"class":445},[431,2070,2071,2073,2076],{"class":433,"line":452},[431,2072,438],{"class":437},[431,2074,2075],{"class":441},"(greeting)  ",[431,2077,1982],{"class":455},[431,2079,2080,2082,2084],{"class":433,"line":578},[431,2081,1959],{"class":441},[431,2083,1189],{"class":654},[431,2085,2031],{"class":445},[431,2087,2088,2090,2092],{"class":433,"line":584},[431,2089,438],{"class":437},[431,2091,2075],{"class":441},[431,2093,2094],{"class":455},"# => Пока!\n",[415,2096,2097],{},"Имя переменной осталось тем же, но внутри появились другие данные. Отметим, что переменные в Python не требуют специального объявления. Вместо этого переменная объявляется, когда ее впервые используют в программе.\nПеременные — мощная и в то же время запутанная вещь. Нельзя сразу с уверенностью сказать, что внутри нее записано — сначала надо проанализировать код, который находится до переменной.\nИменно этим занимаются разработчики во время отладки, когда пытаются разобраться, почему программа работает не так, как задумано.",[632,2099,2101],{"id":2100},"какие-ошибки-часто-допускают-с-переменными","Какие ошибки часто допускают с переменными",[415,2103,2104],{},"Порядок инструкций в коде с переменными имеет огромное значение. Поэтому переменную нужно определить до первого использования. Ниже пример ошибки, которую часто допускают новички:",[422,2106,2108],{"className":424,"code":2107,"language":396,"meta":426,"style":426},"print(greeting)\ngreeting = 'Привет!'\n",[428,2109,2110,2116],{"__ignoreMap":426},[431,2111,2112,2114],{"class":433,"line":434},[431,2113,438],{"class":437},[431,2115,1971],{"class":441},[431,2117,2118,2120,2122],{"class":433,"line":452},[431,2119,1959],{"class":441},[431,2121,1189],{"class":654},[431,2123,1964],{"class":445},[415,2125,2126],{},"Запуск программы выше завершается с ошибкой NameError: name 'greeting' is not defined — это ошибка обращения. Это значит, что в коде используется имя переменной(идентификатор), которое пока не определено. Это говорится в самом тексте ошибки: 'greeting' is not defined.\nКроме неправильного порядка действий, в Python встречаются банальные опечатки в имени переменной. Это происходит и когда переменная используется, и когда ее объявляют.\nКоличество подобных ошибок можно уменьшить, если использовать правильно настроенный редактор. Он предупреждает о возможных проблемах и подсвечивает переменные, которые используются без объявления.\nС переменными мы разобрались. Можно переходить к данным, которые никогда не меняются.",[632,2128,2130],{"id":2129},"как-работают-константы","Как работают константы",[415,2132,2133],{},"Некоторые данные никогда не меняются — например, математические постоянные. Возьмем для примера число π. Оно всегда равно 3.14 и не может измениться.\nЧтобы обратиться к подобным данным, в Python используют константы:",[422,2135,2137],{"className":424,"code":2136,"language":396,"meta":426,"style":426},"PI = 3.14\nprint(PI)  # => 3.14\n",[428,2138,2139,2150],{"__ignoreMap":426},[431,2140,2141,2144,2147],{"class":433,"line":434},[431,2142,2143],{"class":437},"PI",[431,2145,2146],{"class":654}," =",[431,2148,2149],{"class":437}," 3.14\n",[431,2151,2152,2154,2156,2158,2160],{"class":433,"line":452},[431,2153,438],{"class":437},[431,2155,442],{"class":441},[431,2157,2143],{"class":437},[431,2159,526],{"class":441},[431,2161,2162],{"class":455},"# => 3.14\n",[415,2164,2165],{},"В Python интерпретатору нет разницы при работе с переменной как с обычной или константой(нет оператора const как в некоторых других языках программирования).\nРазница только в том, что константы принято именовать заглавными буквами и использовать нижнее подчёркивание(_) в качестве разделителя между словами.\nКонстанта, как и переменная, может использоваться в любом выражении.",[632,2167,2169],{"id":2168},"выражения-в-определениях","Выражения в определениях",[415,2171,2172],{},"Переменные помогают упрощать сложные вычисления. Например, конвертация валюты или составление нового слова. Рассмотрим два способа.",[458,2174,2176],{"id":2175},"сложные-вычисления-через-переменную","Сложные вычисления через переменную",[415,2178,2179],{},"Представим, что нам нужно перевести доллары в рубли через евро. Подобные конвертации через промежуточную валюту часто делают банки при покупках за рубежом.",[415,2181,2182],{},"Для начала переведем 50 долларов в евро. Допустим, что один доллар — 0.96 евро:",[422,2184,2186],{"className":424,"code":2185,"language":396,"meta":426,"style":426},"euro_count = 50 * 0.96\nprint(euro_count)  # => 48.0\n",[428,2187,2188,2203],{"__ignoreMap":426},[431,2189,2190,2193,2195,2198,2200],{"class":433,"line":434},[431,2191,2192],{"class":441},"euro_count ",[431,2194,1189],{"class":654},[431,2196,2197],{"class":437}," 50",[431,2199,897],{"class":654},[431,2201,2202],{"class":437}," 0.96\n",[431,2204,2205,2207,2210],{"class":433,"line":452},[431,2206,438],{"class":437},[431,2208,2209],{"class":441},"(euro_count)  ",[431,2211,2212],{"class":455},"# => 48.0\n",[415,2214,2215],{},"Здесь в переменную euro_count = 50 * 0.96 справа от знака «равно» мы записываем выражение. Интерпретатор вычислит результат (48.0) и запишет его в переменную.\nИнтерпретатору не важно, в каком виде записаны данные: 48.0 или 50 * 0.96. Для него оба варианта — выражения, которые надо вычислить.\nОн проводит вычисления и приходит к одному и тому же значению — 48.0.",[415,2217,2218],{},"Python различает выражения (expressions) и инструкции (statements).\nВыражение — это любой корректный блок кода, который возвращает значение. Конкатенация строк (склеивание значений переменных) — это тоже выражение.\nКогда интерпретатор видит выражение, он обрабатывает его и генерирует результат — значение выражения.\nВот несколько примеров выражения. В комментариях справа от каждого выражения записаны итоговые значения:",[422,2220,2222],{"className":424,"code":2221,"language":396,"meta":426,"style":426},"48.0             # 48.0\n50 * 0.96        # 48.0\n100 \u002F 10 * 2     # 20.0\nint('50')        # 50\n'привет'         # привет\n'при' + 'вет'    # привет\n",[428,2223,2224,2232,2245,2262,2278,2286],{"__ignoreMap":426},[431,2225,2226,2229],{"class":433,"line":434},[431,2227,2228],{"class":437},"48.0",[431,2230,2231],{"class":455},"             # 48.0\n",[431,2233,2234,2237,2239,2242],{"class":433,"line":452},[431,2235,2236],{"class":437},"50",[431,2238,897],{"class":654},[431,2240,2241],{"class":437}," 0.96",[431,2243,2244],{"class":455},"        # 48.0\n",[431,2246,2247,2250,2252,2255,2257,2259],{"class":433,"line":578},[431,2248,2249],{"class":437},"100",[431,2251,745],{"class":654},[431,2253,2254],{"class":437}," 10",[431,2256,897],{"class":654},[431,2258,689],{"class":437},[431,2260,2261],{"class":455},"     # 20.0\n",[431,2263,2264,2267,2269,2272,2275],{"class":433,"line":584},[431,2265,2266],{"class":437},"int",[431,2268,442],{"class":441},[431,2270,2271],{"class":445},"'50'",[431,2273,2274],{"class":441},")        ",[431,2276,2277],{"class":455},"# 50\n",[431,2279,2280,2283],{"class":433,"line":1244},[431,2281,2282],{"class":445},"'привет'",[431,2284,2285],{"class":455},"         # привет\n",[431,2287,2288,2291,2293,2295],{"class":433,"line":1985},[431,2289,2290],{"class":445},"'при'",[431,2292,655],{"class":654},[431,2294,1738],{"class":445},[431,2296,2297],{"class":455},"    # привет\n",[415,2299,2300],{},"Инструкция — это команда, действие.",[415,2302,2303],{},"if, while, for — примеры инструкций. Они производят или контролируют действия, но не превращаются в значения.",[415,2305,2306],{},"Операция присваивания также является инструкцией, потому что она не возвращает, а связывает имя переменной с заданным значением:",[422,2308,2310],{"className":424,"code":2309,"language":396,"meta":426,"style":426},"x = 42 # это инструкция (statement)\nx + 1  # а это выражение (expressions)\n",[428,2311,2312,2324],{"__ignoreMap":426},[431,2313,2314,2316,2318,2321],{"class":433,"line":434},[431,2315,1186],{"class":441},[431,2317,1189],{"class":654},[431,2319,2320],{"class":437}," 42",[431,2322,2323],{"class":455}," # это инструкция (statement)\n",[431,2325,2326,2328,2330,2332],{"class":433,"line":452},[431,2327,1186],{"class":441},[431,2329,802],{"class":654},[431,2331,1032],{"class":437},[431,2333,2334],{"class":455},"  # а это выражение (expressions)\n",[415,2336,2337],{},"В тех местах, где ожидается выражение, можно поставить любое вычисление. Оно может быть не только математическим, но и строковым — как конкатенация.\nПрограмма все равно останется работоспособной. Программы состоят из множества комбинаций выражений. Основываясь на сказанном выше, подумайте, сработает ли такой код:",[422,2339,2341],{"className":424,"code":2340,"language":396,"meta":426,"style":426},"author = \"Jack \" + 'London'\nprint(author)\n",[428,2342,2343,2358],{"__ignoreMap":426},[431,2344,2345,2348,2350,2353,2355],{"class":433,"line":434},[431,2346,2347],{"class":441},"author ",[431,2349,1189],{"class":654},[431,2351,2352],{"class":445}," \"Jack \"",[431,2354,655],{"class":654},[431,2356,2357],{"class":445}," 'London'\n",[431,2359,2360,2362],{"class":433,"line":452},[431,2361,438],{"class":437},[431,2363,2364],{"class":441},"(author)\n",[415,2366,2367],{},"Такой код выведет на экран строку Jack London. Если хотите проверить самостоятельно, запустите код в конце статьи и поэкспериментируйте.\nС помощью переменных можно записывать еще более сложные вычисления. Вернемся к нашей валютной программе.\nЗапишем стоимость евро в рублях как отдельную переменную. Вычислим цену 48 евро в рублях, умножив их на 105. Допустим, что 1 евро — 105 рублей:",[422,2369,2371],{"className":424,"code":2370,"language":396,"meta":426,"style":426},"rubles_per_euro = 105\neuro_count = 50 * 0.96  # 48.0\nrubles_count = euro_count * rubles_per_euro  # 5040.0\nprint(rubles_count)\n",[428,2372,2373,2383,2398,2416],{"__ignoreMap":426},[431,2374,2375,2378,2380],{"class":433,"line":434},[431,2376,2377],{"class":441},"rubles_per_euro ",[431,2379,1189],{"class":654},[431,2381,2382],{"class":437}," 105\n",[431,2384,2385,2387,2389,2391,2393,2395],{"class":433,"line":452},[431,2386,2192],{"class":441},[431,2388,1189],{"class":654},[431,2390,2197],{"class":437},[431,2392,897],{"class":654},[431,2394,2241],{"class":437},[431,2396,2397],{"class":455},"  # 48.0\n",[431,2399,2400,2403,2405,2408,2410,2413],{"class":433,"line":578},[431,2401,2402],{"class":441},"rubles_count ",[431,2404,1189],{"class":654},[431,2406,2407],{"class":441}," euro_count ",[431,2409,1357],{"class":654},[431,2411,2412],{"class":441}," rubles_per_euro  ",[431,2414,2415],{"class":455},"# 5040.0\n",[431,2417,2418,2420],{"class":433,"line":584},[431,2419,438],{"class":437},[431,2421,2422],{"class":441},"(rubles_count)\n",[415,2424,2425],{},"Теперь добавим к выводу текст с помощью конкатенации:",[422,2427,2429],{"className":424,"code":2428,"language":396,"meta":426,"style":426},"rubles_per_euro = 105\neuro_count = 50 * 0.96  # 48.0\nrubles_count = euro_count * rubles_per_euro  # 5040.0\n# Функция str() превращает число в строку.\nprint('У вас получилось: ' + str(rubles_count) + ' рублей.')\n# => У вас получилось: 5040.0 рублей.\n",[428,2430,2431,2439,2453,2467,2472,2496],{"__ignoreMap":426},[431,2432,2433,2435,2437],{"class":433,"line":434},[431,2434,2377],{"class":441},[431,2436,1189],{"class":654},[431,2438,2382],{"class":437},[431,2440,2441,2443,2445,2447,2449,2451],{"class":433,"line":452},[431,2442,2192],{"class":441},[431,2444,1189],{"class":654},[431,2446,2197],{"class":437},[431,2448,897],{"class":654},[431,2450,2241],{"class":437},[431,2452,2397],{"class":455},[431,2454,2455,2457,2459,2461,2463,2465],{"class":433,"line":578},[431,2456,2402],{"class":441},[431,2458,1189],{"class":654},[431,2460,2407],{"class":441},[431,2462,1357],{"class":654},[431,2464,2412],{"class":441},[431,2466,2415],{"class":455},[431,2468,2469],{"class":433,"line":584},[431,2470,2471],{"class":455},"# Функция str() превращает число в строку.\n",[431,2473,2474,2476,2478,2481,2483,2486,2489,2491,2494],{"class":433,"line":1244},[431,2475,438],{"class":437},[431,2477,442],{"class":441},[431,2479,2480],{"class":445},"'У вас получилось: '",[431,2482,655],{"class":654},[431,2484,2485],{"class":437}," str",[431,2487,2488],{"class":441},"(rubles_count) ",[431,2490,802],{"class":654},[431,2492,2493],{"class":445}," ' рублей.'",[431,2495,449],{"class":441},[431,2497,2498],{"class":433,"line":1985},[431,2499,2500],{"class":455},"# => У вас получилось: 5040.0 рублей.\n",[415,2502,2503],{},"Любая переменная может быть частью любого выражения. В момент вычисления вместо имени переменной подставляется ее значение.\nИнтерпретатор вычисляет значение euro_count до того, как эта переменная начнет использоваться в других выражениях.\nКогда подходит момент использования переменной, Python уже знает значение, потому что вычислил его.\nС помощью переменных можно проводить сложные вычисления, а также делать подробный вывод с получившимся значением.\nНо еще можно получать новые выражения посредством склеивания двух и более значений переменных. За это отвечает конкатенация.",[458,2505,2507],{"id":2506},"переменные-и-конкатенация","Переменные и конкатенация",[415,2509,2510],{},"Попробуем использовать переменные с конкатенацией, при этом синтаксически ничего не поменяется. Вот как конкатенировать две строки:",[422,2512,2514],{"className":424,"code":2513,"language":396,"meta":426,"style":426},"author = \"Jack \" + \"London\"\nprint(author)  # => Jack London\n",[428,2515,2516,2529],{"__ignoreMap":426},[431,2517,2518,2520,2522,2524,2526],{"class":433,"line":434},[431,2519,2347],{"class":441},[431,2521,1189],{"class":654},[431,2523,2352],{"class":445},[431,2525,655],{"class":654},[431,2527,2528],{"class":445}," \"London\"\n",[431,2530,2531,2533,2536],{"class":433,"line":452},[431,2532,438],{"class":437},[431,2534,2535],{"class":441},"(author)  ",[431,2537,2538],{"class":455},"# => Jack London\n",[415,2540,2541],{},"Значит, также можно склеить строку и одну переменную, в которой записана строка:",[422,2543,2545],{"className":424,"code":2544,"language":396,"meta":426,"style":426},"first_name = \"Jack\"\nauthor = first_name + \" London\"\nprint(author)  # => Jack London\n",[428,2546,2547,2557,2571],{"__ignoreMap":426},[431,2548,2549,2552,2554],{"class":433,"line":434},[431,2550,2551],{"class":441},"first_name ",[431,2553,1189],{"class":654},[431,2555,2556],{"class":445}," \"Jack\"\n",[431,2558,2559,2561,2563,2566,2568],{"class":433,"line":452},[431,2560,2347],{"class":441},[431,2562,1189],{"class":654},[431,2564,2565],{"class":441}," first_name ",[431,2567,802],{"class":654},[431,2569,2570],{"class":445}," \" London\"\n",[431,2572,2573,2575,2577],{"class":433,"line":578},[431,2574,438],{"class":437},[431,2576,2535],{"class":441},[431,2578,2538],{"class":455},[415,2580,2581],{},"А еще можно конкатенировать две или три переменные и т.д., в которых записаны строки:",[422,2583,2585],{"className":424,"code":2584,"language":396,"meta":426,"style":426},"first_name = \"Jack\"\nlast_name = \"London\"\nauthor = first_name + \" \" + last_name\nprint(author)  # => Jack London\n",[428,2586,2587,2595,2604,2622],{"__ignoreMap":426},[431,2588,2589,2591,2593],{"class":433,"line":434},[431,2590,2551],{"class":441},[431,2592,1189],{"class":654},[431,2594,2556],{"class":445},[431,2596,2597,2600,2602],{"class":433,"line":452},[431,2598,2599],{"class":441},"last_name ",[431,2601,1189],{"class":654},[431,2603,2528],{"class":445},[431,2605,2606,2608,2610,2612,2614,2617,2619],{"class":433,"line":578},[431,2607,2347],{"class":441},[431,2609,1189],{"class":654},[431,2611,2565],{"class":441},[431,2613,802],{"class":654},[431,2615,2616],{"class":445}," \" \"",[431,2618,655],{"class":654},[431,2620,2621],{"class":441}," last_name\n",[431,2623,2624,2626,2628],{"class":433,"line":584},[431,2625,438],{"class":437},[431,2627,2535],{"class":441},[431,2629,2538],{"class":455},[415,2631,2632],{},"Переменные — важный инструмент в программировании. Они упрощают сложные вычисления и таким образом облегчают разработку.\nНо, чтобы успешно работать с переменными, надо не только правильно использовать их, но и правильно называть.",[632,2634,2636],{"id":2635},"именование-переменных","Именование переменных",[415,2638,2639],{},"Представьте следующую программу:",[422,2641,2643],{"className":424,"code":2642,"language":396,"meta":426,"style":426},"x = 'Привет!'\nprint(x)\n",[428,2644,2645,2653],{"__ignoreMap":426},[431,2646,2647,2649,2651],{"class":433,"line":434},[431,2648,1186],{"class":441},[431,2650,1189],{"class":654},[431,2652,1964],{"class":445},[431,2654,2655,2657],{"class":433,"line":452},[431,2656,438],{"class":437},[431,2658,2659],{"class":441},"(x)\n",[415,2661,2662],{},"С подобной программой мы уже работали, но сейчас в ней изменилось имя переменной на x.",[415,2664,2665],{},"Компьютеру без разницы, как мы именуем ту или иную переменную. Названия важны только людям. Обычно программисты гораздо чаще читают чужой код, чем пишут свой.\nЧтобы другие смогли с легкостью прочитать и проанализировать ваш код, нужно понятно называть переменные.\nВажно придумать понятное название, которое отражает смысл переменной. При этом важно давать такие имена, которые будут понимать без контекста, без изучения окружающего кода.\nСуществует общепринятое правило: не используйте транслит для имен — только английский язык. Если вы испытываете сложности с английским, то пользуйтесь переводчиком.\nСо временем, анализируя чужой код, вы научитесь правильно именовать переменные.\nСреди разработчиков есть шутка: «Названия переменных — это одна из самых сложных вещей в программировании». Придумывать названия и правда сложно.\nНапример, сложно назвать переменную, в которой хранится количество неоплаченных заказов от клиентов с задолженностью в предыдущем квартале.",[415,2667,2668],{},"Чтобы проверить себя, попробуйте сделать такое задание:\nПридумайте название для переменной, в которой будет храниться «количество братьев и сестер».\nЗапишите его в блокноте или отправьте себе на почту. Не указывайте там ничего, кроме названия переменной. А потом через пару месяцев попытайтесь вспомнить что это значило.",[415,2670,2671],{},"Теперь разберем, как придумывать простые и понятные имена переменных.",[458,2673,2636],{"id":2674},"именование-переменных-1",[415,2676,2677],{},"greeting — пример простого имени, но не все имена так просты. Часто они включают в себя несколько слов: например, «имя пользователя».\nВ разных языках применяются разные стили кодирования, и имя переменной будет отличаться.",[415,2679,2680],{},"К именованию переменных есть три основных подхода, которые иногда комбинируют друг с другом. Все эти подходы проявляют себя, когда имя переменной состоит из нескольких слов:",[697,2682,2683,2686,2689],{},[700,2684,2685],{},"kebab-case — составные части переменной разделяются дефисом (my-super-var)",[700,2687,2688],{},"snake_case — для разделения используется подчеркивание (my_super_var)",[700,2690,2691],{},"CamelCase — каждое слово в переменной пишется с заглавной буквы (MySuperVar)",[415,2693,2694,2695,2699],{},"Переменные в Python именуются в стиле snake_case: слова записываются строчными буквами и разделяются символом подчеркивания _. Чтобы разобраться подробнее, можете изучить раздел «Как называть переменные» в стандарте PEP8 ",[1205,2696,2697],{"href":2697,"rel":2698},"https:\u002F\u002Fpeps.python.org\u002Fpep-0008\u002F#method-names-and-instance-variables",[1209],".",[415,2701,2702],{},"Далее посмотрим пример плохих практик и разберем, почему их стоит избегать.",[458,2704,2706],{"id":2705},"магические-числа","Магические числа",[415,2708,2709],{},"Возьмем пример программы, которая считает курс валют:",[422,2711,2712],{"className":424,"code":2370,"language":396,"meta":426,"style":426},[428,2713,2714,2722,2736,2750],{"__ignoreMap":426},[431,2715,2716,2718,2720],{"class":433,"line":434},[431,2717,2377],{"class":441},[431,2719,1189],{"class":654},[431,2721,2382],{"class":437},[431,2723,2724,2726,2728,2730,2732,2734],{"class":433,"line":452},[431,2725,2192],{"class":441},[431,2727,1189],{"class":654},[431,2729,2197],{"class":437},[431,2731,897],{"class":654},[431,2733,2241],{"class":437},[431,2735,2397],{"class":455},[431,2737,2738,2740,2742,2744,2746,2748],{"class":433,"line":578},[431,2739,2402],{"class":441},[431,2741,1189],{"class":654},[431,2743,2407],{"class":441},[431,2745,1357],{"class":654},[431,2747,2412],{"class":441},[431,2749,2415],{"class":455},[431,2751,2752,2754],{"class":433,"line":584},[431,2753,438],{"class":437},[431,2755,2422],{"class":441},[415,2757,2758],{},"С точки зрения профессиональной разработки, такой код не соответствует «лучшим практикам» — best practices.\nВ этом примере сложно понять, что значат числа 50 и 0.96. Представьте, что вам придется разбираться в этом коде через месяц или через год — это будет сложно.\nТакже сложно будет программисту, который не видел код ранее.\nВ нашем примере контекст легко восстановить, потому что переменные названы грамотно.\nНо в реальных проектах код значительно сложнее, поэтому понять смысл чисел зачастую невозможно.\nПроблема кроется в «магических числах» — magic numbers.\nЭто числа, происхождение которых невозможно понять с первого взгляда — приходится глубоко вникать в то, что происходит в коде.\nЧтобы предотвратить проблему, нужно создавать переменные с правильными именами. Так все встанет на свои места:",[422,2760,2762],{"className":424,"code":2761,"language":396,"meta":426,"style":426},"euro_per_dollars = 0.96\nrubles_per_euro = 105\ndollars_count = 50\neuro_count = dollars_count * euro_per_dollars # 48.0\nrubles_count = euro_count * rubles_per_euro   # 5040.0\nprint(rubles_count)\n",[428,2763,2764,2773,2781,2791,2808,2823],{"__ignoreMap":426},[431,2765,2766,2769,2771],{"class":433,"line":434},[431,2767,2768],{"class":441},"euro_per_dollars ",[431,2770,1189],{"class":654},[431,2772,2202],{"class":437},[431,2774,2775,2777,2779],{"class":433,"line":452},[431,2776,2377],{"class":441},[431,2778,1189],{"class":654},[431,2780,2382],{"class":437},[431,2782,2783,2786,2788],{"class":433,"line":578},[431,2784,2785],{"class":441},"dollars_count ",[431,2787,1189],{"class":654},[431,2789,2790],{"class":437}," 50\n",[431,2792,2793,2795,2797,2800,2802,2805],{"class":433,"line":584},[431,2794,2192],{"class":441},[431,2796,1189],{"class":654},[431,2798,2799],{"class":441}," dollars_count ",[431,2801,1357],{"class":654},[431,2803,2804],{"class":441}," euro_per_dollars ",[431,2806,2807],{"class":455},"# 48.0\n",[431,2809,2810,2812,2814,2816,2818,2821],{"class":433,"line":1244},[431,2811,2402],{"class":441},[431,2813,1189],{"class":654},[431,2815,2407],{"class":441},[431,2817,1357],{"class":654},[431,2819,2820],{"class":441}," rubles_per_euro   ",[431,2822,2415],{"class":455},[431,2824,2825,2827],{"class":433,"line":1985},[431,2826,438],{"class":437},[431,2828,2422],{"class":441},[415,2830,2831],{},"В этой программе:",[697,2833,2834,2837],{},[700,2835,2836],{},"Используется именование snake_case.",[700,2838,2839],{},"Две новые переменные отделяются от последующих вычислений пустой строчкой. Эти переменные имеют смысл и без вычислений, поэтому такое отделение уместно, потому что повышает читаемость.",[415,2841,2842],{},"Получился хорошо именованный и структурированный код, но он длиннее прошлой версии. Так часто бывает — это нормально, ведь код должен быть читабельным.\nМагические числа и непонятные именования переменных не ломают код, но делают его менее читабельным.\nНужно понимать, что компьютер в любом случае выполнит заданное вычисление. Однако другой программист будет читать код и ничего не поймет — это усложнит работу.\nПравильное именование переменных — половина успеха анализа кода.",[415,2844,1849,2845,1853,2847,1857],{},[800,2846,1852],{},[800,2848,1856],{},[1859,2850],{},[1862,2852,2853],{},"html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}",{"title":426,"searchDepth":452,"depth":1244,"links":2855},[2856],{"id":1901,"depth":452,"text":1902,"children":2857},[2858,2859,2860,2861,2862,2866],{"id":1908,"depth":578,"text":1909},{"id":2051,"depth":578,"text":2052},{"id":2100,"depth":578,"text":2101},{"id":2129,"depth":578,"text":2130},{"id":2168,"depth":578,"text":2169,"children":2863},[2864,2865],{"id":2175,"depth":584,"text":2176},{"id":2506,"depth":584,"text":2507},{"id":2635,"depth":578,"text":2636,"children":2867},[2868,2869],{"id":2674,"depth":584,"text":2636},{"id":2705,"depth":584,"text":2706},"2025-01-21","Использование и именование переменных","images\u002Fblog\u002Fpython\u002Fst2\u002Fimg.png",{},20,{"title":234,"description":2871},"eyX3kxdUKVh8brrG6LqYbzxrgb97BZo-nuQsYCZlDLI",{"id":2878,"title":278,"author":2879,"body":2881,"date":4082,"description":4083,"extension":1887,"image":4084,"meta":4085,"minRead":4086,"navigation":393,"num":578,"path":279,"seo":4087,"stem":280,"__hash__":4088},"python\u002Fblog\u002Fpython\u002Fst3.md",{"name":402,"avatar":2880},{"src":404,"alt":405},{"type":407,"value":2882,"toc":4067},[2883,2887,2890,2894,2900,2954,2957,3020,3030,3081,3084,3088,3091,3116,3119,3139,3142,3165,3181,3184,3247,3261,3264,3268,3271,3275,3278,3309,3316,3363,3366,3397,3400,3404,3407,3434,3437,3470,3473,3477,3480,3484,3490,3532,3535,3579,3585,3631,3634,3674,3677,3734,3737,3741,3744,3777,3780,3824,3827,3854,3857,3891,3894,3935,3938,4053,4056,4062,4064],[410,2884,2886],{"id":2885},"работа-со-строками-в-python","Работа со строками в Python",[415,2888,2889],{},"Вы уже знаете, как перенести строку или соединить несколько строк в одну.\nНо в программировании есть ещё операции со строками которые повышают читаемость кода и делают решения многих задач проще.",[632,2891,2893],{"id":2892},"интерполяция","Интерполяция",[415,2895,2896,2897,2899],{},"Базовый способ соединения строк — ",[800,2898,1707],{},". С помощью конкатенации строки «суммируются» друг с другом, как в примере ниже:",[422,2901,2903],{"className":424,"code":2902,"language":396,"meta":426,"style":426},"first_name = 'Jack'\nlast_name = 'London'\n\nprint(first_name + \" \" + last_name + \"!\")\n# => Jack London!\n",[428,2904,2905,2914,2922,2926,2949],{"__ignoreMap":426},[431,2906,2907,2909,2911],{"class":433,"line":434},[431,2908,2551],{"class":441},[431,2910,1189],{"class":654},[431,2912,2913],{"class":445}," 'Jack'\n",[431,2915,2916,2918,2920],{"class":433,"line":452},[431,2917,2599],{"class":441},[431,2919,1189],{"class":654},[431,2921,2357],{"class":445},[431,2923,2924],{"class":433,"line":578},[431,2925,1662],{"emptyLinePlaceholder":393},[431,2927,2928,2930,2933,2935,2937,2939,2942,2944,2947],{"class":433,"line":584},[431,2929,438],{"class":437},[431,2931,2932],{"class":441},"(first_name ",[431,2934,802],{"class":654},[431,2936,2616],{"class":445},[431,2938,655],{"class":654},[431,2940,2941],{"class":441}," last_name ",[431,2943,802],{"class":654},[431,2945,2946],{"class":445}," \"!\"",[431,2948,449],{"class":441},[431,2950,2951],{"class":433,"line":1244},[431,2952,2953],{"class":455},"# => Jack London!\n",[415,2955,2956],{},"Конкатенация работает просто, но выглядит не всегда наглядно. Из-за кавычек сложно разглядеть то, каким будет конечный результат.\nИ чем сложнее устроена строка, тем запутаннее она начнет выглядеть. У конкатенации есть альтернатива — интерполяция. Вот как это выглядит:",[422,2958,2960],{"className":424,"code":2959,"language":396,"meta":426,"style":426},"first_name = 'Jack'\nlast_name = 'London'\n\nprint(f'{first_name} {last_name}!')\n# => Jack London!\n",[428,2961,2962,2970,2978,2982,3016],{"__ignoreMap":426},[431,2963,2964,2966,2968],{"class":433,"line":434},[431,2965,2551],{"class":441},[431,2967,1189],{"class":654},[431,2969,2913],{"class":445},[431,2971,2972,2974,2976],{"class":433,"line":452},[431,2973,2599],{"class":441},[431,2975,1189],{"class":654},[431,2977,2357],{"class":445},[431,2979,2980],{"class":433,"line":578},[431,2981,1662],{"emptyLinePlaceholder":393},[431,2983,2984,2986,2988,2991,2994,2997,3000,3003,3006,3009,3011,3014],{"class":433,"line":584},[431,2985,438],{"class":437},[431,2987,442],{"class":441},[431,2989,2990],{"class":654},"f",[431,2992,2993],{"class":445},"'",[431,2995,2996],{"class":437},"{",[431,2998,2999],{"class":441},"first_name",[431,3001,3002],{"class":437},"}",[431,3004,3005],{"class":437}," {",[431,3007,3008],{"class":441},"last_name",[431,3010,3002],{"class":437},[431,3012,3013],{"class":445},"!'",[431,3015,449],{"class":441},[431,3017,3018],{"class":433,"line":1244},[431,3019,2953],{"class":455},[415,3021,3022,3023,3025,3026,3029],{},"Буква ",[800,3024,2990],{}," указывает на то, что мы создаем ",[800,3027,3028],{},"f-строку"," — шаблон, в который с помощью фигурных скобок подставляются значения переменных. На выходе получается обычная строка.\nРассмотрим такой пример:",[422,3031,3033],{"className":424,"code":3032,"language":396,"meta":426,"style":426},"lesson = 'Информатика'\n\nbest_subject = f'{lesson} - лучший предмет!'\nprint(best_subject)  # => Информатика - лучший предмет!\n",[428,3034,3035,3045,3049,3071],{"__ignoreMap":426},[431,3036,3037,3040,3042],{"class":433,"line":434},[431,3038,3039],{"class":441},"lesson ",[431,3041,1189],{"class":654},[431,3043,3044],{"class":445}," 'Информатика'\n",[431,3046,3047],{"class":433,"line":452},[431,3048,1662],{"emptyLinePlaceholder":393},[431,3050,3051,3054,3056,3059,3061,3063,3066,3068],{"class":433,"line":578},[431,3052,3053],{"class":441},"best_subject ",[431,3055,1189],{"class":654},[431,3057,3058],{"class":654}," f",[431,3060,2993],{"class":445},[431,3062,2996],{"class":437},[431,3064,3065],{"class":441},"lesson",[431,3067,3002],{"class":437},[431,3069,3070],{"class":445}," - лучший предмет!'\n",[431,3072,3073,3075,3078],{"class":433,"line":584},[431,3074,438],{"class":437},[431,3076,3077],{"class":441},"(best_subject)  ",[431,3079,3080],{"class":455},"# => Информатика - лучший предмет!\n",[415,3082,3083],{},"Почти во всех языках для объединения строк интерполяция предпочтительнее конкатенации.\nСтрока при этом получается склеенная, и внутри нее хорошо просматриваются пробелы и другие символы.\nИнтерполяция помогает сделать код более понятным для разработчиков. Но это не единственная полезная альтернатива.\nДалее разберемся, как объявлять многострочную строку и не использовать символ новой строки \\n.",[458,3085,3087],{"id":3086},"multi-line-строки","Multi-line строки",[415,3089,3090],{},"Представьте, что нужно определить строку, которая состоит из нескольких строчек — то есть внутри есть переводы строки \\n. Например, она будет выглядеть так:",[422,3092,3094],{"className":424,"code":3093,"language":396,"meta":426,"style":426},"text = 'Пример текста,\\nсостоящего из\\nнескольких строк'\n",[428,3095,3096],{"__ignoreMap":426},[431,3097,3098,3101,3103,3106,3108,3111,3113],{"class":433,"line":434},[431,3099,3100],{"class":441},"text ",[431,3102,1189],{"class":654},[431,3104,3105],{"class":445}," 'Пример текста,",[431,3107,1540],{"class":437},[431,3109,3110],{"class":445},"состоящего из",[431,3112,1540],{"class":437},[431,3114,3115],{"class":445},"нескольких строк'\n",[415,3117,3118],{},"На печати строка примет совсем другой вид:",[422,3120,3122],{"className":1436,"code":3121,"language":1438,"meta":426,"style":426},"Пример текста,\nсостоящего из\nнескольких строк\n",[428,3123,3124,3129,3134],{"__ignoreMap":426},[431,3125,3126],{"class":433,"line":434},[431,3127,3128],{},"Пример текста,\n",[431,3130,3131],{"class":433,"line":452},[431,3132,3133],{},"состоящего из\n",[431,3135,3136],{"class":433,"line":578},[431,3137,3138],{},"нескольких строк\n",[415,3140,3141],{},"Для таких ситуаций в Python есть еще один способ создания строк, который называется multi-line строки.\nЧтобы описать такую «многострочную строку», нужно заключить ее в тройные кавычки — \"\"\" или '''.\nВнутри multi-line строки можно переносить текст и не использовать перевод строки \\n:",[422,3143,3145],{"className":424,"code":3144,"language":396,"meta":426,"style":426},"text = '''Пример текста,\nсостоящего из\nнескольких строк'''\n",[428,3146,3147,3156,3160],{"__ignoreMap":426},[431,3148,3149,3151,3153],{"class":433,"line":434},[431,3150,3100],{"class":441},[431,3152,1189],{"class":654},[431,3154,3155],{"class":445}," '''Пример текста,\n",[431,3157,3158],{"class":433,"line":452},[431,3159,3133],{"class":445},[431,3161,3162],{"class":433,"line":578},[431,3163,3164],{"class":445},"нескольких строк'''\n",[422,3166,3167],{"className":1436,"code":3121,"language":1438,"meta":426,"style":426},[428,3168,3169,3173,3177],{"__ignoreMap":426},[431,3170,3171],{"class":433,"line":434},[431,3172,3128],{},[431,3174,3175],{"class":433,"line":452},[431,3176,3133],{},[431,3178,3179],{"class":433,"line":578},[431,3180,3138],{},[415,3182,3183],{},"Благодаря тройным кавычкам multi-line строки позволяют не экранировать кавычки внутри строки.\nЕще multi-line строки могут становиться f-строками для интерполяции:",[422,3185,3187],{"className":424,"code":3186,"language":396,"meta":426,"style":426},"a = 'A'\nb = 'B'\ntext = f'''{a} и {b}\nсидели на трубе\n'''\n",[428,3188,3189,3199,3209,3237,3242],{"__ignoreMap":426},[431,3190,3191,3194,3196],{"class":433,"line":434},[431,3192,3193],{"class":441},"a ",[431,3195,1189],{"class":654},[431,3197,3198],{"class":445}," 'A'\n",[431,3200,3201,3204,3206],{"class":433,"line":452},[431,3202,3203],{"class":441},"b ",[431,3205,1189],{"class":654},[431,3207,3208],{"class":445}," 'B'\n",[431,3210,3211,3213,3215,3217,3220,3222,3224,3226,3229,3231,3234],{"class":433,"line":578},[431,3212,3100],{"class":441},[431,3214,1189],{"class":654},[431,3216,3058],{"class":654},[431,3218,3219],{"class":445},"'''",[431,3221,2996],{"class":437},[431,3223,1205],{"class":441},[431,3225,3002],{"class":437},[431,3227,3228],{"class":445}," и ",[431,3230,2996],{"class":437},[431,3232,3233],{"class":441},"b",[431,3235,3236],{"class":437},"}\n",[431,3238,3239],{"class":433,"line":584},[431,3240,3241],{"class":445},"сидели на трубе\n",[431,3243,3244],{"class":433,"line":1244},[431,3245,3246],{"class":445},"'''\n",[422,3248,3250],{"className":1436,"code":3249,"language":1438,"meta":426,"style":426},"А и B\nсидели на трубе\n",[428,3251,3252,3257],{"__ignoreMap":426},[431,3253,3254],{"class":433,"line":434},[431,3255,3256],{},"А и B\n",[431,3258,3259],{"class":433,"line":452},[431,3260,3241],{},[415,3262,3263],{},"Для компьютера не важно, какие способы соединения и переноса строк вы будете использовать.\nИнтерполяция и multi-line строки используются для удобства разработчиков, чтобы им было проще читать код.",[632,3265,3267],{"id":3266},"извлечение-символов-из-строки","Извлечение символов из строки",[415,3269,3270],{},"Иногда нужно получить один символ из строки. Например, если сайт знает имя и фамилию пользователя, и в какой-то момент требуется вывести эту информацию в формате И. Иванов.\nДля этого компьютеру потребуется взять первый символ из имени. В Python есть подходящая операция.",[458,3272,3274],{"id":3273},"извлечение-элемента-по-индексу","Извлечение элемента по индексу",[415,3276,3277],{},"Представим, что из имени Иван нужно вывести на экран только первую букву. Это выглядит так:",[422,3279,3281],{"className":424,"code":3280,"language":396,"meta":426,"style":426},"name = 'Иван'\nprint(name[0])  # => И\n",[428,3282,3283,3293],{"__ignoreMap":426},[431,3284,3285,3288,3290],{"class":433,"line":434},[431,3286,3287],{"class":441},"name ",[431,3289,1189],{"class":654},[431,3291,3292],{"class":445}," 'Иван'\n",[431,3294,3295,3297,3300,3303,3306],{"class":433,"line":452},[431,3296,438],{"class":437},[431,3298,3299],{"class":441},"(name[",[431,3301,3302],{"class":437},"0",[431,3304,3305],{"class":441},"])  ",[431,3307,3308],{"class":455},"# => И\n",[415,3310,3311,3312,3315],{},"Операция с квадратными скобками с цифрой извлекает элемент по ",[800,3313,3314],{},"индексу"," — позиции символа внутри строки.\nИндексы начинаются с 0 почти во всех языках программирования. Поэтому, чтобы получить первый символ, нужно указать индекс 0.\nИндекс последнего элемента равен длине строки минус единица. Обращение к индексу за пределами строки приведет к ошибке:",[422,3317,3319],{"className":424,"code":3318,"language":396,"meta":426,"style":426},"# Длина строки 9, поэтому последний индекс — это 8\nfirst_name = 'Александр'\nprint(first_name[8])  # => р\nprint(first_name[9])  # => IndexError: string index out of range\n",[428,3320,3321,3326,3335,3349],{"__ignoreMap":426},[431,3322,3323],{"class":433,"line":434},[431,3324,3325],{"class":455},"# Длина строки 9, поэтому последний индекс — это 8\n",[431,3327,3328,3330,3332],{"class":433,"line":452},[431,3329,2551],{"class":441},[431,3331,1189],{"class":654},[431,3333,3334],{"class":445}," 'Александр'\n",[431,3336,3337,3339,3342,3344,3346],{"class":433,"line":578},[431,3338,438],{"class":437},[431,3340,3341],{"class":441},"(first_name[",[431,3343,1021],{"class":437},[431,3345,3305],{"class":441},[431,3347,3348],{"class":455},"# => р\n",[431,3350,3351,3353,3355,3358,3360],{"class":433,"line":584},[431,3352,438],{"class":437},[431,3354,3341],{"class":441},[431,3356,3357],{"class":437},"9",[431,3359,3305],{"class":441},[431,3361,3362],{"class":455},"# => IndexError: string index out of range\n",[415,3364,3365],{},"Чтобы лучше закрепить новые знания, посмотрите на код ниже и подумайте, что он выдаст:",[422,3367,3369],{"className":424,"code":3368,"language":396,"meta":426,"style":426},"x = '\\nyou'\nprint(x[1])\n",[428,3370,3371,3385],{"__ignoreMap":426},[431,3372,3373,3375,3377,3380,3382],{"class":433,"line":434},[431,3374,1186],{"class":441},[431,3376,1189],{"class":654},[431,3378,3379],{"class":445}," '",[431,3381,1540],{"class":437},[431,3383,3384],{"class":445},"you'\n",[431,3386,3387,3389,3392,3394],{"class":433,"line":452},[431,3388,438],{"class":437},[431,3390,3391],{"class":441},"(x[",[431,3393,1192],{"class":437},[431,3395,3396],{"class":441},"])\n",[415,3398,3399],{},"Бывают и нестандартные ситуации. Например, нужно вывести элемент с конца, причем из выражения с большим количеством символов.\nВ этом случае можно воспользоваться отрицательным индексом, который облегчит работу программиста.",[458,3401,3403],{"id":3402},"отрицательные-индексы","Отрицательные индексы",[415,3405,3406],{},"Допустимо использовать отрицательные индексы. В этом случае идет обращение к символам, начиная с конца строки.\n-1 — индекс последнего символа, -2 — предпоследнего и так далее. В отличие от прямой индексации, обратный отсчет идет от -1:",[422,3408,3410],{"className":424,"code":3409,"language":396,"meta":426,"style":426},"name = 'Александр'\nprint(name[-1])  # => р\n",[428,3411,3412,3420],{"__ignoreMap":426},[431,3413,3414,3416,3418],{"class":433,"line":434},[431,3415,3287],{"class":441},[431,3417,1189],{"class":654},[431,3419,3334],{"class":445},[431,3421,3422,3424,3426,3428,3430,3432],{"class":433,"line":452},[431,3423,438],{"class":437},[431,3425,3299],{"class":441},[431,3427,853],{"class":654},[431,3429,1192],{"class":437},[431,3431,3305],{"class":441},[431,3433,3348],{"class":455},[415,3435,3436],{},"Индексом может быть не только конкретное число, но и значение переменной. Посмотрите на пример ниже.\nЗдесь записали индекс внутри квадратных скобок не числом, а переменной.\nТакой код приведет к тому же результату — выводу на экран символа А:",[422,3438,3440],{"className":424,"code":3439,"language":396,"meta":426,"style":426},"name = 'Александр'\ni = 0\nprint(name[i])  # => А\n",[428,3441,3442,3450,3460],{"__ignoreMap":426},[431,3443,3444,3446,3448],{"class":433,"line":434},[431,3445,3287],{"class":441},[431,3447,1189],{"class":654},[431,3449,3334],{"class":445},[431,3451,3452,3455,3457],{"class":433,"line":452},[431,3453,3454],{"class":441},"i ",[431,3456,1189],{"class":654},[431,3458,3459],{"class":437}," 0\n",[431,3461,3462,3464,3467],{"class":433,"line":578},[431,3463,438],{"class":437},[431,3465,3466],{"class":441},"(name[i])  ",[431,3468,3469],{"class":455},"# => А\n",[415,3471,3472],{},"Чтобы выводить из выражения лишь некоторые символы, не нужно писать большое количество строк кода — достаточно извлечь элемент с помощью индекса.\nТакже можно пользоваться отрицательным индексом, чтобы легче выводить символы с конца выражения.\nДалее разберемся, как с помощью этих знаний можно извлекать подстроки из строки.",[632,3474,3476],{"id":3475},"срезы-строк","Срезы строк",[415,3478,3479],{},"Когда идёт работа со строками в программировании, из них регулярно приходится извлекать некую часть.\nНапример, нам нужно выяснить, присутствует ли меньшая строка внутри большей.",[458,3481,3483],{"id":3482},"подстрока-и-срезы-для-строк","Подстрока и срезы для строк",[415,3485,3486,3489],{},[800,3487,3488],{},"Подстрока"," — это некоторая часть строки, которую нужно найти и извлечь.\nПредставим, что у нас есть дата в таком формате: 24-01-2025. Нам нужно извлечь из нее подстроку, в которую входит только год.\nЕсли подумать логически, то нужно посчитать индекс символа, с которого начинается год, и затем извлечь четыре символа.\nИндексы в строке начинаются с нуля, значит, первый символ года доступен по индексу 6, а последний символ — по индексу 9. Проверим:",[422,3491,3493],{"className":424,"code":3492,"language":396,"meta":426,"style":426},"data = '12-08-2025'\nprint(data[6])  # => 2\nprint(data[9])  # => 5\n",[428,3494,3495,3505,3519],{"__ignoreMap":426},[431,3496,3497,3500,3502],{"class":433,"line":434},[431,3498,3499],{"class":441},"data ",[431,3501,1189],{"class":654},[431,3503,3504],{"class":445}," '12-08-2025'\n",[431,3506,3507,3509,3512,3514,3516],{"class":433,"line":452},[431,3508,438],{"class":437},[431,3510,3511],{"class":441},"(data[",[431,3513,742],{"class":437},[431,3515,3305],{"class":441},[431,3517,3518],{"class":455},"# => 2\n",[431,3520,3521,3523,3525,3527,3529],{"class":433,"line":578},[431,3522,438],{"class":437},[431,3524,3511],{"class":441},[431,3526,3357],{"class":437},[431,3528,3305],{"class":441},[431,3530,3531],{"class":455},"# => 5\n",[415,3533,3534],{},"Зная эти индексы, можно воспользоваться срезами и получить нужную подстроку:",[422,3536,3538],{"className":424,"code":3537,"language":396,"meta":426,"style":426},"data = '12-08-2025'\nyear = data[6:10]\nprint(year)  # => 2025\n",[428,3539,3540,3548,3569],{"__ignoreMap":426},[431,3541,3542,3544,3546],{"class":433,"line":434},[431,3543,3499],{"class":441},[431,3545,1189],{"class":654},[431,3547,3504],{"class":445},[431,3549,3550,3553,3555,3558,3560,3563,3566],{"class":433,"line":452},[431,3551,3552],{"class":441},"year ",[431,3554,1189],{"class":654},[431,3556,3557],{"class":441}," data[",[431,3559,742],{"class":437},[431,3561,3562],{"class":441},":",[431,3564,3565],{"class":437},"10",[431,3567,3568],{"class":441},"]\n",[431,3570,3571,3573,3576],{"class":433,"line":578},[431,3572,438],{"class":437},[431,3574,3575],{"class":441},"(year)  ",[431,3577,3578],{"class":455},"# => 2025\n",[415,3580,3581,3584],{},[800,3582,3583],{},"Срезы для строк в Python"," — это механизм, с помощью которого извлекается подстрока по указанным параметрам.\nВ примере выше создаётся подстрока с 6 индекса до 10 индекса, не включая, то есть с 6 по 9. Формула выглядит так:[начальный индекс:конечный индекс]. Примеры:",[422,3586,3588],{"className":424,"code":3587,"language":396,"meta":426,"style":426},"data = '24-01-2025'\ndata[1:2]  # '4'\ndata[3:5]  # '01'\n",[428,3589,3590,3599,3616],{"__ignoreMap":426},[431,3591,3592,3594,3596],{"class":433,"line":434},[431,3593,3499],{"class":441},[431,3595,1189],{"class":654},[431,3597,3598],{"class":445}," '24-01-2025'\n",[431,3600,3601,3604,3606,3608,3610,3613],{"class":433,"line":452},[431,3602,3603],{"class":441},"data[",[431,3605,1192],{"class":437},[431,3607,3562],{"class":441},[431,3609,651],{"class":437},[431,3611,3612],{"class":441},"]  ",[431,3614,3615],{"class":455},"# '4'\n",[431,3617,3618,3620,3622,3624,3626,3628],{"class":433,"line":578},[431,3619,3603],{"class":441},[431,3621,971],{"class":437},[431,3623,3562],{"class":441},[431,3625,856],{"class":437},[431,3627,3612],{"class":441},[431,3629,3630],{"class":455},"# '01'\n",[415,3632,3633],{},"Срезы — механизм с большим количеством вариаций. Например, если не указать вторую границу, то извлечение произойдет до конца строки.\nТо же самое с первой границей — началом строки:",[422,3635,3637],{"className":424,"code":3636,"language":396,"meta":426,"style":426},"value = 'Python'\nvalue[3:]  # 'hon'\nvalue[:3]  # 'Pyt'\n",[428,3638,3639,3649,3662],{"__ignoreMap":426},[431,3640,3641,3644,3646],{"class":433,"line":434},[431,3642,3643],{"class":441},"value ",[431,3645,1189],{"class":654},[431,3647,3648],{"class":445}," 'Python'\n",[431,3650,3651,3654,3656,3659],{"class":433,"line":452},[431,3652,3653],{"class":441},"value[",[431,3655,971],{"class":437},[431,3657,3658],{"class":441},":]  ",[431,3660,3661],{"class":455},"# 'hon'\n",[431,3663,3664,3667,3669,3671],{"class":433,"line":578},[431,3665,3666],{"class":441},"value[:",[431,3668,971],{"class":437},[431,3670,3612],{"class":441},[431,3672,3673],{"class":455},"# 'Pyt'\n",[415,3675,3676],{},"Можно указать даже отрицательные индексы. В таком случае отсчет идет с обратной стороны:",[422,3678,3680],{"className":424,"code":3679,"language":396,"meta":426,"style":426},"value = 'Python'\n# Правая граница отрицательная. Считаем -1 от конца строки\nvalue[3:-1]  # 'ho'\n# Левая граница отрицательная. Считаем -5 от конца строки\nvalue[-5:3]  # 'yt'\n",[428,3681,3682,3690,3695,3712,3717],{"__ignoreMap":426},[431,3683,3684,3686,3688],{"class":433,"line":434},[431,3685,3643],{"class":441},[431,3687,1189],{"class":654},[431,3689,3648],{"class":445},[431,3691,3692],{"class":433,"line":452},[431,3693,3694],{"class":455},"# Правая граница отрицательная. Считаем -1 от конца строки\n",[431,3696,3697,3699,3701,3703,3705,3707,3709],{"class":433,"line":578},[431,3698,3653],{"class":441},[431,3700,971],{"class":437},[431,3702,3562],{"class":441},[431,3704,853],{"class":654},[431,3706,1192],{"class":437},[431,3708,3612],{"class":441},[431,3710,3711],{"class":455},"# 'ho'\n",[431,3713,3714],{"class":433,"line":584},[431,3715,3716],{"class":455},"# Левая граница отрицательная. Считаем -5 от конца строки\n",[431,3718,3719,3721,3723,3725,3727,3729,3731],{"class":433,"line":1244},[431,3720,3653],{"class":441},[431,3722,853],{"class":654},[431,3724,856],{"class":437},[431,3726,3562],{"class":441},[431,3728,971],{"class":437},[431,3730,3612],{"class":441},[431,3732,3733],{"class":455},"# 'yt'\n",[415,3735,3736],{},"У срезов два обязательных параметра, но иногда используется и третий.",[458,3738,3740],{"id":3739},"шаг-извлечения","Шаг извлечения",[415,3742,3743],{},"У срезов есть третий необязательный параметр — шаг извлечения. По умолчанию он равен единице, но можно его изменить:",[422,3745,3747],{"className":424,"code":3746,"language":396,"meta":426,"style":426},"data = 'Python'\ndata[1:5:2]   # => yh\n",[428,3748,3749,3757],{"__ignoreMap":426},[431,3750,3751,3753,3755],{"class":433,"line":434},[431,3752,3499],{"class":441},[431,3754,1189],{"class":654},[431,3756,3648],{"class":445},[431,3758,3759,3761,3763,3765,3767,3769,3771,3774],{"class":433,"line":452},[431,3760,3603],{"class":441},[431,3762,1192],{"class":437},[431,3764,3562],{"class":441},[431,3766,856],{"class":437},[431,3768,3562],{"class":441},[431,3770,651],{"class":437},[431,3772,3773],{"class":441},"]   ",[431,3775,3776],{"class":455},"# => yh\n",[415,3778,3779],{},"Все это можно комбинировать с открытыми границами, то есть без указания начала или конца:",[422,3781,3783],{"className":424,"code":3782,"language":396,"meta":426,"style":426},"value = 'Python'\nvalue[:5:2]  # 'Pto' символы берутся от начала до 5 индекса через один\nvalue[1::2]  # 'yhn' символы берутся от 1 индекса до конца через один\n",[428,3784,3785,3793,3808],{"__ignoreMap":426},[431,3786,3787,3789,3791],{"class":433,"line":434},[431,3788,3643],{"class":441},[431,3790,1189],{"class":654},[431,3792,3648],{"class":445},[431,3794,3795,3797,3799,3801,3803,3805],{"class":433,"line":452},[431,3796,3666],{"class":441},[431,3798,856],{"class":437},[431,3800,3562],{"class":441},[431,3802,651],{"class":437},[431,3804,3612],{"class":441},[431,3806,3807],{"class":455},"# 'Pto' символы берутся от начала до 5 индекса через один\n",[431,3809,3810,3812,3814,3817,3819,3821],{"class":433,"line":578},[431,3811,3653],{"class":441},[431,3813,1192],{"class":437},[431,3815,3816],{"class":441},"::",[431,3818,651],{"class":437},[431,3820,3612],{"class":441},[431,3822,3823],{"class":455},"# 'yhn' символы берутся от 1 индекса до конца через один\n",[415,3825,3826],{},"Шаг может быть отрицательным, в таком случае он берется с конца. На этом основан самый популярный способ использования шага — переворот строки:",[422,3828,3830],{"className":424,"code":3829,"language":396,"meta":426,"style":426},"value = 'Python'\nvalue[::-1]  # 'nohtyP'\n",[428,3831,3832,3840],{"__ignoreMap":426},[431,3833,3834,3836,3838],{"class":433,"line":434},[431,3835,3643],{"class":441},[431,3837,1189],{"class":654},[431,3839,3648],{"class":445},[431,3841,3842,3845,3847,3849,3851],{"class":433,"line":452},[431,3843,3844],{"class":441},"value[::",[431,3846,853],{"class":654},[431,3848,1192],{"class":437},[431,3850,3612],{"class":441},[431,3852,3853],{"class":455},"# 'nohtyP'\n",[415,3855,3856],{},"Если используется отрицательный шаг, и элементы среза извлекаются в обратном порядке, тогда и границы среза тоже нужно указывать в обратном порядке.\nПервой указывается правая граница среза, второй — левая:",[422,3858,3860],{"className":424,"code":3859,"language":396,"meta":426,"style":426},"value = 'Python'\nvalue[4:1:-1]  # 'oht'\n",[428,3861,3862,3870],{"__ignoreMap":426},[431,3863,3864,3866,3868],{"class":433,"line":434},[431,3865,3643],{"class":441},[431,3867,1189],{"class":654},[431,3869,3648],{"class":445},[431,3871,3872,3874,3876,3878,3880,3882,3884,3886,3888],{"class":433,"line":452},[431,3873,3653],{"class":441},[431,3875,762],{"class":437},[431,3877,3562],{"class":441},[431,3879,1192],{"class":437},[431,3881,3562],{"class":441},[431,3883,853],{"class":654},[431,3885,1192],{"class":437},[431,3887,3612],{"class":441},[431,3889,3890],{"class":455},"# 'oht'\n",[415,3892,3893],{},"Срезы можно указывать не только через числа, но и с использованием переменных:",[422,3895,3897],{"className":424,"code":3896,"language":396,"meta":426,"style":426},"value = 'Python'\nbegin = 1\nend = 5\nvalue[begin:end]  # 'ytho'\n",[428,3898,3899,3907,3917,3927],{"__ignoreMap":426},[431,3900,3901,3903,3905],{"class":433,"line":434},[431,3902,3643],{"class":441},[431,3904,1189],{"class":654},[431,3906,3648],{"class":445},[431,3908,3909,3912,3914],{"class":433,"line":452},[431,3910,3911],{"class":441},"begin ",[431,3913,1189],{"class":654},[431,3915,3916],{"class":437}," 1\n",[431,3918,3919,3922,3924],{"class":433,"line":578},[431,3920,3921],{"class":441},"end ",[431,3923,1189],{"class":654},[431,3925,3926],{"class":437}," 5\n",[431,3928,3929,3932],{"class":433,"line":584},[431,3930,3931],{"class":441},"value[begin:end]  ",[431,3933,3934],{"class":455},"# 'ytho'\n",[415,3936,3937],{},"Всё вместе:",[422,3939,3941],{"className":424,"code":3940,"language":396,"meta":426,"style":426},"value = 'Python'\nvalue[::]  # 'Python'  # Вся строка\nvalue[:]  # 'Python'  # Вся строка\nvalue[::2]  # 'Pto'  # Нечетные по порядку символы\nvalue[1::2]  # 'yhn'  # Четные по порядку символы\nvalue[::-1]  # 'nohtyP'  # Вся строка в обратном порядке\nvalue[5:]  # 'n'  # Строка, начиная с шестого символа\nvalue[:5]  # 'Pytho'  # Строка до шестого символа\nvalue[-2:1:-1] # 'oht'  # Все символы с предпоследнего до третьего в обратном порядке\n",[428,3942,3943,3951,3959,3966,3977,3992,4005,4016,4028],{"__ignoreMap":426},[431,3944,3945,3947,3949],{"class":433,"line":434},[431,3946,3643],{"class":441},[431,3948,1189],{"class":654},[431,3950,3648],{"class":445},[431,3952,3953,3956],{"class":433,"line":452},[431,3954,3955],{"class":441},"value[::]  ",[431,3957,3958],{"class":455},"# 'Python'  # Вся строка\n",[431,3960,3961,3964],{"class":433,"line":578},[431,3962,3963],{"class":441},"value[:]  ",[431,3965,3958],{"class":455},[431,3967,3968,3970,3972,3974],{"class":433,"line":584},[431,3969,3844],{"class":441},[431,3971,651],{"class":437},[431,3973,3612],{"class":441},[431,3975,3976],{"class":455},"# 'Pto'  # Нечетные по порядку символы\n",[431,3978,3979,3981,3983,3985,3987,3989],{"class":433,"line":1244},[431,3980,3653],{"class":441},[431,3982,1192],{"class":437},[431,3984,3816],{"class":441},[431,3986,651],{"class":437},[431,3988,3612],{"class":441},[431,3990,3991],{"class":455},"# 'yhn'  # Четные по порядку символы\n",[431,3993,3994,3996,3998,4000,4002],{"class":433,"line":1985},[431,3995,3844],{"class":441},[431,3997,853],{"class":654},[431,3999,1192],{"class":437},[431,4001,3612],{"class":441},[431,4003,4004],{"class":455},"# 'nohtyP'  # Вся строка в обратном порядке\n",[431,4006,4007,4009,4011,4013],{"class":433,"line":2041},[431,4008,3653],{"class":441},[431,4010,856],{"class":437},[431,4012,3658],{"class":441},[431,4014,4015],{"class":455},"# 'n'  # Строка, начиная с шестого символа\n",[431,4017,4019,4021,4023,4025],{"class":433,"line":4018},8,[431,4020,3666],{"class":441},[431,4022,856],{"class":437},[431,4024,3612],{"class":441},[431,4026,4027],{"class":455},"# 'Pytho'  # Строка до шестого символа\n",[431,4029,4031,4033,4035,4037,4039,4041,4043,4045,4047,4050],{"class":433,"line":4030},9,[431,4032,3653],{"class":441},[431,4034,853],{"class":654},[431,4036,651],{"class":437},[431,4038,3562],{"class":441},[431,4040,1192],{"class":437},[431,4042,3562],{"class":441},[431,4044,853],{"class":654},[431,4046,1192],{"class":437},[431,4048,4049],{"class":441},"] ",[431,4051,4052],{"class":455},"# 'oht'  # Все символы с предпоследнего до третьего в обратном порядке\n",[415,4054,4055],{},"Во всех случаях выборки от большего индекса к меньшему нужно указывать шаг.",[415,4057,1849,4058,1853,4060,1857],{},[800,4059,1852],{},[800,4061,1856],{},[1859,4063],{},[1862,4065,4066],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":4068},[4069],{"id":2885,"depth":452,"text":2886,"children":4070},[4071,4074,4078],{"id":2892,"depth":578,"text":2893,"children":4072},[4073],{"id":3086,"depth":584,"text":3087},{"id":3266,"depth":578,"text":3267,"children":4075},[4076,4077],{"id":3273,"depth":584,"text":3274},{"id":3402,"depth":584,"text":3403},{"id":3475,"depth":578,"text":3476,"children":4079},[4080,4081],{"id":3482,"depth":584,"text":3483},{"id":3739,"depth":584,"text":3740},"2025-01-24","Интерполяция. Извлечение символов из строки. Срез строки","images\u002Fblog\u002Fpython\u002Fst3\u002Fimg.png",{},14,{"title":278,"description":4083},"fs_b8FPhrC71crJSWoLeCIhrYbYXVI9jk2t8kVAEto8",{"id":4090,"title":306,"author":4091,"body":4093,"date":4756,"description":4757,"extension":1887,"image":4758,"meta":4759,"minRead":4086,"navigation":393,"num":584,"path":307,"seo":4760,"stem":308,"__hash__":4761},"python\u002Fblog\u002Fpython\u002Fst4.md",{"name":402,"avatar":4092},{"src":404,"alt":405},{"type":407,"value":4094,"toc":4745},[4095,4098,4101,4105,4108,4125,4128,4147,4158,4162,4165,4188,4191,4208,4211,4215,4218,4251,4254,4283,4286,4290,4293,4330,4336,4514,4524,4582,4589,4622,4626,4629,4647,4650,4654,4657,4697,4700,4731,4734,4740,4742],[410,4096,306],{"id":4097},"типы-данных",[415,4099,4100],{},"Существуют разные способы представления данных в программах. Есть строки — наборы символов в кавычках вроде \"Hello World!\". Есть целые числа — например, 9, -100, 0.\nЭто две разные категории информации — два разных типа данных. Операция умножения имеет смысл для категории «целые числа», но не для категории «строки»: нет смысла умножать одно слово на другое.\nТип данных определяет, что можно делать с элементами конкретного множества информации.",[458,4102,4104],{"id":4103},"примитивные-типы-данных","Примитивные типы данных",[415,4106,4107],{},"Язык программирования распознает типы данных, поэтому Python не позволит нам умножать строку на строку — нельзя умножать текст на текст.\nПри этом можно умножать целое число на другое целое число. Наличие типов и таких ограничений в языке защищает программы от случайных ошибок.\nВ отличие от строк, числа заключать в кавычки не нужно. Чтобы напечатать число 5, достаточно написать:",[422,4109,4111],{"className":424,"code":4110,"language":396,"meta":426,"style":426},"print(9)  # => 9\n",[428,4112,4113],{"__ignoreMap":426},[431,4114,4115,4117,4119,4121,4123],{"class":433,"line":434},[431,4116,438],{"class":437},[431,4118,442],{"class":441},[431,4120,3357],{"class":437},[431,4122,526],{"class":441},[431,4124,989],{"class":455},[415,4126,4127],{},"Число 9 и строка '9' — совершенно разные вещи, хотя вывод у print() для этих данных идентичный.\nВ Python целые числа (10, 35, -18 и т.д.) и рациональные числа (1.2, 1.0, -12.324 и т.д.) — это два отдельных типа данных.\nЭто разделение существует, несмотря на то, что и целые, и рациональные числа считаются вещественными числами.\nТакое разделение связано с особенностями устройства компьютеров. Есть и другие типы, о них позже.\nВот еще один пример, но уже с рациональным числом:",[422,4129,4131],{"className":424,"code":4130,"language":396,"meta":426,"style":426},"print(1.234)  # => 1.234\n",[428,4132,4133],{"__ignoreMap":426},[431,4134,4135,4137,4139,4142,4144],{"class":433,"line":434},[431,4136,438],{"class":437},[431,4138,442],{"class":441},[431,4140,4141],{"class":437},"1.234",[431,4143,526],{"class":441},[431,4145,4146],{"class":455},"# => 1.234\n",[415,4148,4149,4150,4153,4154,4157],{},"Типы данных «строка», «целое число» и «рациональное число» — это примитивные типы, то есть они встроены в сам язык Python.\nВ язык встроены также и некоторые составные типы. Программисты также могут создавать собственные типы данных.\nПо-английски строки в программировании называются strings, а строчки текстовых файлов — lines. Например, в коде выше есть строчка (line), но нет никаких строк (strings).\nВ русском иногда может быть путаница, поэтому будем говорить ",[1355,4151,4152],{},"строка"," для обозначения типа данных «строка» и ",[1355,4155,4156],{},"строчка"," для обозначения строчек кода (lines) в файлах.\nPython — один из языков, который строго относится к типам данных. Поэтому на любую несовместимость типов он ответит ошибкой. Все дело в сильной типизации.",[632,4159,4161],{"id":4160},"сильная-типизация","Сильная типизация",[415,4163,4164],{},"Нам известно про два типа данных: числа и строки. Например, мы могли складывать числа, потому что операция сложения — это операция для типа «числа».\nА что, если применить эту операцию не к двум числам, а к числу и строке?",[422,4166,4168],{"className":424,"code":4167,"language":396,"meta":426,"style":426},"print(7 + '7')  # TypeError: unsupported operand type(s)...\n",[428,4169,4170],{"__ignoreMap":426},[431,4171,4172,4174,4176,4178,4180,4183,4185],{"class":433,"line":434},[431,4173,438],{"class":437},[431,4175,442],{"class":441},[431,4177,781],{"class":437},[431,4179,655],{"class":654},[431,4181,4182],{"class":445}," '7'",[431,4184,526],{"class":441},[431,4186,4187],{"class":455},"# TypeError: unsupported operand type(s)...\n",[415,4189,4190],{},"Python не разрешит сложить число 7 и строку '7', потому что это значения разных типов. Нужно сначала либо сделать строку числом, либо число строкой.\nТакое отношение к совместимости типов называется сильной типизацией. Python — язык с сильной типизацией.\nНе все языки так делают. Например, JavaScript — это язык со слабой типизацией. Он знает о существовании разных типов, но относится к их использованию не очень строго.\nJavaScript пытается преобразовывать информацию, когда это кажется разумным. То же самое это относится к некоторым другим языкам, например, к PHP.",[422,4192,4196],{"className":4193,"code":4194,"language":4195,"meta":426,"style":426},"language-javascript shiki shiki-themes github-light","\u002F\u002F Число 1 + Строка 7 = Строка 17\n1 + '7'; \u002F\u002F '17'\n","javascript",[428,4197,4198,4203],{"__ignoreMap":426},[431,4199,4200],{"class":433,"line":434},[431,4201,4202],{},"\u002F\u002F Число 1 + Строка 7 = Строка 17\n",[431,4204,4205],{"class":433,"line":452},[431,4206,4207],{},"1 + '7'; \u002F\u002F '17'\n",[415,4209,4210],{},"Есть также языки со строгой типизацией, это когда тип данных нужно указывать при объявлении переменной, к ним относятся: C++, C#, Java и др.\nС одной стороны, автоматическое неявное преобразование типов и правда кажется удобным.\nНо на практике это свойство языка создает множество ошибок и проблем, которые трудно найти.\nКод может иногда работать, а иногда не работать — в зависимости от того, «повезло» ли с автоматическим преобразованием.\nПрограммист это заметит не сразу и потратит много времени на отладку.",[458,4212,4214],{"id":4213},"неизменяемость-примитивных-типов","Неизменяемость примитивных типов",[415,4216,4217],{},"Представим, что нам нужно изменить символ в строке. Вот, что получится:",[422,4219,4221],{"className":424,"code":4220,"language":396,"meta":426,"style":426},"name = 'Ваня'\nname[2] = 'р'\n# Ошибка: TypeError: 'str' object does not support item assignment\n",[428,4222,4223,4232,4246],{"__ignoreMap":426},[431,4224,4225,4227,4229],{"class":433,"line":434},[431,4226,3287],{"class":441},[431,4228,1189],{"class":654},[431,4230,4231],{"class":445}," 'Ваня'\n",[431,4233,4234,4237,4239,4241,4243],{"class":433,"line":452},[431,4235,4236],{"class":441},"name[",[431,4238,651],{"class":437},[431,4240,4049],{"class":441},[431,4242,1189],{"class":654},[431,4244,4245],{"class":445}," 'р'\n",[431,4247,4248],{"class":433,"line":578},[431,4249,4250],{"class":455},"# Ошибка: TypeError: 'str' object does not support item assignment\n",[415,4252,4253],{},"Такое происходит из-за неизменяемости примитивных типов в Python — язык не дает никакой физической возможности поменять строку.\nНеизменяемость примитивных типов важна по многим причинам. Ключевая причина — производительность.\nНо иногда нам нужно изменить строку. Для этого и существуют переменные:",[422,4255,4257],{"className":424,"code":4256,"language":396,"meta":426,"style":426},"name = 'Ваня'\nname = 'Варя'\nprint(name)\n",[428,4258,4259,4267,4276],{"__ignoreMap":426},[431,4260,4261,4263,4265],{"class":433,"line":434},[431,4262,3287],{"class":441},[431,4264,1189],{"class":654},[431,4266,4231],{"class":445},[431,4268,4269,4271,4273],{"class":433,"line":452},[431,4270,3287],{"class":441},[431,4272,1189],{"class":654},[431,4274,4275],{"class":445}," 'Варя'\n",[431,4277,4278,4280],{"class":433,"line":578},[431,4279,438],{"class":437},[431,4281,4282],{"class":441},"(name)\n",[415,4284,4285],{},"Есть большая разница между изменением значения переменной и изменением самого значения.\nПримитивные типы в Python поменять нельзя, а составные — можно. Также можно без проблем заменить значение переменной.",[458,4287,4289],{"id":4288},"явное-преобразование-типов","Явное преобразование типов",[415,4291,4292],{},"В программировании регулярно встречаются задачи, когда один тип данных нужно преобразовать в другой — например, при работе с формами на сайтах.\nДанные формы всегда приходят в текстовом виде, даже если значение — число. Вот как его можно преобразовать:",[422,4294,4296],{"className":424,"code":4295,"language":396,"meta":426,"style":426},"# str в int\nnumber = int('123')\nprint(number)  # => 123\n",[428,4297,4298,4303,4320],{"__ignoreMap":426},[431,4299,4300],{"class":433,"line":434},[431,4301,4302],{"class":455},"# str в int\n",[431,4304,4305,4308,4310,4313,4315,4318],{"class":433,"line":452},[431,4306,4307],{"class":441},"number ",[431,4309,1189],{"class":654},[431,4311,4312],{"class":437}," int",[431,4314,442],{"class":441},[431,4316,4317],{"class":445},"'123'",[431,4319,449],{"class":441},[431,4321,4322,4324,4327],{"class":433,"line":578},[431,4323,438],{"class":437},[431,4325,4326],{"class":441},"(number)  ",[431,4328,4329],{"class":455},"# => 123\n",[415,4331,4332,4335],{},[800,4333,4334],{},"int()"," — это функция, в которую передается значение, чтобы его преобразовать.\nФункция ведет себя подобно арифметическим операциям, но выполняет особые действия. Вот еще несколько примеров:",[422,4337,4339],{"className":424,"code":4338,"language":396,"meta":426,"style":426},"v = '0'\n# Внутри скобок можно указывать переменную\nv1 = int(v)\nprint(v1)  # => 0\n\n# Или конкретное значение\nv2 = int('10')\nprint(v2)  # => 10\n\nv3 = int(False)\nprint(v3)  # => 0\n\nv4 = int(True)\nprint(v4)  # => 1\n\n# Если преобразуется число с плавающей точкой, то отбрасывается вся дробная часть\nv5 = int(3.5)\nprint(v5)  # => 3\n",[428,4340,4341,4351,4356,4368,4378,4382,4387,4403,4413,4417,4434,4444,4449,4466,4475,4480,4486,4503],{"__ignoreMap":426},[431,4342,4343,4346,4348],{"class":433,"line":434},[431,4344,4345],{"class":441},"v ",[431,4347,1189],{"class":654},[431,4349,4350],{"class":445}," '0'\n",[431,4352,4353],{"class":433,"line":452},[431,4354,4355],{"class":455},"# Внутри скобок можно указывать переменную\n",[431,4357,4358,4361,4363,4365],{"class":433,"line":578},[431,4359,4360],{"class":441},"v1 ",[431,4362,1189],{"class":654},[431,4364,4312],{"class":437},[431,4366,4367],{"class":441},"(v)\n",[431,4369,4370,4372,4375],{"class":433,"line":584},[431,4371,438],{"class":437},[431,4373,4374],{"class":441},"(v1)  ",[431,4376,4377],{"class":455},"# => 0\n",[431,4379,4380],{"class":433,"line":1244},[431,4381,1662],{"emptyLinePlaceholder":393},[431,4383,4384],{"class":433,"line":1985},[431,4385,4386],{"class":455},"# Или конкретное значение\n",[431,4388,4389,4392,4394,4396,4398,4401],{"class":433,"line":2041},[431,4390,4391],{"class":441},"v2 ",[431,4393,1189],{"class":654},[431,4395,4312],{"class":437},[431,4397,442],{"class":441},[431,4399,4400],{"class":445},"'10'",[431,4402,449],{"class":441},[431,4404,4405,4407,4410],{"class":433,"line":4018},[431,4406,438],{"class":437},[431,4408,4409],{"class":441},"(v2)  ",[431,4411,4412],{"class":455},"# => 10\n",[431,4414,4415],{"class":433,"line":4030},[431,4416,1662],{"emptyLinePlaceholder":393},[431,4418,4420,4423,4425,4427,4429,4432],{"class":433,"line":4419},10,[431,4421,4422],{"class":441},"v3 ",[431,4424,1189],{"class":654},[431,4426,4312],{"class":437},[431,4428,442],{"class":441},[431,4430,4431],{"class":437},"False",[431,4433,449],{"class":441},[431,4435,4437,4439,4442],{"class":433,"line":4436},11,[431,4438,438],{"class":437},[431,4440,4441],{"class":441},"(v3)  ",[431,4443,4377],{"class":455},[431,4445,4447],{"class":433,"line":4446},12,[431,4448,1662],{"emptyLinePlaceholder":393},[431,4450,4452,4455,4457,4459,4461,4464],{"class":433,"line":4451},13,[431,4453,4454],{"class":441},"v4 ",[431,4456,1189],{"class":654},[431,4458,4312],{"class":437},[431,4460,442],{"class":441},[431,4462,4463],{"class":437},"True",[431,4465,449],{"class":441},[431,4467,4468,4470,4473],{"class":433,"line":4086},[431,4469,438],{"class":437},[431,4471,4472],{"class":441},"(v4)  ",[431,4474,791],{"class":455},[431,4476,4478],{"class":433,"line":4477},15,[431,4479,1662],{"emptyLinePlaceholder":393},[431,4481,4483],{"class":433,"line":4482},16,[431,4484,4485],{"class":455},"# Если преобразуется число с плавающей точкой, то отбрасывается вся дробная часть\n",[431,4487,4489,4492,4494,4496,4498,4501],{"class":433,"line":4488},17,[431,4490,4491],{"class":441},"v5 ",[431,4493,1189],{"class":654},[431,4495,4312],{"class":437},[431,4497,442],{"class":441},[431,4499,4500],{"class":437},"3.5",[431,4502,449],{"class":441},[431,4504,4506,4508,4511],{"class":433,"line":4505},18,[431,4507,438],{"class":437},[431,4509,4510],{"class":441},"(v5)  ",[431,4512,4513],{"class":455},"# => 3\n",[415,4515,4516,4517,4520,4521,3562],{},"Точно так же можно преобразовать данные в строки ",[800,4518,4519],{},"str()"," и число с плавающей точкой ",[800,4522,4523],{},"float()",[422,4525,4527],{"className":424,"code":4526,"language":396,"meta":426,"style":426},"v1 = str(10)\nv2 = str(True)\nv3 = float(5)\nprint(v, v2, v3)  # '10' True 5.0\n",[428,4528,4529,4543,4557,4572],{"__ignoreMap":426},[431,4530,4531,4533,4535,4537,4539,4541],{"class":433,"line":434},[431,4532,4360],{"class":441},[431,4534,1189],{"class":654},[431,4536,2485],{"class":437},[431,4538,442],{"class":441},[431,4540,3565],{"class":437},[431,4542,449],{"class":441},[431,4544,4545,4547,4549,4551,4553,4555],{"class":433,"line":452},[431,4546,4391],{"class":441},[431,4548,1189],{"class":654},[431,4550,2485],{"class":437},[431,4552,442],{"class":441},[431,4554,4463],{"class":437},[431,4556,449],{"class":441},[431,4558,4559,4561,4563,4566,4568,4570],{"class":433,"line":578},[431,4560,4422],{"class":441},[431,4562,1189],{"class":654},[431,4564,4565],{"class":437}," float",[431,4567,442],{"class":441},[431,4569,856],{"class":437},[431,4571,449],{"class":441},[431,4573,4574,4576,4579],{"class":433,"line":584},[431,4575,438],{"class":437},[431,4577,4578],{"class":441},"(v, v2, v3)  ",[431,4580,4581],{"class":455},"# '10' True 5.0\n",[415,4583,4584,4585,4588],{},"Некоторые преобразования Python выполняет автоматически. Например, в операциях, где встречаются одновременно целое число и число с плавающей точкой.\n",[800,4586,4587],{},"Python автоматически все приводит к float"," — числу с плавающей точкой:",[422,4590,4592],{"className":424,"code":4591,"language":396,"meta":426,"style":426},"# Неявно выполняется код float(6) + 1.2\nv = 5 + 1.2\nprint(v)  # => 6.2\n",[428,4593,4594,4599,4612],{"__ignoreMap":426},[431,4595,4596],{"class":433,"line":434},[431,4597,4598],{"class":455},"# Неявно выполняется код float(6) + 1.2\n",[431,4600,4601,4603,4605,4607,4609],{"class":433,"line":452},[431,4602,4345],{"class":441},[431,4604,1189],{"class":654},[431,4606,910],{"class":437},[431,4608,655],{"class":654},[431,4610,4611],{"class":437}," 1.2\n",[431,4613,4614,4616,4619],{"class":433,"line":578},[431,4615,438],{"class":437},[431,4617,4618],{"class":441},"(v)  ",[431,4620,4621],{"class":455},"# => 6.2\n",[458,4623,4625],{"id":4624},"числа-с-плавающей-точкой","Числа с плавающей точкой",[415,4627,4628],{},"В математике существуют разные виды чисел. Например, натуральные — целые числа от одного и больше или рациональные — числа с точкой, например 0.3.\nС точки зрения устройства компьютеров, между этими видами чисел — пропасть.\nНапример, нам легко определить, сколько будет 0.1 + 0.2. А теперь посмотрим, что на это скажет Python:",[422,4630,4632],{"className":424,"code":4631,"language":396,"meta":426,"style":426},"0.1 + 0.2  # 0.30000000000000004\n",[428,4633,4634],{"__ignoreMap":426},[431,4635,4636,4639,4641,4644],{"class":433,"line":434},[431,4637,4638],{"class":437},"0.1",[431,4640,655],{"class":654},[431,4642,4643],{"class":437}," 0.2",[431,4645,4646],{"class":455},"  # 0.30000000000000004\n",[415,4648,4649],{},"Сложение двух рациональных чисел внезапно привело к неточному вычислению результата.\nЭто объясняется ограничениями вычислительных мощностей. Объем памяти конечен, в отличие от чисел. Бесконечное количество чисел потребовало бы бесконечного количества памяти.\nРациональные числа не выстроены в непрерывную цепочку — между 0.1 и 0.2 бесконечное множество чисел.\nКак тогда хранить рациональные числа? В интернете много статей об организации памяти в таких случаях.\nБолее того, существует стандарт, в котором описано, как это делать правильно. На этот стандарт опирается большинство языков.\nРазработчикам важно понимать, что операции над числами с плавающей точкой неточны, но эту точность можно регулировать при работе с конкретными задачами.",[632,4651,4653],{"id":4652},"неизменяемость-и-примитивные-типы","Неизменяемость и примитивные типы",[415,4655,4656],{},"Иногда разработчикам нужно вернуть положительное значение числа, которое задано. Для этого в Python есть специальная функция.\nФункция abs() делает число неотрицательным:",[422,4658,4660],{"className":424,"code":4659,"language":396,"meta":426,"style":426},"balance = -100\namount = abs(balance)\nprint(amount)  # => 100\n",[428,4661,4662,4674,4687],{"__ignoreMap":426},[431,4663,4664,4667,4669,4671],{"class":433,"line":434},[431,4665,4666],{"class":441},"balance ",[431,4668,1189],{"class":654},[431,4670,981],{"class":654},[431,4672,4673],{"class":437},"100\n",[431,4675,4676,4679,4681,4684],{"class":433,"line":452},[431,4677,4678],{"class":441},"amount ",[431,4680,1189],{"class":654},[431,4682,4683],{"class":437}," abs",[431,4685,4686],{"class":441},"(balance)\n",[431,4688,4689,4691,4694],{"class":433,"line":578},[431,4690,438],{"class":437},[431,4692,4693],{"class":441},"(amount)  ",[431,4695,4696],{"class":455},"# => 100\n",[415,4698,4699],{},"На экран выведется 100. Но если вызвать print(balance), то на экран выведется старое значение: -100. Функция abs() вернула новые данные, но не изменила переданные в нее.\nОна не могла это сделать, потому что примитивные типы в Python — неизменяемы.\nНапомним, что примитивные типы — это простые типы данных, которые встроены в сам язык программирования. Например, число или строка.\nНикакие функции не смогут изменять данные примитивных типов. Число -100 — это значение переменной balance, и само число нельзя изменить.\nНо переменная называется переменной, потому что ее значение можно заменить на другое. То есть мы можем написать:",[422,4701,4703],{"className":424,"code":4702,"language":396,"meta":426,"style":426},"balance = -100\nbalance = abs(balance)\nprint(balance)\n",[428,4704,4705,4715,4725],{"__ignoreMap":426},[431,4706,4707,4709,4711,4713],{"class":433,"line":434},[431,4708,4666],{"class":441},[431,4710,1189],{"class":654},[431,4712,981],{"class":654},[431,4714,4673],{"class":437},[431,4716,4717,4719,4721,4723],{"class":433,"line":452},[431,4718,4666],{"class":441},[431,4720,1189],{"class":654},[431,4722,4683],{"class":437},[431,4724,4686],{"class":441},[431,4726,4727,4729],{"class":433,"line":578},[431,4728,438],{"class":437},[431,4730,4686],{"class":441},[415,4732,4733],{},"Сначала в переменную записывается одно значение, а потом в ту же переменную вместо предыдущего значения записывается новое — то, что вернет вызов abs(balance).\nСтроку balance = abs(balance) можно прочитать так: «записать в переменную balance то, что вернет вызов функции abs(), если передать в нее текущее значение переменной balance».\nМы не изменили число, но изменили переменную — записали в нее новое число вместо старого.\nИзменение значения уже существующей переменной может показаться безобидным действием. Но в реальных программах перезаписывание переменной иногда становится источником проблем.\nКод с изменяемыми переменными сложно понимать и анализировать. Никогда нельзя быть уверенным, какое значение будет у переменной в определенный момент времени.\nНаверняка, вы регулярно сталкиваетесь с багами и ошибками в приложениях. Многие из них появляются, потому что изменили значения переменных.\nТакие ошибки сложно найти и исправить. Единственное место, где без изменения значений переменных никак — это циклы.\nВо всех остальных местах относитесь к переменным как к константам — неизменяемым сущностям. Создавайте переменные, задавайте им значения и больше не меняйте без необходимости.",[415,4735,1849,4736,1853,4738,1857],{},[800,4737,1852],{},[800,4739,1856],{},[1859,4741],{},[1862,4743,4744],{},"html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}",{"title":426,"searchDepth":452,"depth":1244,"links":4746},[4747],{"id":4097,"depth":452,"text":306,"children":4748},[4749,4750,4755],{"id":4103,"depth":584,"text":4104},{"id":4160,"depth":578,"text":4161,"children":4751},[4752,4753,4754],{"id":4213,"depth":584,"text":4214},{"id":4288,"depth":584,"text":4289},{"id":4624,"depth":584,"text":4625},{"id":4652,"depth":578,"text":4653},"2025-01-25","Типы данных. Изменяемость данных","images\u002Fblog\u002Fpython\u002Fst4\u002Fimg.png",{},{"title":306,"description":4757},"XtfK7hGtVi1oYoOZnnxryO8Efs-HkRNaqqj5vbY9ZVo",{"id":4763,"title":310,"author":4764,"body":4766,"date":5452,"description":5453,"extension":1887,"image":5454,"meta":5455,"minRead":4086,"navigation":393,"num":1244,"path":311,"seo":5456,"stem":312,"__hash__":5457},"python\u002Fblog\u002Fpython\u002Fst5.md",{"name":402,"avatar":4765},{"src":404,"alt":405},{"type":407,"value":4767,"toc":5435},[4768,4772,4776,4779,4785,4820,4826,4862,4866,4869,4873,4886,4904,4907,4911,4918,4946,4949,4957,4960,4983,4986,5040,5049,5053,5056,5060,5063,5093,5096,5123,5126,5130,5133,5181,5184,5216,5219,5274,5277,5281,5287,5291,5297,5353,5356,5359,5403,5406,5409,5413,5424,5430,5432],[410,4769,4771],{"id":4770},"функции","Функции",[632,4773,4775],{"id":4774},"вызов-функции","Вызов функции",[415,4777,4778],{},"Сложение, конкатенация, нахождение остатка от деления и остальные рассмотренные операции — это базовые возможности языков программирования.\nМатематика не ограничена арифметикой, кроме нее есть и другие разделы со своими операциями — например, статистика.\nТо же самое касается и строк: их можно переворачивать, менять регистр букв, удалять лишние символы — и это только самое простое.\nЕще на более высоком уровне есть прикладная логика конкретного приложения. Программы списывают деньги, считают налоги, формируют отчеты.\nКоличество подобных операций бесконечно и индивидуально для каждой программы. И их нужно уметь выражать в коде.\nЧтобы выразить любую произвольную операцию, в программировании существует понятие функция.\nФункции бывают встроенные и добавленные программистом. С одной встроенной функцией мы уже знакомы — это print().\nФункции — одна из ключевых конструкций в программировании. Без них невозможно сделать практически ничего.\nЗнакомство с ними нужно начинать как можно раньше, так как весь дальнейший материал оперирует функциями по максимуму.\nСначала необходимо научится пользоваться уже созданными функциями, а потом создавать собственные.",[415,4780,4781,4784],{},[800,4782,4783],{},"Функция len()"," считает количество символов в строке. Пример ее вызова:",[422,4786,4788],{"className":424,"code":4787,"language":396,"meta":426,"style":426},"# Вызов функции len с параметром 'Python'\nresult = len('Python')\nprint(result)  # => 6\n",[428,4789,4790,4795,4811],{"__ignoreMap":426},[431,4791,4792],{"class":433,"line":434},[431,4793,4794],{"class":455},"# Вызов функции len с параметром 'Python'\n",[431,4796,4797,4800,4802,4805,4807,4809],{"class":433,"line":452},[431,4798,4799],{"class":441},"result ",[431,4801,1189],{"class":654},[431,4803,4804],{"class":437}," len",[431,4806,442],{"class":441},[431,4808,1304],{"class":445},[431,4810,449],{"class":441},[431,4812,4813,4815,4818],{"class":433,"line":578},[431,4814,438],{"class":437},[431,4816,4817],{"class":441},"(result)  ",[431,4819,951],{"class":455},[415,4821,4822,4825],{},[800,4823,4824],{},"Параметры или аргументы"," — это информация, которую функция получает при вызове. На основе этой информации функция обычно вычисляет и выдает результат.\nВ примере выше мы создали переменную result и указали интерпретатору конкретное действие: надо записать в нее результат, который возвращается функцией len() при ее вызове.\nВ этом смысле функции подобны операциям — они всегда возвращают результат своей работы.\nЗапись len('Python') означает, что вызывается функция с именем len, в которую передали параметр 'Python'. Функция len() считает длину той строки, которую ей передали.\nВызов функции всегда обозначается скобками (), которые идут сразу за именем функции. В скобках может быть любое количество параметров, а иногда ни одного.\nКоличество зависит от используемой функции. Возьмем для примера функцию pow(), которая возводит указанное число в нужную степень.\nОна принимает на вход два параметра: берет первый параметр и возводит его в степень, переданную вторым параметром:",[422,4827,4829],{"className":424,"code":4828,"language":396,"meta":426,"style":426},"result = pow(2, 4)  # 2 * 2 * 2 * 2\nprint(result)  # => 16\n",[428,4830,4831,4854],{"__ignoreMap":426},[431,4832,4833,4835,4837,4840,4842,4844,4847,4849,4851],{"class":433,"line":434},[431,4834,4799],{"class":441},[431,4836,1189],{"class":654},[431,4838,4839],{"class":437}," pow",[431,4841,442],{"class":441},[431,4843,651],{"class":437},[431,4845,4846],{"class":441},", ",[431,4848,762],{"class":437},[431,4850,526],{"class":441},[431,4852,4853],{"class":455},"# 2 * 2 * 2 * 2\n",[431,4855,4856,4858,4860],{"class":433,"line":452},[431,4857,438],{"class":437},[431,4859,4817],{"class":441},[431,4861,772],{"class":455},[632,4863,4865],{"id":4864},"сигнатура-функции","Сигнатура функции",[415,4867,4868],{},"Посмотрим на функции, которые возводят число в степень и округляют.\nТакже на их примере разберем, что такое сигнатура, и какие параметры называют обязательными и необязательными.",[458,4870,4872],{"id":4871},"функция-pow","Функция pow()",[415,4874,4875,4876,4879,4880,4885],{},"Функция ",[800,4877,4878],{},"pow()"," возводит число в степень. Она принимает два параметра: какое число возводить и в какую степень возводить.\nЕсли вызывать pow() без параметров, то Python выдаст следующее: \"TypeError: pow expected at least 2 arguments, got 0\".\nИнтерпретатор сообщает, что функция ожидает два параметра, а вы вызвали ее без них.\nФункция pow() всегда имеет два обязательных параметра, поэтому ее невозможно вызвать с другим количеством параметров.\nБолее того, параметрами pow() могут быть только числа.\nНапример, если передать в нее пару строк, это приведет к следующей ошибке: \"TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'\".\nРезультат вызова функции — тоже всегда число. Другая функция может иметь другое число параметров и другие типы параметров.\nНапример, может существовать функция, которая принимает три параметра: число, строку и еще одно число.\nЧтобы знать такие подробности о конкретной функции, нужно изучать ее сигнатуру.\nОна определяет входные параметры и их типы, а также выходной параметр и его тип.\nПро функцию pow() можно почитать в ",[1205,4881,4884],{"href":4882,"rel":4883},"https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002Ffunctions.html#pow",[1209],"официальной документации Python",".\nОбычно документация для функции выглядит так:",[422,4887,4889],{"className":424,"code":4888,"language":396,"meta":426,"style":426},"pow(x, y[, z])\nВозвращает x в степени y; если z присутствует, возвращает x в степени y, по модулю z\n",[428,4890,4891,4899],{"__ignoreMap":426},[431,4892,4893,4896],{"class":433,"line":434},[431,4894,4895],{"class":437},"pow",[431,4897,4898],{"class":441},"(x, y[, z])\n",[431,4900,4901],{"class":433,"line":452},[431,4902,4903],{"class":441},"Возвращает x в степени y; если z присутствует, возвращает x в степени y, по модулю z\n",[415,4905,4906],{},"Первая строка здесь — это сигнатура функции. У функции два обязательных параметра — x и y.\nНеобязательный параметр z указан в квадратных скобках. Следом поясняется, для чего функция нужна.\nДокументация дает понять, сколько аргументов у функции и какого они типа.\nТакже она описывает, что возвращает функция и какого типа будет возвращаемое значение.\nРассмотрим еще одну функцию — она округляет число.",[458,4908,4910],{"id":4909},"функция-round","Функция round()",[415,4912,4913,4914,4917],{},"Рассмотрим функцию ",[800,4915,4916],{},"round()",", которая округляет переданное ей число:",[422,4919,4921],{"className":424,"code":4920,"language":396,"meta":426,"style":426},"result = round(9.35, 0)  # 9.0\n",[428,4922,4923],{"__ignoreMap":426},[431,4924,4925,4927,4929,4932,4934,4937,4939,4941,4943],{"class":433,"line":434},[431,4926,4799],{"class":441},[431,4928,1189],{"class":654},[431,4930,4931],{"class":437}," round",[431,4933,442],{"class":441},[431,4935,4936],{"class":437},"9.35",[431,4938,4846],{"class":441},[431,4940,3302],{"class":437},[431,4942,526],{"class":441},[431,4944,4945],{"class":455},"# 9.0\n",[415,4947,4948],{},"Мы передали в нее два параметра:",[697,4950,4951,4954],{},[700,4952,4953],{},"Число, которое нужно округлить",[700,4955,4956],{},"Точность округления",[415,4958,4959],{},"Создатели функции round сделали второй параметр необязательным и задали ему внутри функции значение по умолчанию None.\nЕсли не указывать второй параметр, то результат будет целым значением (int):",[422,4961,4963],{"className":424,"code":4962,"language":396,"meta":426,"style":426},"result = round(9.23)  # 9\n",[428,4964,4965],{"__ignoreMap":426},[431,4966,4967,4969,4971,4973,4975,4978,4980],{"class":433,"line":434},[431,4968,4799],{"class":441},[431,4970,1189],{"class":654},[431,4972,4931],{"class":437},[431,4974,442],{"class":441},[431,4976,4977],{"class":437},"9.23",[431,4979,526],{"class":441},[431,4981,4982],{"class":455},"# 9\n",[415,4984,4985],{},"А если нужна точность, то можно передать параметр:",[422,4987,4989],{"className":424,"code":4988,"language":396,"meta":426,"style":426},"# округление до одного знака после запятой\nprint(round(8.25, 1))  # 8.2\nprint(round(8.15, 1))  # 8.2\n",[428,4990,4991,4996,5019],{"__ignoreMap":426},[431,4992,4993],{"class":433,"line":434},[431,4994,4995],{"class":455},"# округление до одного знака после запятой\n",[431,4997,4998,5000,5002,5005,5007,5010,5012,5014,5016],{"class":433,"line":452},[431,4999,438],{"class":437},[431,5001,442],{"class":441},[431,5003,5004],{"class":437},"round",[431,5006,442],{"class":441},[431,5008,5009],{"class":437},"8.25",[431,5011,4846],{"class":441},[431,5013,1192],{"class":437},[431,5015,986],{"class":441},[431,5017,5018],{"class":455},"# 8.2\n",[431,5020,5021,5023,5025,5027,5029,5032,5034,5036,5038],{"class":433,"line":578},[431,5022,438],{"class":437},[431,5024,442],{"class":441},[431,5026,5004],{"class":437},[431,5028,442],{"class":441},[431,5030,5031],{"class":437},"8.15",[431,5033,4846],{"class":441},[431,5035,1192],{"class":437},[431,5037,986],{"class":441},[431,5039,5018],{"class":455},[415,5041,5042,5043,5048],{},"В первом случае округление в меньшую сторону, а во втором случае округление в большую сторону.\nСогласно ",[1205,5044,5047],{"href":5045,"rel":5046},"https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002Fstdtypes.html#numeric-types-int-float-complex",[1209],"документации"," среднее значение округляется в сторону четного числа.\nЕсли функция в Python принимает необязательные аргументы, то они всегда стоят после обязательных. Их количество может быть любым.\nЭто зависит от самой функции, но они всегда идут рядом и в конце списка аргументов.",[632,5050,5052],{"id":5051},"вызов-функции-выражение","Вызов функции — выражение",[415,5054,5055],{},"Можно ли вызов функции принять за выражение?",[458,5057,5059],{"id":5058},"что-принимается-за-выражение","Что принимается за выражение",[415,5061,5062],{},"Выражение в программировании возвращает результат, который можно использовать.\nНапример, такие математические операции, как сложение и вычитание, строковые операции, как конкатенация, — все это выражения.\nОсобенность выражений в том, что они возвращают результат, который можно использовать дальше: например, присвоить переменной или вывести на экран.\nТак это выглядит в коде:",[422,5064,5066],{"className":424,"code":5065,"language":396,"meta":426,"style":426},"# Тут выражение — это 1 + 5\nsumm = 5 + 5\nprint(summ)\n",[428,5067,5068,5073,5086],{"__ignoreMap":426},[431,5069,5070],{"class":433,"line":434},[431,5071,5072],{"class":455},"# Тут выражение — это 1 + 5\n",[431,5074,5075,5078,5080,5082,5084],{"class":433,"line":452},[431,5076,5077],{"class":441},"summ ",[431,5079,1189],{"class":654},[431,5081,910],{"class":437},[431,5083,655],{"class":654},[431,5085,3926],{"class":437},[431,5087,5088,5090],{"class":433,"line":578},[431,5089,438],{"class":437},[431,5091,5092],{"class":441},"(summ)\n",[415,5094,5095],{},"Но не все в программировании — выражение. Определение переменной — это инструкция, значит, она не может быть частью выражения. То есть такой код выдаст ошибку:",[422,5097,5099],{"className":424,"code":5098,"language":396,"meta":426,"style":426},"# Бессмысленный код, который не сработает\n5 + summ = 5 + 5\n",[428,5100,5101,5106],{"__ignoreMap":426},[431,5102,5103],{"class":433,"line":434},[431,5104,5105],{"class":455},"# Бессмысленный код, который не сработает\n",[431,5107,5108,5110,5112,5115,5117,5119,5121],{"class":433,"line":452},[431,5109,856],{"class":437},[431,5111,655],{"class":654},[431,5113,5114],{"class":441}," summ ",[431,5116,1189],{"class":654},[431,5118,910],{"class":437},[431,5120,655],{"class":654},[431,5122,3926],{"class":437},[415,5124,5125],{},"Теперь разберемся, принимается ли за выражение вызов функции.",[458,5127,5129],{"id":5128},"можно-ли-считать-вызов-функции-выражением","Можно ли считать вызов функции выражением",[415,5131,5132],{},"Функции возвращают результат — значит, они выражения. Например, можно использовать вызов функции прямо в математических операциях.\nВот как можно получить индекс последнего символа в слове:",[422,5134,5136],{"className":424,"code":5135,"language":396,"meta":426,"style":426},"name = 'Python'\n# Индексы начинаются с нуля\n# Вызов функции и вычитание вместе!\nlast_i = len(name) - 1\nprint(last_i)  # => 5\n",[428,5137,5138,5146,5151,5156,5172],{"__ignoreMap":426},[431,5139,5140,5142,5144],{"class":433,"line":434},[431,5141,3287],{"class":441},[431,5143,1189],{"class":654},[431,5145,3648],{"class":445},[431,5147,5148],{"class":433,"line":452},[431,5149,5150],{"class":455},"# Индексы начинаются с нуля\n",[431,5152,5153],{"class":433,"line":578},[431,5154,5155],{"class":455},"# Вызов функции и вычитание вместе!\n",[431,5157,5158,5161,5163,5165,5168,5170],{"class":433,"line":584},[431,5159,5160],{"class":441},"last_i ",[431,5162,1189],{"class":654},[431,5164,4804],{"class":437},[431,5166,5167],{"class":441},"(name) ",[431,5169,853],{"class":654},[431,5171,3916],{"class":437},[431,5173,5174,5176,5179],{"class":433,"line":1244},[431,5175,438],{"class":437},[431,5177,5178],{"class":441},"(last_i)  ",[431,5180,3531],{"class":455},[415,5182,5183],{},"В этом коде нет нового синтаксиса. Мы всего лишь соединили уже известные части, опираясь на их природу. Можно пойти еще дальше:",[422,5185,5187],{"className":424,"code":5186,"language":396,"meta":426,"style":426},"name = 'Python'\nprint(len(name) - 1)  # => 5\n",[428,5188,5189,5197],{"__ignoreMap":426},[431,5190,5191,5193,5195],{"class":433,"line":434},[431,5192,3287],{"class":441},[431,5194,1189],{"class":654},[431,5196,3648],{"class":445},[431,5198,5199,5201,5203,5206,5208,5210,5212,5214],{"class":433,"line":452},[431,5200,438],{"class":437},[431,5202,442],{"class":441},[431,5204,5205],{"class":437},"len",[431,5207,5167],{"class":441},[431,5209,853],{"class":654},[431,5211,1032],{"class":437},[431,5213,526],{"class":441},[431,5215,3531],{"class":455},[415,5217,5218],{},"Все это справедливо для любых функций, например, строковых:",[422,5220,5222],{"className":424,"code":5221,"language":396,"meta":426,"style":426},"name = 'Python'\n# Используется интерполяция\nprint(f'Последний символ: {name[len(name) - 1]}')\n# => Последний символ: n\n",[428,5223,5224,5232,5237,5269],{"__ignoreMap":426},[431,5225,5226,5228,5230],{"class":433,"line":434},[431,5227,3287],{"class":441},[431,5229,1189],{"class":654},[431,5231,3648],{"class":445},[431,5233,5234],{"class":433,"line":452},[431,5235,5236],{"class":455},"# Используется интерполяция\n",[431,5238,5239,5241,5243,5245,5248,5250,5252,5254,5256,5258,5260,5263,5265,5267],{"class":433,"line":578},[431,5240,438],{"class":437},[431,5242,442],{"class":441},[431,5244,2990],{"class":654},[431,5246,5247],{"class":445},"'Последний символ: ",[431,5249,2996],{"class":437},[431,5251,4236],{"class":441},[431,5253,5205],{"class":437},[431,5255,5167],{"class":441},[431,5257,853],{"class":654},[431,5259,1032],{"class":437},[431,5261,5262],{"class":441},"]",[431,5264,3002],{"class":437},[431,5266,2993],{"class":445},[431,5268,449],{"class":441},[431,5270,5271],{"class":433,"line":584},[431,5272,5273],{"class":455},"# => Последний символ: n\n",[415,5275,5276],{},"Как вы увидите дальше, выражения можно комбинировать, получая все более сложное поведение в разных местах и любым образом.\nЧем глубже вы будете изучать Python и практиковаться в нем, тем лучше вы будете понимать работу с выражениями.\nСо временем вы лучше поймете, как соединять части кода, чтобы получить нужный результат.",[632,5278,5280],{"id":5279},"детерминированность","Детерминированность",[415,5282,5283,5284,5286],{},"У функций внутри каждого языка программирования есть фундаментальные свойства.\nЭти свойства помогают прогнозировать поведение функций, способы их тестирования и место использования.\nК таким свойствам относится ",[1355,5285,5279],{},".\nДавайте разберемся с детерминированной функцией. Узнаем, зачем эта функция выдает результат, который никак не применяется.",[458,5288,5290],{"id":5289},"детерминированная-функция","Детерминированная функция",[415,5292,5293,5296],{},[1355,5294,5295],{},"Детерминированная функция возвращает один и тот же результат для одинаковых входных параметров.","\nНапример, детерминированной можно назвать функцию, которая считает количество символов:",[422,5298,5300],{"className":424,"code":5299,"language":396,"meta":426,"style":426},"len('Python')  # 6\nlen('Python')  # 6\nlen('hex')  # 3\nlen('hex')  # 3\n",[428,5301,5302,5315,5327,5341],{"__ignoreMap":426},[431,5303,5304,5306,5308,5310,5312],{"class":433,"line":434},[431,5305,5205],{"class":437},[431,5307,442],{"class":441},[431,5309,1304],{"class":445},[431,5311,526],{"class":441},[431,5313,5314],{"class":455},"# 6\n",[431,5316,5317,5319,5321,5323,5325],{"class":433,"line":452},[431,5318,5205],{"class":437},[431,5320,442],{"class":441},[431,5322,1304],{"class":445},[431,5324,526],{"class":441},[431,5326,5314],{"class":455},[431,5328,5329,5331,5333,5336,5338],{"class":433,"line":578},[431,5330,5205],{"class":437},[431,5332,442],{"class":441},[431,5334,5335],{"class":445},"'hex'",[431,5337,526],{"class":441},[431,5339,5340],{"class":455},"# 3\n",[431,5342,5343,5345,5347,5349,5351],{"class":433,"line":584},[431,5344,5205],{"class":437},[431,5346,442],{"class":441},[431,5348,5335],{"class":445},[431,5350,526],{"class":441},[431,5352,5340],{"class":455},[415,5354,5355],{},"Можно бесконечно вызывать эту функцию и передавать туда значение 'Python' — она всегда вернет 6.",[415,5357,5358],{},"Посмотрим и обратный случай — недетерминированные функции.\nНапример, к этой категории относится функция, которая возвращает случайное число: у одного и того же входа мы получим всегда разный результат.\nЕсли хотя бы один из миллиона вызовов функции вернет другой результат, она считается недетерминированной.\nЭто работает и в том случае, если параметры не принимаются:",[422,5360,5362],{"className":424,"code":5361,"language":396,"meta":426,"style":426},"# Про синтаксис импортов позже\nfrom random import random\n# Функция, которая возвращает случайное число\nrandom()  # 0.0432523454325265\nrandom()  # 0.2364564577656544\n",[428,5363,5364,5369,5383,5388,5396],{"__ignoreMap":426},[431,5365,5366],{"class":433,"line":434},[431,5367,5368],{"class":455},"# Про синтаксис импортов позже\n",[431,5370,5371,5374,5377,5380],{"class":433,"line":452},[431,5372,5373],{"class":654},"from",[431,5375,5376],{"class":441}," random ",[431,5378,5379],{"class":654},"import",[431,5381,5382],{"class":441}," random\n",[431,5384,5385],{"class":433,"line":578},[431,5386,5387],{"class":455},"# Функция, которая возвращает случайное число\n",[431,5389,5390,5393],{"class":433,"line":584},[431,5391,5392],{"class":441},"random()  ",[431,5394,5395],{"class":455},"# 0.0432523454325265\n",[431,5397,5398,5400],{"class":433,"line":1244},[431,5399,5392],{"class":441},[431,5401,5402],{"class":455},"# 0.2364564577656544\n",[415,5404,5405],{},"Детерминированность — это важное свойство функции, так как она влияет на многие аспекты.\nНапример, детерминированные функции удобны в работе — их легко оптимизировать и тестировать.\nЕсли возможно, то лучше сделать функцию детерминированной.",[415,5407,5408],{},"Для примера рассмотрим одну необычную функцию — она возвращает результат, с которым ничего нельзя сделать.",[458,5410,5412],{"id":5411},"побочные-эффекты","Побочные эффекты",[415,5414,5415,5416,5419,5420,5423],{},"В Python есть функция ",[800,5417,5418],{},"print()",", которая принимает на вход данные любого типа и выводит их на экран.\nОна вызывает ",[800,5421,5422],{},"побочный эффект"," — из-за выполнения функции запускается действие, которое изменяет среду выполнения.\nЕщё побочные эффекты вызывают любые сетевые взаимодействия, чтение и запись файлов, вывод информации на экран и печать на принтере.\nПобочные эффекты — один из основных источников проблем и ошибок в программных системах. Такой код сложнее тестировать, снижается его надежность.\nПри этом без побочных эффектов программирование не имеет смысла.\nБез них было бы невозможно получить результат работы программы: например, записать в базу, вывести на экран и отправить по сети.\nПобочными эффектами print() отличается от других функций, которые также принимают на вход данные любого типа.\nДругие функции возвращают значения, которые можно дальше использовать.\nВ отличие от них, функция print() выводит такой результат, с которым ничего нельзя сделать.\nВывод на экран и возврат значения из функции — разные и независимые операции.",[415,5425,1849,5426,1853,5428,1857],{},[800,5427,1852],{},[800,5429,1856],{},[1859,5431],{},[1862,5433,5434],{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":5436},[5437],{"id":4770,"depth":452,"text":4771,"children":5438},[5439,5440,5444,5448],{"id":4774,"depth":578,"text":4775},{"id":4864,"depth":578,"text":4865,"children":5441},[5442,5443],{"id":4871,"depth":584,"text":4872},{"id":4909,"depth":584,"text":4910},{"id":5051,"depth":578,"text":5052,"children":5445},[5446,5447],{"id":5058,"depth":584,"text":5059},{"id":5128,"depth":584,"text":5129},{"id":5279,"depth":578,"text":5280,"children":5449},[5450,5451],{"id":5289,"depth":584,"text":5290},{"id":5411,"depth":584,"text":5412},"2025-01-26","Использование готовых функций. Приём и возврат значений функций. Свойства функций","images\u002Fblog\u002Fpython\u002Fst5\u002Fimg.png",{},{"title":310,"description":5453},"568TvG4SmbMI2FA0Z1eIV5DnmPc2TcSFDfIFGkGprv4",{"id":5459,"title":314,"author":5460,"body":5462,"date":6218,"description":6219,"extension":1887,"image":6220,"meta":6221,"minRead":4446,"navigation":393,"num":1985,"path":315,"seo":6222,"stem":316,"__hash__":6223},"python\u002Fblog\u002Fpython\u002Fst6.md",{"name":402,"avatar":5461},{"src":404,"alt":405},{"type":407,"value":5463,"toc":6207},[5464,5467,5472,5476,5482,5488,5491,5495,5498,5541,5547,5552,5555,5593,5596,5599,5614,5622,5689,5692,5729,5732,5777,5780,5783,5800,5803,5807,5810,5847,5850,5853,5882,5886,5889,5892,5924,5927,5983,5987,5990,6013,6016,6019,6052,6055,6088,6091,6116,6119,6158,6161,6165,6168,6171,6174,6185,6188,6196,6202,6204],[410,5465,314],{"id":5466},"свойства-и-методы",[415,5468,5469],{},[1355,5470,5471],{},"У данных обычно есть важные атрибуты и методы. Они определяют поведение и возможности этих данных.\nПодробнее о них можно узнать в объектно-ориентированном программировании.\nВ этой статье рассмотрим основы работы с методами в Python.",[632,5473,5475],{"id":5474},"атрибуты-и-методы","Атрибуты и методы",[415,5477,5478,5481],{},[800,5479,5480],{},"Атрибуты (attributes)"," — это переменные, которые хранят данные в объектах классов.\nУ каждого объекта класса есть свой набор атрибутов, которые могут быть доступны для чтения и записи.",[415,5483,5484,5487],{},[800,5485,5486],{},"Методы (methods)"," — это функции, которые связаны с определенными объектами данных.",[415,5489,5490],{},"Атрибуты и методы являются такими же выражениями, как переменные и вызовы функций.\nТакже они могут использоваться в комбинации с другими выражениями.",[458,5492,5494],{"id":5493},"объекты","Объекты",[415,5496,5497],{},"В программировании происходит взаимодействие с данными, создание чисел и строк, и выполнение над ними различных операций.\nЧтобы выполнить операцию, применяются либо операторы, либо функции:",[422,5499,5501],{"className":424,"code":5500,"language":396,"meta":426,"style":426},"# Сложение с помощью оператора +\n3 + 3 # 6\n# Подсчет длины с помощью функции len()\nname = 'Python'\nlen(name)  # 6\n",[428,5502,5503,5508,5519,5524,5532],{"__ignoreMap":426},[431,5504,5505],{"class":433,"line":434},[431,5506,5507],{"class":455},"# Сложение с помощью оператора +\n",[431,5509,5510,5512,5514,5516],{"class":433,"line":452},[431,5511,971],{"class":437},[431,5513,655],{"class":654},[431,5515,900],{"class":437},[431,5517,5518],{"class":455}," # 6\n",[431,5520,5521],{"class":433,"line":578},[431,5522,5523],{"class":455},"# Подсчет длины с помощью функции len()\n",[431,5525,5526,5528,5530],{"class":433,"line":584},[431,5527,3287],{"class":441},[431,5529,1189],{"class":654},[431,5531,3648],{"class":445},[431,5533,5534,5536,5539],{"class":433,"line":1244},[431,5535,5205],{"class":437},[431,5537,5538],{"class":441},"(name)  ",[431,5540,5314],{"class":455},[415,5542,5543,5544,2699],{},"В примере выше есть четкое разделение: данные отдельно, функции отдельно.\nНо это не единственный способ организации кода.\nВ Python наравне с таким разделением используется и другой подход — ",[800,5545,5546],{},"объектно-ориентированный(ОО)",[415,5548,5549],{},[800,5550,5551],{},"Объектно-ориентированный код строится на объединении данных и функций в одну сущность — объект. Данные в таком случае называются атрибутами, а функции — методами.",[415,5553,5554],{},"Вот пример:",[422,5556,5558],{"className":424,"code":5557,"language":396,"meta":426,"style":426},"name = 'Python'\n# Метод upper()\nupper_name = name.upper()\nprint(upper_name)  # => 'PYTHON'\n",[428,5559,5560,5568,5573,5583],{"__ignoreMap":426},[431,5561,5562,5564,5566],{"class":433,"line":434},[431,5563,3287],{"class":441},[431,5565,1189],{"class":654},[431,5567,3648],{"class":445},[431,5569,5570],{"class":433,"line":452},[431,5571,5572],{"class":455},"# Метод upper()\n",[431,5574,5575,5578,5580],{"class":433,"line":578},[431,5576,5577],{"class":441},"upper_name ",[431,5579,1189],{"class":654},[431,5581,5582],{"class":441}," name.upper()\n",[431,5584,5585,5587,5590],{"class":433,"line":584},[431,5586,438],{"class":437},[431,5588,5589],{"class":441},"(upper_name)  ",[431,5591,5592],{"class":455},"# => 'PYTHON'\n",[415,5594,5595],{},"Строки в Python — это объекты. В примере выше мы вызываем метод, то есть функцию, которая связана со строкой.\nВызов происходит через точку, которая идет сразу за именем переменной. В остальном методы работают как обычные функции.",[415,5597,5598],{},"Также вызов можно делать и напрямую:",[422,5600,5602],{"className":424,"code":5601,"language":396,"meta":426,"style":426},"'Python'.upper()  # 'PYTHON'\n",[428,5603,5604],{"__ignoreMap":426},[431,5605,5606,5608,5611],{"class":433,"line":434},[431,5607,1304],{"class":445},[431,5609,5610],{"class":441},".upper()  ",[431,5612,5613],{"class":455},"# 'PYTHON'\n",[415,5615,5616,5617,5621],{},"В строки встроено много методов, которые постоянно нужны разработчику. Посмотреть их список можно в ",[1205,5618,5047],{"href":5619,"rel":5620},"https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002Fstdtypes.html#string-methods",[1209],".\nВот несколько полезных примеров:",[422,5623,5625],{"className":424,"code":5624,"language":396,"meta":426,"style":426},"name = 'Python'\n# Возвращает индекс первого вхождения буквы в строку\nname.find('t')  # 2\n# Переводит в нижний регистр\nname.lower()  # 'python'\n# Заменяет одну подстроку другой\nname.replace('on', 'off')  # 'Pythoff'\n",[428,5626,5627,5635,5640,5653,5658,5666,5671],{"__ignoreMap":426},[431,5628,5629,5631,5633],{"class":433,"line":434},[431,5630,3287],{"class":441},[431,5632,1189],{"class":654},[431,5634,3648],{"class":445},[431,5636,5637],{"class":433,"line":452},[431,5638,5639],{"class":455},"# Возвращает индекс первого вхождения буквы в строку\n",[431,5641,5642,5645,5648,5650],{"class":433,"line":578},[431,5643,5644],{"class":441},"name.find(",[431,5646,5647],{"class":445},"'t'",[431,5649,526],{"class":441},[431,5651,5652],{"class":455},"# 2\n",[431,5654,5655],{"class":433,"line":584},[431,5656,5657],{"class":455},"# Переводит в нижний регистр\n",[431,5659,5660,5663],{"class":433,"line":1244},[431,5661,5662],{"class":441},"name.lower()  ",[431,5664,5665],{"class":455},"# 'python'\n",[431,5667,5668],{"class":433,"line":1985},[431,5669,5670],{"class":455},"# Заменяет одну подстроку другой\n",[431,5672,5673,5676,5679,5681,5684,5686],{"class":433,"line":2041},[431,5674,5675],{"class":441},"name.replace(",[431,5677,5678],{"class":445},"'on'",[431,5680,4846],{"class":441},[431,5682,5683],{"class":445},"'off'",[431,5685,526],{"class":441},[431,5687,5688],{"class":455},"# 'Pythoff'\n",[415,5690,5691],{},"То же самое касается чисел и остальных типов данных. Можно сказать, что в Python почти всё является объектом:",[422,5693,5695],{"className":424,"code":5694,"language":396,"meta":426,"style":426},"x = -10\n# Возвращает модуль числа\n# Имя выглядит странно, но это действительно имя метода\nx.__abs__()\n",[428,5696,5697,5708,5713,5718],{"__ignoreMap":426},[431,5698,5699,5701,5703,5705],{"class":433,"line":434},[431,5700,1186],{"class":441},[431,5702,1189],{"class":654},[431,5704,981],{"class":654},[431,5706,5707],{"class":437},"10\n",[431,5709,5710],{"class":433,"line":452},[431,5711,5712],{"class":455},"# Возвращает модуль числа\n",[431,5714,5715],{"class":433,"line":578},[431,5716,5717],{"class":455},"# Имя выглядит странно, но это действительно имя метода\n",[431,5719,5720,5723,5726],{"class":433,"line":584},[431,5721,5722],{"class":441},"x.",[431,5724,5725],{"class":437},"__abs__",[431,5727,5728],{"class":441},"()\n",[415,5730,5731],{},"В примере выше есть имя метода, в начале и конце которого по два подчеркивания.\nВ Python так называют методы, которые не предназначены для прямого вызова.\nДля них создали функции, которые внутри себя уже сами вызывают методы:",[422,5733,5735],{"className":424,"code":5734,"language":396,"meta":426,"style":426},"x = -10\nabs(x)  # вызывает x.__abs__()\n# -10 в 3 степени\npow(x, 3)  # вызывает x.__pow__(3)\n",[428,5736,5737,5747,5758,5763],{"__ignoreMap":426},[431,5738,5739,5741,5743,5745],{"class":433,"line":434},[431,5740,1186],{"class":441},[431,5742,1189],{"class":654},[431,5744,981],{"class":654},[431,5746,5707],{"class":437},[431,5748,5749,5752,5755],{"class":433,"line":452},[431,5750,5751],{"class":437},"abs",[431,5753,5754],{"class":441},"(x)  ",[431,5756,5757],{"class":455},"# вызывает x.__abs__()\n",[431,5759,5760],{"class":433,"line":578},[431,5761,5762],{"class":455},"# -10 в 3 степени\n",[431,5764,5765,5767,5770,5772,5774],{"class":433,"line":584},[431,5766,4895],{"class":437},[431,5768,5769],{"class":441},"(x, ",[431,5771,971],{"class":437},[431,5773,526],{"class":441},[431,5775,5776],{"class":455},"# вызывает x.__pow__(3)\n",[415,5778,5779],{},"Создатель Python решил, что будет нагляднее, если математические или похожие на математические операции выразить функциями.\nОн хотел, чтобы такие функции воспринимались как операции, типа сложения или вычитания. Так привычнее для тех, кто изучал математику.\nТак же работает и функция len().",[415,5781,5782],{},"Кроме методов у объектов есть атрибуты, но у встроенных в Python объектов их мало.\nНапример, атрибут __doc__, который возвращает документацию функции. Поэтому функции тоже считаются объектами:",[422,5784,5786],{"className":424,"code":5785,"language":396,"meta":426,"style":426},"len.__doc__  # 'Return the number of items in a container.'\n",[428,5787,5788],{"__ignoreMap":426},[431,5789,5790,5792,5794,5797],{"class":433,"line":434},[431,5791,5205],{"class":437},[431,5793,2699],{"class":441},[431,5795,5796],{"class":437},"__doc__",[431,5798,5799],{"class":455},"  # 'Return the number of items in a container.'\n",[415,5801,5802],{},"Атрибуты работают и выглядят как переменные, только указываются через точку после объекта.\nТеперь поговорим про неизменяемость типов данных.",[458,5804,5806],{"id":5805},"неизменяемость","Неизменяемость",[415,5808,5809],{},"Допустим есть такой вызов:",[422,5811,5813],{"className":424,"code":5812,"language":396,"meta":426,"style":426},"name = 'Python'\nprint(name.upper())  # => PYTHON\n# Что напечатает на экран этот вызов?\nprint(name)  # => ?\n",[428,5814,5815,5823,5833,5838],{"__ignoreMap":426},[431,5816,5817,5819,5821],{"class":433,"line":434},[431,5818,3287],{"class":441},[431,5820,1189],{"class":654},[431,5822,3648],{"class":445},[431,5824,5825,5827,5830],{"class":433,"line":452},[431,5826,438],{"class":437},[431,5828,5829],{"class":441},"(name.upper())  ",[431,5831,5832],{"class":455},"# => PYTHON\n",[431,5834,5835],{"class":433,"line":578},[431,5836,5837],{"class":455},"# Что напечатает на экран этот вызов?\n",[431,5839,5840,5842,5844],{"class":433,"line":584},[431,5841,438],{"class":437},[431,5843,5538],{"class":441},[431,5845,5846],{"class":455},"# => ?\n",[415,5848,5849],{},"Вызов метода .upper() возвращает новое значение, в котором все буквы преобразованы в верхний регистр, но он не меняет исходную строку.\nПоэтому внутри переменной окажется старое значение: 'Python'. Эта логика справедлива для методов всех примитивных типов.",[415,5851,5852],{},"Вместо того, чтобы изменять значение, можно заменить значение. Для этого понадобятся переменные:",[422,5854,5856],{"className":424,"code":5855,"language":396,"meta":426,"style":426},"name = 'Python'\nname = name.upper()\nprint(name)  # => PYTHON\n",[428,5857,5858,5866,5874],{"__ignoreMap":426},[431,5859,5860,5862,5864],{"class":433,"line":434},[431,5861,3287],{"class":441},[431,5863,1189],{"class":654},[431,5865,3648],{"class":445},[431,5867,5868,5870,5872],{"class":433,"line":452},[431,5869,3287],{"class":441},[431,5871,1189],{"class":654},[431,5873,5582],{"class":441},[431,5875,5876,5878,5880],{"class":433,"line":578},[431,5877,438],{"class":437},[431,5879,5538],{"class":441},[431,5881,5832],{"class":455},[458,5883,5885],{"id":5884},"методы-выражения","Методы выражения",[415,5887,5888],{},"Методы — такие же выражения, как переменные и вызовы функции, значит, их можно по-разному комбинировать.",[415,5890,5891],{},"Например, использовать в операциях:",[422,5893,5895],{"className":424,"code":5894,"language":396,"meta":426,"style":426},"name = 'Alex'\n'Hello, ' + name.upper() + '!'  # Hello, ALEX!\n",[428,5896,5897,5906],{"__ignoreMap":426},[431,5898,5899,5901,5903],{"class":433,"line":434},[431,5900,3287],{"class":441},[431,5902,1189],{"class":654},[431,5904,5905],{"class":445}," 'Alex'\n",[431,5907,5908,5911,5913,5916,5918,5921],{"class":433,"line":452},[431,5909,5910],{"class":445},"'Hello, '",[431,5912,655],{"class":654},[431,5914,5915],{"class":441}," name.upper() ",[431,5917,802],{"class":654},[431,5919,5920],{"class":445}," '!'",[431,5922,5923],{"class":455},"  # Hello, ALEX!\n",[415,5925,5926],{},"Или использовать в аргументах функций:",[422,5928,5930],{"className":424,"code":5929,"language":396,"meta":426,"style":426},"name = 'Alex'\nprint(name.lower())  # => alex\nn1, n2 = 2, 32\n# bit_length() — вычисляет количество бит, необходимых для представления числа в двоичном виде\nprint((n1 + n2).bit_length())  # 6\n",[428,5931,5932,5940,5950,5964,5969],{"__ignoreMap":426},[431,5933,5934,5936,5938],{"class":433,"line":434},[431,5935,3287],{"class":441},[431,5937,1189],{"class":654},[431,5939,5905],{"class":445},[431,5941,5942,5944,5947],{"class":433,"line":452},[431,5943,438],{"class":437},[431,5945,5946],{"class":441},"(name.lower())  ",[431,5948,5949],{"class":455},"# => alex\n",[431,5951,5952,5955,5957,5959,5961],{"class":433,"line":578},[431,5953,5954],{"class":441},"n1, n2 ",[431,5956,1189],{"class":654},[431,5958,689],{"class":437},[431,5960,4846],{"class":441},[431,5962,5963],{"class":437},"32\n",[431,5965,5966],{"class":433,"line":584},[431,5967,5968],{"class":455},"# bit_length() — вычисляет количество бит, необходимых для представления числа в двоичном виде\n",[431,5970,5971,5973,5976,5978,5981],{"class":433,"line":1244},[431,5972,438],{"class":437},[431,5974,5975],{"class":441},"((n1 ",[431,5977,802],{"class":654},[431,5979,5980],{"class":441}," n2).bit_length())  ",[431,5982,5314],{"class":455},[632,5984,5986],{"id":5985},"цепочка-методов","Цепочка методов",[415,5988,5989],{},"Рассмотрим, как комбинировать различные подходы, когда пишем код, а также разберем типичные ошибки новичков.\nУ нас есть следующий код:",[422,5991,5993],{"className":424,"code":5992,"language":396,"meta":426,"style":426},"name = 'Python'\nprint(name.upper().lower())  # => `python`\n",[428,5994,5995,6003],{"__ignoreMap":426},[431,5996,5997,5999,6001],{"class":433,"line":434},[431,5998,3287],{"class":441},[431,6000,1189],{"class":654},[431,6002,3648],{"class":445},[431,6004,6005,6007,6010],{"class":433,"line":452},[431,6006,438],{"class":437},[431,6008,6009],{"class":441},"(name.upper().lower())  ",[431,6011,6012],{"class":455},"# => `python`\n",[415,6014,6015],{},"Он напечатал на экране python.",[415,6017,6018],{},"Синтаксис нескольких подряд идущих точек мы видим впервые, но все операции, которые здесь встречаются, нам знакомы.\nВ этом коде объединились известные возможности языка.\nТакое в программировании происходит часто.\nЕсли вы не знаете синтаксис, то можно все равно пробовать комбинировать различные подходы, и есть вероятность, что они заработают.\nЧтобы понять, как работает этот код, нужно разбить цепочку на отдельные операции:",[422,6020,6022],{"className":424,"code":6021,"language":396,"meta":426,"style":426},"name = 'Python'\nupper_name = name.upper()  # 'PYTHON'\nprint(upper_name.lower())  # 'python'\n",[428,6023,6024,6032,6043],{"__ignoreMap":426},[431,6025,6026,6028,6030],{"class":433,"line":434},[431,6027,3287],{"class":441},[431,6029,1189],{"class":654},[431,6031,3648],{"class":445},[431,6033,6034,6036,6038,6041],{"class":433,"line":452},[431,6035,5577],{"class":441},[431,6037,1189],{"class":654},[431,6039,6040],{"class":441}," name.upper()  ",[431,6042,5613],{"class":455},[431,6044,6045,6047,6050],{"class":433,"line":578},[431,6046,438],{"class":437},[431,6048,6049],{"class":441},"(upper_name.lower())  ",[431,6051,5665],{"class":455},[415,6053,6054],{},"Первый и второй примеры эквивалентны.\nМы можем выполнять операции последовательно с промежуточным созданием переменных, а можем строить непрерывную цепочку из атрибутов и методов.\nВ цепочках вычисления всегда идут слева направо.\nЕще один пример для закрепления:",[422,6056,6058],{"className":424,"code":6057,"language":396,"meta":426,"style":426},"name = 'Python'\nprint(name.replace('Py', 'Ti').lower())  # => ?\n",[428,6059,6060,6068],{"__ignoreMap":426},[431,6061,6062,6064,6066],{"class":433,"line":434},[431,6063,3287],{"class":441},[431,6065,1189],{"class":654},[431,6067,3648],{"class":445},[431,6069,6070,6072,6075,6078,6080,6083,6086],{"class":433,"line":452},[431,6071,438],{"class":437},[431,6073,6074],{"class":441},"(name.replace(",[431,6076,6077],{"class":445},"'Py'",[431,6079,4846],{"class":441},[431,6081,6082],{"class":445},"'Ti'",[431,6084,6085],{"class":441},").lower())  ",[431,6087,5846],{"class":455},[415,6089,6090],{},"Над этим кодом нужно хорошо подумать. .lower() применяется к результату вызова метода, который находится левее. А метод replace() возвращает строку.\nНовички часто делают ошибки в цепочках с методами и забывают ставить вызов:",[422,6092,6094],{"className":424,"code":6093,"language":396,"meta":426,"style":426},"name = 'Python'\n# Этот код отработает неверно!\nprint(name.upper.lower())\n",[428,6095,6096,6104,6109],{"__ignoreMap":426},[431,6097,6098,6100,6102],{"class":433,"line":434},[431,6099,3287],{"class":441},[431,6101,1189],{"class":654},[431,6103,3648],{"class":445},[431,6105,6106],{"class":433,"line":452},[431,6107,6108],{"class":455},"# Этот код отработает неверно!\n",[431,6110,6111,6113],{"class":433,"line":578},[431,6112,438],{"class":437},[431,6114,6115],{"class":441},"(name.upper.lower())\n",[415,6117,6118],{},"Также можно строить бесконечно длинные и бесполезные цепочки, которые включают в себя срезы:",[422,6120,6122],{"className":424,"code":6121,"language":396,"meta":426,"style":426},"name = 'Python'\n# Чему равен результат такого вызова?\nprint(name[1:5].upper().find('Y'))\n",[428,6123,6124,6132,6137],{"__ignoreMap":426},[431,6125,6126,6128,6130],{"class":433,"line":434},[431,6127,3287],{"class":441},[431,6129,1189],{"class":654},[431,6131,3648],{"class":445},[431,6133,6134],{"class":433,"line":452},[431,6135,6136],{"class":455},"# Чему равен результат такого вызова?\n",[431,6138,6139,6141,6143,6145,6147,6149,6152,6155],{"class":433,"line":578},[431,6140,438],{"class":437},[431,6142,3299],{"class":441},[431,6144,1192],{"class":437},[431,6146,3562],{"class":441},[431,6148,856],{"class":437},[431,6150,6151],{"class":441},"].upper().find(",[431,6153,6154],{"class":445},"'Y'",[431,6156,6157],{"class":441},"))\n",[415,6159,6160],{},"С функциями это не сработает, так как обычно они вкладываются друг в друга — f(f(f())).\nЭто значительно усложняет анализ. Но это не значит, что нельзя сделать красиво.\nВ других языках это реализуется через композицию функций или pipeline-оператор.",[632,6162,6164],{"id":6163},"стандартная-библиотека","Стандартная библиотека",[415,6166,6167],{},"Python поставляется с набором полезных функций, которые составляют стандартную библиотеку.\nОбычно в нее входят тысячи функций, которые невозможно запомнить.\nПоэтому программист должен знать, где найти документацию по этим функциям, а также представлять результат, который хочет получить.\nПо этим причинам программировать без интернета сложно.",[415,6169,6170],{},"Новички часто не понимают, как и где узнавать про функции, которые нужно использовать.\nПри этом нет способа, который поможет решить эту проблему.\nПо мере работы разработчики становятся опытнее, пополняют свой багаж знаний и практик.\nПостепенно они знакомятся с более интересными функциями, которые решают их задачи по-другому.",[415,6172,6173],{},"Вот советы, которые помогут повысить уровень профессионализма:",[697,6175,6176,6179,6182],{},[700,6177,6178],{},"Всегда отслеживайте, с каким типом данных вы работаете. Так вы найдете необходимую функцию в соответствующем разделе документации. Например, для работы со строками нужно изучать строковые функции",[700,6180,6181],{},"Периодически открывайте раздел со стандартными функциями по вашей тематике, изучайте сигнатуры и способы использования",[700,6183,6184],{},"Чаще читайте чужой код на GitHub. Особое внимание обращайте на код библиотек, которые используете в своем коде",[415,6186,6187],{},"Если следовать этим советам и внимательно относиться к деталям, то уже скоро вы заметите, как развиваетесь и растете как профессионал.",[415,6189,6190,6191,2699],{},"Полезная ссылка:\n",[1205,6192,6195],{"href":6193,"rel":6194},"https:\u002F\u002Fdocs-python.ru\u002Fstandart-library\u002F",[1209],"Стандартная библиотека Python3 на русском",[415,6197,1849,6198,1853,6200,1857],{},[800,6199,1852],{},[800,6201,1856],{},[1859,6203],{},[1862,6205,6206],{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":6208},[6209],{"id":5466,"depth":452,"text":314,"children":6210},[6211,6216,6217],{"id":5474,"depth":578,"text":5475,"children":6212},[6213,6214,6215],{"id":5493,"depth":584,"text":5494},{"id":5805,"depth":584,"text":5806},{"id":5884,"depth":584,"text":5885},{"id":5985,"depth":578,"text":5986},{"id":6163,"depth":578,"text":6164},"2025-01-29","Использование встроенных функций. Цепочки методов. Стандартная библиотека Python","images\u002Fblog\u002Fpython\u002Fst6\u002Fimg.png",{},{"title":314,"description":6219},"MXIS_qomtd2_aV6Ot9rH1HJ4myBPwxyoHbGCzXyqi_k",{"id":6225,"title":318,"author":6226,"body":6228,"date":8378,"description":8379,"extension":1887,"image":8380,"meta":8381,"minRead":8382,"navigation":393,"num":2041,"path":319,"seo":8383,"stem":320,"__hash__":8384},"python\u002Fblog\u002Fpython\u002Fst7.md",{"name":402,"avatar":6227},{"src":404,"alt":405},{"type":407,"value":6229,"toc":8362},[6230,6233,6236,6240,6243,6313,6316,6377,6380,6418,6421,6425,6428,6451,6454,6474,6540,6543,6578,6581,6603,6606,6648,6651,6682,6685,6738,6741,6770,6773,6813,6816,6867,6871,6874,6954,6957,7019,7022,7033,7036,7064,7067,7094,7097,7170,7173,7206,7209,7230,7233,7266,7269,7312,7315,7344,7348,7351,7439,7442,7494,7497,7537,7540,7681,7684,7688,7691,7718,7721,7738,7741,7775,7778,7782,7785,7789,7795,7802,7826,7833,7866,7869,7872,7876,7879,7882,7890,7893,7996,7999,8025,8028,8032,8037,8040,8067,8070,8073,8113,8116,8161,8164,8168,8182,8234,8237,8294,8297,8348,8351,8357,8359],[410,6231,318],{"id":6232},"определение-функций",[415,6234,6235],{},"С помощью определения собственных функций писать и поддерживать программы проще.\nОни позволяют объединять составные операции в одну.",[632,6237,6239],{"id":6238},"создание-функции","Создание функции",[415,6241,6242],{},"Допустим, мы хотим отправить письма на сайте — это достаточно сложный процесс, который включает взаимодействие с внешними системами.\nНо если определить функцию, вся сложность скроется за одной простой функцией. Представим такой код:",[422,6244,6246],{"className":424,"code":6245,"language":396,"meta":426,"style":426},"# Место, откуда берется функция\nfrom emails import send\n\nemail = 'support@admin.ru'\ntitle = 'Помогите'\nbody = 'Я написал историю, как я могу получить скидку?'\n\n# Один вызов — много логики внутри\nsend(email, title, body)\n",[428,6247,6248,6253,6265,6269,6279,6289,6299,6303,6308],{"__ignoreMap":426},[431,6249,6250],{"class":433,"line":434},[431,6251,6252],{"class":455},"# Место, откуда берется функция\n",[431,6254,6255,6257,6260,6262],{"class":433,"line":452},[431,6256,5373],{"class":654},[431,6258,6259],{"class":441}," emails ",[431,6261,5379],{"class":654},[431,6263,6264],{"class":441}," send\n",[431,6266,6267],{"class":433,"line":578},[431,6268,1662],{"emptyLinePlaceholder":393},[431,6270,6271,6274,6276],{"class":433,"line":584},[431,6272,6273],{"class":441},"email ",[431,6275,1189],{"class":654},[431,6277,6278],{"class":445}," 'support@admin.ru'\n",[431,6280,6281,6284,6286],{"class":433,"line":1244},[431,6282,6283],{"class":441},"title ",[431,6285,1189],{"class":654},[431,6287,6288],{"class":445}," 'Помогите'\n",[431,6290,6291,6294,6296],{"class":433,"line":1985},[431,6292,6293],{"class":441},"body ",[431,6295,1189],{"class":654},[431,6297,6298],{"class":445}," 'Я написал историю, как я могу получить скидку?'\n",[431,6300,6301],{"class":433,"line":2041},[431,6302,1662],{"emptyLinePlaceholder":393},[431,6304,6305],{"class":433,"line":4018},[431,6306,6307],{"class":455},"# Один вызов — много логики внутри\n",[431,6309,6310],{"class":433,"line":4030},[431,6311,6312],{"class":441},"send(email, title, body)\n",[415,6314,6315],{},"Внутри себя этот вызов выполняет много логики: соединяется с почтовым сервером, формирует правильный запрос на основе заголовка и тела сообщения, а затем все отправляет, не забыв закрыть соединение.\nСоздадим нашу первую функцию. Ее задача — вывести на экран приветствие: Hello, World!",[422,6317,6319],{"className":424,"code":6318,"language":396,"meta":426,"style":426},"# Определение функции не вызывает и не выполняет код функции\ndef show_greeting():\n    # Внутри тела — отступ четыре пробела\n    text = 'Hello, World!'\n    print(text)\n\n# Вызов функции\nshow_greeting()  # => Hello, World!\n",[428,6320,6321,6326,6338,6343,6353,6361,6365,6370],{"__ignoreMap":426},[431,6322,6323],{"class":433,"line":434},[431,6324,6325],{"class":455},"# Определение функции не вызывает и не выполняет код функции\n",[431,6327,6328,6331,6335],{"class":433,"line":452},[431,6329,6330],{"class":654},"def",[431,6332,6334],{"class":6333},"s7eDp"," show_greeting",[431,6336,6337],{"class":441},"():\n",[431,6339,6340],{"class":433,"line":578},[431,6341,6342],{"class":455},"    # Внутри тела — отступ четыре пробела\n",[431,6344,6345,6348,6350],{"class":433,"line":584},[431,6346,6347],{"class":441},"    text ",[431,6349,1189],{"class":654},[431,6351,6352],{"class":445}," 'Hello, World!'\n",[431,6354,6355,6358],{"class":433,"line":1244},[431,6356,6357],{"class":437},"    print",[431,6359,6360],{"class":441},"(text)\n",[431,6362,6363],{"class":433,"line":1985},[431,6364,1662],{"emptyLinePlaceholder":393},[431,6366,6367],{"class":433,"line":2041},[431,6368,6369],{"class":455},"# Вызов функции\n",[431,6371,6372,6375],{"class":433,"line":4018},[431,6373,6374],{"class":441},"show_greeting()  ",[431,6376,456],{"class":455},[415,6378,6379],{},"Важным моментом при определении функции является то, что внутри тела функции обязательно должен быть отступ в четыре пробела.\nВ отличие от обычных данных, функции выполняют действия.\nПоэтому их имена нужно указывать через глаголы: «построить что-то», «нарисовать что-то», «открыть что-то».\nОписание с отступом, которое находится ниже имени функции, называется телом функции.\nВнутри тела можно писать любой код. Это как небольшая самостоятельная программа — набор произвольных инструкций.\nТело выполняется в тот момент, когда запускается функция. При этом каждый вызов функции запускает тело независимо от других вызовов.\nТело функции может быть пустым, тогда внутри него используется ключевое слово pass(используется как \"заглушка\", чтобы интерпретатор Python не выдавал ошибку, позднее можно будет написать код):",[422,6381,6383],{"className":424,"code":6382,"language":396,"meta":426,"style":426},"# Минимальное определение функции\n# Функция ничего не делает\ndef noop():\n    pass\n\nnoop()\n",[428,6384,6385,6390,6395,6404,6409,6413],{"__ignoreMap":426},[431,6386,6387],{"class":433,"line":434},[431,6388,6389],{"class":455},"# Минимальное определение функции\n",[431,6391,6392],{"class":433,"line":452},[431,6393,6394],{"class":455},"# Функция ничего не делает\n",[431,6396,6397,6399,6402],{"class":433,"line":578},[431,6398,6330],{"class":654},[431,6400,6401],{"class":6333}," noop",[431,6403,6337],{"class":441},[431,6405,6406],{"class":433,"line":584},[431,6407,6408],{"class":654},"    pass\n",[431,6410,6411],{"class":433,"line":1244},[431,6412,1662],{"emptyLinePlaceholder":393},[431,6414,6415],{"class":433,"line":1985},[431,6416,6417],{"class":441},"noop()\n",[415,6419,6420],{},"У понятия «создать функцию» много синонимов: «реализовать», «определить» и даже «заимплементить».\nОни часто встречаются на практике. Создавая свои функции, вы облегчите сложные операции и сделаете разработку проще.",[632,6422,6424],{"id":6423},"возврат-значений","Возврат значений",[415,6426,6427],{},"Когда мы определяем функцию, она печатает на экране какие-то данные:",[422,6429,6431],{"className":424,"code":6430,"language":396,"meta":426,"style":426},"def show_greeting():\n    print('Hello, World!')\n",[428,6432,6433,6441],{"__ignoreMap":426},[431,6434,6435,6437,6439],{"class":433,"line":434},[431,6436,6330],{"class":654},[431,6438,6334],{"class":6333},[431,6440,6337],{"class":441},[431,6442,6443,6445,6447,6449],{"class":433,"line":452},[431,6444,6357],{"class":437},[431,6446,442],{"class":441},[431,6448,446],{"class":445},[431,6450,449],{"class":441},[415,6452,6453],{},"Пользы от таких функций немного, так как результатом нельзя воспользоваться внутри программы. Рассмотрим на примере.\nВозьмем задачу обработки электронной почты. Когда пользователь регистрируется на сайте, он может ввести email любым способом:",[697,6455,6456,6466],{},[700,6457,6458,6459,6465],{},"Добавить случайно пробелы в начале или в конце: ",[1355,6460,6461],{},[1205,6462,6464],{"href":6463},"mailto:support@admin.ru","support@admin.ru","_",[700,6467,6468,6469,6473],{},"Использовать буквы в разных регистрах: ",[1205,6470,6472],{"href":6471},"mailto:SUPPORT@admin.ru","SUPPORT@admin.ru","\nЕсли мы сохраним его в таком виде в базе данных, то пользователь не войдет на сайт.\nЧтобы этого не произошло, email нужно подготовить к записи в базу: привести его к нижнему регистру и обрезать пробелы по краям строки.\nТакая задача решается в пару строчек:",[422,6475,6477],{"className":424,"code":6476,"language":396,"meta":426,"style":426},"def save_email():\n    # Email приходит из формы\n    email = '  SuppORT@admin.ru'\n    # Обрезаем пробельные символы\n    trimmed_email = email.strip()\n    prepared_email = trimmed_email.lower()\n    print(prepared_email)\n    # Здесь будет запись в базу данных \n",[428,6478,6479,6488,6493,6503,6508,6518,6528,6535],{"__ignoreMap":426},[431,6480,6481,6483,6486],{"class":433,"line":434},[431,6482,6330],{"class":654},[431,6484,6485],{"class":6333}," save_email",[431,6487,6337],{"class":441},[431,6489,6490],{"class":433,"line":452},[431,6491,6492],{"class":455},"    # Email приходит из формы\n",[431,6494,6495,6498,6500],{"class":433,"line":578},[431,6496,6497],{"class":441},"    email ",[431,6499,1189],{"class":654},[431,6501,6502],{"class":445}," '  SuppORT@admin.ru'\n",[431,6504,6505],{"class":433,"line":584},[431,6506,6507],{"class":455},"    # Обрезаем пробельные символы\n",[431,6509,6510,6513,6515],{"class":433,"line":1244},[431,6511,6512],{"class":441},"    trimmed_email ",[431,6514,1189],{"class":654},[431,6516,6517],{"class":441}," email.strip()\n",[431,6519,6520,6523,6525],{"class":433,"line":1985},[431,6521,6522],{"class":441},"    prepared_email ",[431,6524,1189],{"class":654},[431,6526,6527],{"class":441}," trimmed_email.lower()\n",[431,6529,6530,6532],{"class":433,"line":2041},[431,6531,6357],{"class":437},[431,6533,6534],{"class":441},"(prepared_email)\n",[431,6536,6537],{"class":433,"line":4018},[431,6538,6539],{"class":455},"    # Здесь будет запись в базу данных\n",[415,6541,6542],{},"Этот код стал возможен благодаря тому, что значение вернулось.\nМетоды strip() и lower() ничего не печатают на экране, они возвращают результат своей работы.\nПоэтому мы можем записать его в переменные.\nЕсли бы они печатали на экране, мы бы не могли присвоить результат переменной.\nНапример, так мы не можем сделать с функцией show_greeting():",[422,6544,6546],{"className":424,"code":6545,"language":396,"meta":426,"style":426},"message = show_greeting()\n# в действительности функция print() возвращает None\n# None — специальный объект, используемый для представления отсутствия значения\nprint(message) # => None\n",[428,6547,6548,6558,6563,6568],{"__ignoreMap":426},[431,6549,6550,6553,6555],{"class":433,"line":434},[431,6551,6552],{"class":441},"message ",[431,6554,1189],{"class":654},[431,6556,6557],{"class":441}," show_greeting()\n",[431,6559,6560],{"class":433,"line":452},[431,6561,6562],{"class":455},"# в действительности функция print() возвращает None\n",[431,6564,6565],{"class":433,"line":578},[431,6566,6567],{"class":455},"# None — специальный объект, используемый для представления отсутствия значения\n",[431,6569,6570,6572,6575],{"class":433,"line":584},[431,6571,438],{"class":437},[431,6573,6574],{"class":441},"(message) ",[431,6576,6577],{"class":455},"# => None\n",[415,6579,6580],{},"Теперь переименуем и изменим функцию show_greeting() так, чтобы она возвращала данные. Для этого выполним возврат вместо печати на экране:",[422,6582,6584],{"className":424,"code":6583,"language":396,"meta":426,"style":426},"def greeting():\n    return 'Hello World!'\n",[428,6585,6586,6595],{"__ignoreMap":426},[431,6587,6588,6590,6593],{"class":433,"line":434},[431,6589,6330],{"class":654},[431,6591,6592],{"class":6333}," greeting",[431,6594,6337],{"class":441},[431,6596,6597,6600],{"class":433,"line":452},[431,6598,6599],{"class":654},"    return",[431,6601,6602],{"class":445}," 'Hello World!'\n",[415,6604,6605],{},"return — это инструкция. Она берет записанное справа выражение и отдает его тому коду, который вызвал метод.\nЗдесь выполнение функции завершается.",[422,6607,6609],{"className":424,"code":6608,"language":396,"meta":426,"style":426},"# Теперь мы можем использовать результат работы функции\nmessage = greeting()\nprint(message) # => Hello World!\n# И даже выполнить какие-то действия над результатом\nprint(message.upper()) # => HELLO WORLD!\n",[428,6610,6611,6616,6625,6633,6638],{"__ignoreMap":426},[431,6612,6613],{"class":433,"line":434},[431,6614,6615],{"class":455},"# Теперь мы можем использовать результат работы функции\n",[431,6617,6618,6620,6622],{"class":433,"line":452},[431,6619,6552],{"class":441},[431,6621,1189],{"class":654},[431,6623,6624],{"class":441}," greeting()\n",[431,6626,6627,6629,6631],{"class":433,"line":578},[431,6628,438],{"class":437},[431,6630,6574],{"class":441},[431,6632,1846],{"class":455},[431,6634,6635],{"class":433,"line":584},[431,6636,6637],{"class":455},"# И даже выполнить какие-то действия над результатом\n",[431,6639,6640,6642,6645],{"class":433,"line":1244},[431,6641,438],{"class":437},[431,6643,6644],{"class":441},"(message.upper()) ",[431,6646,6647],{"class":455},"# => HELLO WORLD!\n",[415,6649,6650],{},"Любой код после return не выполняется:",[422,6652,6654],{"className":424,"code":6653,"language":396,"meta":426,"style":426},"def greeting_with_code_after_return():\n    return 'Hello World!'\n    print('Я никогда не выполнюсь')\n",[428,6655,6656,6665,6671],{"__ignoreMap":426},[431,6657,6658,6660,6663],{"class":433,"line":434},[431,6659,6330],{"class":654},[431,6661,6662],{"class":6333}," greeting_with_code_after_return",[431,6664,6337],{"class":441},[431,6666,6667,6669],{"class":433,"line":452},[431,6668,6599],{"class":654},[431,6670,6602],{"class":445},[431,6672,6673,6675,6677,6680],{"class":433,"line":578},[431,6674,6357],{"class":437},[431,6676,442],{"class":441},[431,6678,6679],{"class":445},"'Я никогда не выполнюсь'",[431,6681,449],{"class":441},[415,6683,6684],{},"Даже если функция возвращает данные, это не ограничивает ее в том, что она печатает.\nКроме возврата данных мы можем и печатать:",[422,6686,6688],{"className":424,"code":6687,"language":396,"meta":426,"style":426},"def greeting_with_return_and_printing():\n    print('Я появлюсь в консоли')\n    return 'Hello World!'\n\n\n# И напечатает текст на экране, и вернет значение\nmessage = greeting_with_return_and_printing()\n",[428,6689,6690,6699,6710,6716,6720,6724,6729],{"__ignoreMap":426},[431,6691,6692,6694,6697],{"class":433,"line":434},[431,6693,6330],{"class":654},[431,6695,6696],{"class":6333}," greeting_with_return_and_printing",[431,6698,6337],{"class":441},[431,6700,6701,6703,6705,6708],{"class":433,"line":452},[431,6702,6357],{"class":437},[431,6704,442],{"class":441},[431,6706,6707],{"class":445},"'Я появлюсь в консоли'",[431,6709,449],{"class":441},[431,6711,6712,6714],{"class":433,"line":578},[431,6713,6599],{"class":654},[431,6715,6602],{"class":445},[431,6717,6718],{"class":433,"line":584},[431,6719,1662],{"emptyLinePlaceholder":393},[431,6721,6722],{"class":433,"line":1244},[431,6723,1662],{"emptyLinePlaceholder":393},[431,6725,6726],{"class":433,"line":1985},[431,6727,6728],{"class":455},"# И напечатает текст на экране, и вернет значение\n",[431,6730,6731,6733,6735],{"class":433,"line":2041},[431,6732,6552],{"class":441},[431,6734,1189],{"class":654},[431,6736,6737],{"class":441}," greeting_with_return_and_printing()\n",[415,6739,6740],{},"Возвращать можно не только конкретное значение.\nТак как return работает с выражениями, то справа от него может быть что угодно.\nЗдесь нужно руководствоваться принципами читаемости кода:",[422,6742,6744],{"className":424,"code":6743,"language":396,"meta":426,"style":426},"def greeting():\n    message = 'Hello World!'\n    return message\n",[428,6745,6746,6754,6763],{"__ignoreMap":426},[431,6747,6748,6750,6752],{"class":433,"line":434},[431,6749,6330],{"class":654},[431,6751,6592],{"class":6333},[431,6753,6337],{"class":441},[431,6755,6756,6759,6761],{"class":433,"line":452},[431,6757,6758],{"class":441},"    message ",[431,6760,1189],{"class":654},[431,6762,6602],{"class":445},[431,6764,6765,6767],{"class":433,"line":578},[431,6766,6599],{"class":654},[431,6768,6769],{"class":441}," message\n",[415,6771,6772],{},"Здесь мы не возвращаем переменную.\nВозвращается всегда значение, которое находится в этой переменной.\nНиже пример с вычислениями:",[422,6774,6776],{"className":424,"code":6775,"language":396,"meta":426,"style":426},"def double_four():\n    # или return 4 + 4\n    result = 4 + 4\n    return result\n",[428,6777,6778,6787,6792,6806],{"__ignoreMap":426},[431,6779,6780,6782,6785],{"class":433,"line":434},[431,6781,6330],{"class":654},[431,6783,6784],{"class":6333}," double_four",[431,6786,6337],{"class":441},[431,6788,6789],{"class":433,"line":452},[431,6790,6791],{"class":455},"    # или return 4 + 4\n",[431,6793,6794,6797,6799,6801,6803],{"class":433,"line":578},[431,6795,6796],{"class":441},"    result ",[431,6798,1189],{"class":654},[431,6800,905],{"class":437},[431,6802,655],{"class":654},[431,6804,6805],{"class":437}," 4\n",[431,6807,6808,6810],{"class":433,"line":584},[431,6809,6599],{"class":654},[431,6811,6812],{"class":441}," result\n",[415,6814,6815],{},"Определить функцию мало. Еще важно, чтобы она была полезна, и результатом можно было воспользоваться.\nА теперь подумайте, что вернет вызов функции run(), определенной ниже:",[422,6817,6819],{"className":424,"code":6818,"language":396,"meta":426,"style":426},"# Определение\ndef run():\n    return 1\n    return 2\n\n\n# Что будет выведено на экран?\nprint(run())\n",[428,6820,6821,6826,6835,6841,6847,6851,6855,6860],{"__ignoreMap":426},[431,6822,6823],{"class":433,"line":434},[431,6824,6825],{"class":455},"# Определение\n",[431,6827,6828,6830,6833],{"class":433,"line":452},[431,6829,6330],{"class":654},[431,6831,6832],{"class":6333}," run",[431,6834,6337],{"class":441},[431,6836,6837,6839],{"class":433,"line":578},[431,6838,6599],{"class":654},[431,6840,3916],{"class":437},[431,6842,6843,6845],{"class":433,"line":584},[431,6844,6599],{"class":654},[431,6846,658],{"class":437},[431,6848,6849],{"class":433,"line":1244},[431,6850,1662],{"emptyLinePlaceholder":393},[431,6852,6853],{"class":433,"line":1985},[431,6854,1662],{"emptyLinePlaceholder":393},[431,6856,6857],{"class":433,"line":2041},[431,6858,6859],{"class":455},"# Что будет выведено на экран?\n",[431,6861,6862,6864],{"class":433,"line":4018},[431,6863,438],{"class":437},[431,6865,6866],{"class":441},"(run())\n",[632,6868,6870],{"id":6869},"параметры-функций","Параметры функций",[415,6872,6873],{},"Функции могут не только возвращать значения, но и принимать параметры.\nНапомним, что с параметрами функций мы уже сталкивались:",[422,6875,6877],{"className":424,"code":6876,"language":396,"meta":426,"style":426},"# Принимает на вход один параметр любого типа\nprint('я параметр')\n# Принимает на вход два строковых параметра\n# первый — что ищем, второй — на что меняем\n'google'.replace('go', 'mo')  # moogle\n# Принимает на вход два числовых параметра\n# первый — округляемое число, второй — число знаков после запятой, которые нужно оставить\nround(10.23456, 3)  # 10.235\n",[428,6878,6879,6884,6895,6900,6905,6926,6931,6936],{"__ignoreMap":426},[431,6880,6881],{"class":433,"line":434},[431,6882,6883],{"class":455},"# Принимает на вход один параметр любого типа\n",[431,6885,6886,6888,6890,6893],{"class":433,"line":452},[431,6887,438],{"class":437},[431,6889,442],{"class":441},[431,6891,6892],{"class":445},"'я параметр'",[431,6894,449],{"class":441},[431,6896,6897],{"class":433,"line":578},[431,6898,6899],{"class":455},"# Принимает на вход два строковых параметра\n",[431,6901,6902],{"class":433,"line":584},[431,6903,6904],{"class":455},"# первый — что ищем, второй — на что меняем\n",[431,6906,6907,6910,6913,6916,6918,6921,6923],{"class":433,"line":1244},[431,6908,6909],{"class":445},"'google'",[431,6911,6912],{"class":441},".replace(",[431,6914,6915],{"class":445},"'go'",[431,6917,4846],{"class":441},[431,6919,6920],{"class":445},"'mo'",[431,6922,526],{"class":441},[431,6924,6925],{"class":455},"# moogle\n",[431,6927,6928],{"class":433,"line":1985},[431,6929,6930],{"class":455},"# Принимает на вход два числовых параметра\n",[431,6932,6933],{"class":433,"line":2041},[431,6934,6935],{"class":455},"# первый — округляемое число, второй — число знаков после запятой, которые нужно оставить\n",[431,6937,6938,6940,6942,6945,6947,6949,6951],{"class":433,"line":4018},[431,6939,5004],{"class":437},[431,6941,442],{"class":441},[431,6943,6944],{"class":437},"10.23456",[431,6946,4846],{"class":441},[431,6948,971],{"class":437},[431,6950,526],{"class":441},[431,6952,6953],{"class":455},"# 10.235\n",[415,6955,6956],{},"А теперь представим, что нам нужно реализовать функцию get_last_char(), которая возвращает последний символ в строке, переданной ей на вход как параметр.\nВот как будет выглядеть использование этой функции:",[422,6958,6960],{"className":424,"code":6959,"language":396,"meta":426,"style":426},"# Передача параметров напрямую без переменных\nget_last_char(\"Python\")  # n\n# Передача параметров через переменные\nname1 = 'Python'\nget_last_char(name1)  # n\nname2 = 'Go'\nget_last_char(name2)  # o\n",[428,6961,6962,6967,6980,6985,6994,7001,7011],{"__ignoreMap":426},[431,6963,6964],{"class":433,"line":434},[431,6965,6966],{"class":455},"# Передача параметров напрямую без переменных\n",[431,6968,6969,6972,6975,6977],{"class":433,"line":452},[431,6970,6971],{"class":441},"get_last_char(",[431,6973,6974],{"class":445},"\"Python\"",[431,6976,526],{"class":441},[431,6978,6979],{"class":455},"# n\n",[431,6981,6982],{"class":433,"line":578},[431,6983,6984],{"class":455},"# Передача параметров через переменные\n",[431,6986,6987,6990,6992],{"class":433,"line":584},[431,6988,6989],{"class":441},"name1 ",[431,6991,1189],{"class":654},[431,6993,3648],{"class":445},[431,6995,6996,6999],{"class":433,"line":1244},[431,6997,6998],{"class":441},"get_last_char(name1)  ",[431,7000,6979],{"class":455},[431,7002,7003,7006,7008],{"class":433,"line":1985},[431,7004,7005],{"class":441},"name2 ",[431,7007,1189],{"class":654},[431,7009,7010],{"class":445}," 'Go'\n",[431,7012,7013,7016],{"class":433,"line":2041},[431,7014,7015],{"class":441},"get_last_char(name2)  ",[431,7017,7018],{"class":455},"# o\n",[415,7020,7021],{},"Из этого примера можно сделать следующие выводы:",[697,7023,7024,7027,7030],{},[700,7025,7026],{},"Нужно определить функцию get_last_char()",[700,7028,7029],{},"Функция должна принимать на вход один параметр строкового типа",[700,7031,7032],{},"Функция должна возвращать значение строкового типа",[415,7034,7035],{},"Определяем функцию:",[422,7037,7039],{"className":424,"code":7038,"language":396,"meta":426,"style":426},"def get_last_char(text):\n    return text[-1]\n",[428,7040,7041,7051],{"__ignoreMap":426},[431,7042,7043,7045,7048],{"class":433,"line":434},[431,7044,6330],{"class":654},[431,7046,7047],{"class":6333}," get_last_char",[431,7049,7050],{"class":441},"(text):\n",[431,7052,7053,7055,7058,7060,7062],{"class":433,"line":452},[431,7054,6599],{"class":654},[431,7056,7057],{"class":441}," text[",[431,7059,853],{"class":654},[431,7061,1192],{"class":437},[431,7063,3568],{"class":441},[415,7065,7066],{},"В скобках указывается имя переменной text, которая служит параметром. Имя параметра может быть любым.\nГлавное, чтобы оно отражало смысл значения, которое содержится внутри. Например:",[422,7068,7070],{"className":424,"code":7069,"language":396,"meta":426,"style":426},"def get_last_char(string):\n    return string[-1]\n",[428,7071,7072,7081],{"__ignoreMap":426},[431,7073,7074,7076,7078],{"class":433,"line":434},[431,7075,6330],{"class":654},[431,7077,7047],{"class":6333},[431,7079,7080],{"class":441},"(string):\n",[431,7082,7083,7085,7088,7090,7092],{"class":433,"line":452},[431,7084,6599],{"class":654},[431,7086,7087],{"class":441}," string[",[431,7089,853],{"class":654},[431,7091,1192],{"class":437},[431,7093,3568],{"class":441},[415,7095,7096],{},"Значение параметра будет зависеть от вызова этой функции:",[422,7098,7100],{"className":424,"code":7099,"language":396,"meta":426,"style":426},"# Внутри функции string будет равна 'python'\nget_last_char('python')  # n\n\n# Внутри функции string будет равна 'code'\nget_last_char('code')  # e\n\n# Внутри функции string будет равна 'Summer'\n# Имя переменной снаружи не связано с именем переменной в определении функции\ntext = 'Summer'\nget_last_char(text)  # r\n",[428,7101,7102,7107,7118,7122,7127,7139,7143,7148,7153,7162],{"__ignoreMap":426},[431,7103,7104],{"class":433,"line":434},[431,7105,7106],{"class":455},"# Внутри функции string будет равна 'python'\n",[431,7108,7109,7111,7114,7116],{"class":433,"line":452},[431,7110,6971],{"class":441},[431,7112,7113],{"class":445},"'python'",[431,7115,526],{"class":441},[431,7117,6979],{"class":455},[431,7119,7120],{"class":433,"line":578},[431,7121,1662],{"emptyLinePlaceholder":393},[431,7123,7124],{"class":433,"line":584},[431,7125,7126],{"class":455},"# Внутри функции string будет равна 'code'\n",[431,7128,7129,7131,7134,7136],{"class":433,"line":1244},[431,7130,6971],{"class":441},[431,7132,7133],{"class":445},"'code'",[431,7135,526],{"class":441},[431,7137,7138],{"class":455},"# e\n",[431,7140,7141],{"class":433,"line":1985},[431,7142,1662],{"emptyLinePlaceholder":393},[431,7144,7145],{"class":433,"line":2041},[431,7146,7147],{"class":455},"# Внутри функции string будет равна 'Summer'\n",[431,7149,7150],{"class":433,"line":4018},[431,7151,7152],{"class":455},"# Имя переменной снаружи не связано с именем переменной в определении функции\n",[431,7154,7155,7157,7159],{"class":433,"line":4030},[431,7156,3100],{"class":441},[431,7158,1189],{"class":654},[431,7160,7161],{"class":445}," 'Summer'\n",[431,7163,7164,7167],{"class":433,"line":4419},[431,7165,7166],{"class":441},"get_last_char(text)  ",[431,7168,7169],{"class":455},"# r\n",[415,7171,7172],{},"Параметр нужно обязательно указывать. Если вызвать функцию без него, то интерпретатор выдаст ошибку:",[422,7174,7176],{"className":424,"code":7175,"language":396,"meta":426,"style":426},"get_last_char()  # У такого кода нет смысла\n\nTypeError: get_last_char() missing 1 required positional argument: 'string'\n",[428,7177,7178,7186,7190],{"__ignoreMap":426},[431,7179,7180,7183],{"class":433,"line":434},[431,7181,7182],{"class":441},"get_last_char()  ",[431,7184,7185],{"class":455},"# У такого кода нет смысла\n",[431,7187,7188],{"class":433,"line":452},[431,7189,1662],{"emptyLinePlaceholder":393},[431,7191,7192,7195,7198,7200,7203],{"class":433,"line":578},[431,7193,7194],{"class":437},"TypeError",[431,7196,7197],{"class":441},": get_last_char() missing ",[431,7199,1192],{"class":437},[431,7201,7202],{"class":441}," required positional argument: ",[431,7204,7205],{"class":445},"'string'\n",[415,7207,7208],{},"Многие функции работают одновременно с несколькими параметрами.\nНапример, чтобы округлить число, нужно указать не только само число, но и количество знаков после запятой:",[422,7210,7212],{"className":424,"code":7211,"language":396,"meta":426,"style":426},"round(10.23456, 3)  # 10.235\n",[428,7213,7214],{"__ignoreMap":426},[431,7215,7216,7218,7220,7222,7224,7226,7228],{"class":433,"line":434},[431,7217,5004],{"class":437},[431,7219,442],{"class":441},[431,7221,6944],{"class":437},[431,7223,4846],{"class":441},[431,7225,971],{"class":437},[431,7227,526],{"class":441},[431,7229,6953],{"class":455},[415,7231,7232],{},"То же самое относится и к методам. Они могут требовать на вход любое количество параметров, которое им нужно для работы:",[422,7234,7236],{"className":424,"code":7235,"language":396,"meta":426,"style":426},"# Первый параметр — что ищем\n# Второй параметр — на что меняем\n'google'.replace('go', 'do')  # doogle\n",[428,7237,7238,7243,7248],{"__ignoreMap":426},[431,7239,7240],{"class":433,"line":434},[431,7241,7242],{"class":455},"# Первый параметр — что ищем\n",[431,7244,7245],{"class":433,"line":452},[431,7246,7247],{"class":455},"# Второй параметр — на что меняем\n",[431,7249,7250,7252,7254,7256,7258,7261,7263],{"class":433,"line":578},[431,7251,6909],{"class":445},[431,7253,6912],{"class":441},[431,7255,6915],{"class":445},[431,7257,4846],{"class":441},[431,7259,7260],{"class":445},"'do'",[431,7262,526],{"class":441},[431,7264,7265],{"class":455},"# doogle\n",[415,7267,7268],{},"Чтобы создать такие функции и методы, в определении нужно указать необходимое количество параметров через запятую.\nЕще им нужно дать понятные имена.\nНиже пример определения функции replace(), которая заменяет в слове одну часть строки на другую:",[422,7270,7272],{"className":424,"code":7271,"language":396,"meta":426,"style":426},"def replace(text, from_, to):\n    # Здесь тело функции\n\nreplace('google', 'go', 'do')  # doogle\n",[428,7273,7274,7284,7289,7293],{"__ignoreMap":426},[431,7275,7276,7278,7281],{"class":433,"line":434},[431,7277,6330],{"class":654},[431,7279,7280],{"class":6333}," replace",[431,7282,7283],{"class":441},"(text, from_, to):\n",[431,7285,7286],{"class":433,"line":452},[431,7287,7288],{"class":455},"    # Здесь тело функции\n",[431,7290,7291],{"class":433,"line":578},[431,7292,1662],{"emptyLinePlaceholder":393},[431,7294,7295,7298,7300,7302,7304,7306,7308,7310],{"class":433,"line":584},[431,7296,7297],{"class":441},"replace(",[431,7299,6909],{"class":445},[431,7301,4846],{"class":441},[431,7303,6915],{"class":445},[431,7305,4846],{"class":441},[431,7307,7260],{"class":445},[431,7309,526],{"class":441},[431,7311,7265],{"class":455},[415,7313,7314],{},"Когда параметров два и более, то практически для всех функций важен порядок передачи этих параметров.\nЕсли его поменять, то функция отработает по-другому:",[422,7316,7318],{"className":424,"code":7317,"language":396,"meta":426,"style":426},"# Ничего не заменилось, так как внутри google нет do\nreplace('google', 'do', 'go')  # google\n",[428,7319,7320,7325],{"__ignoreMap":426},[431,7321,7322],{"class":433,"line":434},[431,7323,7324],{"class":455},"# Ничего не заменилось, так как внутри google нет do\n",[431,7326,7327,7329,7331,7333,7335,7337,7339,7341],{"class":433,"line":452},[431,7328,7297],{"class":441},[431,7330,6909],{"class":445},[431,7332,4846],{"class":441},[431,7334,7260],{"class":445},[431,7336,4846],{"class":441},[431,7338,6915],{"class":445},[431,7340,526],{"class":441},[431,7342,7343],{"class":455},"# google\n",[632,7345,7347],{"id":7346},"необязательные-параметры-функций","Необязательные параметры функций",[415,7349,7350],{},"В программировании у многих функций и методов есть параметры, которые редко меняются.\nВ таких случаях этим параметрам задают значения по умолчанию, которые можно поменять по необходимости.\nС помощью этого сокращается количество одинакового кода. Рассмотрим, как это выглядит на практике.\nРазберем пример:",[422,7352,7354],{"className":424,"code":7353,"language":396,"meta":426,"style":426},"# Функция возведения в степень\n# Второй параметр имеет значение по умолчанию два\ndef pow(x, base=2):\n    return x ** base\n\n# Три во второй степени (двойка задана по умолчанию)\npow(3)  # 3 * 3 = 9\n# Три в третьей степени\npow(3, 3)  # 3 * 3 * 3 = 27\n",[428,7355,7356,7361,7366,7382,7395,7399,7404,7417,7422],{"__ignoreMap":426},[431,7357,7358],{"class":433,"line":434},[431,7359,7360],{"class":455},"# Функция возведения в степень\n",[431,7362,7363],{"class":433,"line":452},[431,7364,7365],{"class":455},"# Второй параметр имеет значение по умолчанию два\n",[431,7367,7368,7370,7372,7375,7377,7379],{"class":433,"line":578},[431,7369,6330],{"class":654},[431,7371,4839],{"class":437},[431,7373,7374],{"class":441},"(x, base",[431,7376,1189],{"class":654},[431,7378,651],{"class":437},[431,7380,7381],{"class":441},"):\n",[431,7383,7384,7386,7389,7392],{"class":433,"line":584},[431,7385,6599],{"class":654},[431,7387,7388],{"class":441}," x ",[431,7390,7391],{"class":654},"**",[431,7393,7394],{"class":441}," base\n",[431,7396,7397],{"class":433,"line":1244},[431,7398,1662],{"emptyLinePlaceholder":393},[431,7400,7401],{"class":433,"line":1985},[431,7402,7403],{"class":455},"# Три во второй степени (двойка задана по умолчанию)\n",[431,7405,7406,7408,7410,7412,7414],{"class":433,"line":2041},[431,7407,4895],{"class":437},[431,7409,442],{"class":441},[431,7411,971],{"class":437},[431,7413,526],{"class":441},[431,7415,7416],{"class":455},"# 3 * 3 = 9\n",[431,7418,7419],{"class":433,"line":4018},[431,7420,7421],{"class":455},"# Три в третьей степени\n",[431,7423,7424,7426,7428,7430,7432,7434,7436],{"class":433,"line":4030},[431,7425,4895],{"class":437},[431,7427,442],{"class":441},[431,7429,971],{"class":437},[431,7431,4846],{"class":441},[431,7433,971],{"class":437},[431,7435,526],{"class":441},[431,7437,7438],{"class":455},"# 3 * 3 * 3 = 27\n",[415,7440,7441],{},"Значение по умолчанию выглядит как обычное присваивание в определении. Оно срабатывает только в том случае, если параметр не передали.\nПредставьте, что вы не привезли с собой в автосервис запчасти для вашего автомобиля.\nТогда автомеханик предложит вам поставить те, которые есть у него — в наличии, по умолчанию.\nЗначение по умолчанию может быть даже в том случае, когда параметр один:",[422,7443,7445],{"className":424,"code":7444,"language":396,"meta":426,"style":426},"def my_print(text='nothing'):\n    print(text)\n\nmy_print()  # => \"nothing\"\nmy_print(\"Python\")  # => \"Python\"\n",[428,7446,7447,7464,7470,7474,7482],{"__ignoreMap":426},[431,7448,7449,7451,7454,7457,7459,7462],{"class":433,"line":434},[431,7450,6330],{"class":654},[431,7452,7453],{"class":6333}," my_print",[431,7455,7456],{"class":441},"(text",[431,7458,1189],{"class":654},[431,7460,7461],{"class":445},"'nothing'",[431,7463,7381],{"class":441},[431,7465,7466,7468],{"class":433,"line":452},[431,7467,6357],{"class":437},[431,7469,6360],{"class":441},[431,7471,7472],{"class":433,"line":578},[431,7473,1662],{"emptyLinePlaceholder":393},[431,7475,7476,7479],{"class":433,"line":584},[431,7477,7478],{"class":441},"my_print()  ",[431,7480,7481],{"class":455},"# => \"nothing\"\n",[431,7483,7484,7487,7489,7491],{"class":433,"line":1244},[431,7485,7486],{"class":441},"my_print(",[431,7488,6974],{"class":445},[431,7490,526],{"class":441},[431,7492,7493],{"class":455},"# => \"Python\"\n",[415,7495,7496],{},"Параметров со значениями по умолчанию может быть любое количество:",[422,7498,7500],{"className":424,"code":7499,"language":396,"meta":426,"style":426},"def print_params(a=5, b=10, c=100):\n    ...\n",[428,7501,7502,7532],{"__ignoreMap":426},[431,7503,7504,7506,7509,7512,7514,7516,7519,7521,7523,7526,7528,7530],{"class":433,"line":434},[431,7505,6330],{"class":654},[431,7507,7508],{"class":6333}," print_params",[431,7510,7511],{"class":441},"(a",[431,7513,1189],{"class":654},[431,7515,856],{"class":437},[431,7517,7518],{"class":441},", b",[431,7520,1189],{"class":654},[431,7522,3565],{"class":437},[431,7524,7525],{"class":441},", c",[431,7527,1189],{"class":654},[431,7529,2249],{"class":437},[431,7531,7381],{"class":441},[431,7533,7534],{"class":433,"line":452},[431,7535,7536],{"class":437},"    ...\n",[415,7538,7539],{},"У значений по умолчанию есть одно ограничение. Они должны идти в самом конце списка параметров.\nС точки зрения синтаксиса, невозможно создать функцию, у которой после необязательного параметра идет обязательный:",[422,7541,7543],{"className":424,"code":7542,"language":396,"meta":426,"style":426},"# Такой код завершится с ошибкой\ndef print_params(a=5, b=10, c=100, x):\n# И такой\ndef print_params(a=5, b=10, x, c=100):\n\n# Этот код сработает\ndef print_params(x, a=5, b=10, c=100):\n\n# Этот тоже сработает\ndef print_params(x, y, a=5, b=10, c=100):\n",[428,7544,7545,7550,7577,7582,7609,7613,7618,7645,7649,7654],{"__ignoreMap":426},[431,7546,7547],{"class":433,"line":434},[431,7548,7549],{"class":455},"# Такой код завершится с ошибкой\n",[431,7551,7552,7554,7556,7558,7560,7562,7564,7566,7568,7570,7572,7574],{"class":433,"line":452},[431,7553,6330],{"class":654},[431,7555,7508],{"class":6333},[431,7557,7511],{"class":441},[431,7559,1189],{"class":654},[431,7561,856],{"class":437},[431,7563,7518],{"class":441},[431,7565,1189],{"class":654},[431,7567,3565],{"class":437},[431,7569,7525],{"class":441},[431,7571,1189],{"class":654},[431,7573,2249],{"class":437},[431,7575,7576],{"class":441},", x):\n",[431,7578,7579],{"class":433,"line":578},[431,7580,7581],{"class":455},"# И такой\n",[431,7583,7584,7586,7588,7590,7592,7594,7596,7598,7600,7603,7605,7607],{"class":433,"line":584},[431,7585,6330],{"class":654},[431,7587,7508],{"class":6333},[431,7589,7511],{"class":441},[431,7591,1189],{"class":654},[431,7593,856],{"class":437},[431,7595,7518],{"class":441},[431,7597,1189],{"class":654},[431,7599,3565],{"class":437},[431,7601,7602],{"class":441},", x, c",[431,7604,1189],{"class":654},[431,7606,2249],{"class":437},[431,7608,7381],{"class":441},[431,7610,7611],{"class":433,"line":1244},[431,7612,1662],{"emptyLinePlaceholder":393},[431,7614,7615],{"class":433,"line":1985},[431,7616,7617],{"class":455},"# Этот код сработает\n",[431,7619,7620,7622,7624,7627,7629,7631,7633,7635,7637,7639,7641,7643],{"class":433,"line":2041},[431,7621,6330],{"class":654},[431,7623,7508],{"class":6333},[431,7625,7626],{"class":441},"(x, a",[431,7628,1189],{"class":654},[431,7630,856],{"class":437},[431,7632,7518],{"class":441},[431,7634,1189],{"class":654},[431,7636,3565],{"class":437},[431,7638,7525],{"class":441},[431,7640,1189],{"class":654},[431,7642,2249],{"class":437},[431,7644,7381],{"class":441},[431,7646,7647],{"class":433,"line":4018},[431,7648,1662],{"emptyLinePlaceholder":393},[431,7650,7651],{"class":433,"line":4030},[431,7652,7653],{"class":455},"# Этот тоже сработает\n",[431,7655,7656,7658,7660,7663,7665,7667,7669,7671,7673,7675,7677,7679],{"class":433,"line":4419},[431,7657,6330],{"class":654},[431,7659,7508],{"class":6333},[431,7661,7662],{"class":441},"(x, y, a",[431,7664,1189],{"class":654},[431,7666,856],{"class":437},[431,7668,7518],{"class":441},[431,7670,1189],{"class":654},[431,7672,3565],{"class":437},[431,7674,7525],{"class":441},[431,7676,1189],{"class":654},[431,7678,2249],{"class":437},[431,7680,7381],{"class":441},[415,7682,7683],{},"Значения по умолчанию могут быть как у нескольких параметров, так и у одного.\nИ помните, что значения по умолчанию должны быть в самом конце списка параметров.\nЭти знания помогут сократить количество одинакового кода.",[458,7685,7687],{"id":7686},"функции-с-переменным-числом-параметров","Функции с переменным числом параметров",[415,7689,7690],{},"У некоторых функций есть особенность — они принимают переменное число параметров.\nИ мы говорим не о значениях по умолчанию. Посмотрите на этот пример:",[422,7692,7694],{"className":424,"code":7693,"language":396,"meta":426,"style":426},"max(1, 10, 3)  # 10\n",[428,7695,7696],{"__ignoreMap":426},[431,7697,7698,7701,7703,7705,7707,7709,7711,7713,7715],{"class":433,"line":434},[431,7699,7700],{"class":437},"max",[431,7702,442],{"class":441},[431,7704,1192],{"class":437},[431,7706,4846],{"class":441},[431,7708,3565],{"class":437},[431,7710,4846],{"class":441},[431,7712,971],{"class":437},[431,7714,526],{"class":441},[431,7716,7717],{"class":455},"# 10\n",[415,7719,7720],{},"В примере выше функция max() находит максимальное значение среди переданных параметров.\nЧтобы узнать, сколько параметров можно передавать на вход, нужно изучить документацию этой функции.\nТам мы увидим такую конструкцию:",[422,7722,7724],{"className":424,"code":7723,"language":396,"meta":426,"style":426},"max(arg1, arg2, *args[, key])\n",[428,7725,7726],{"__ignoreMap":426},[431,7727,7728,7730,7733,7735],{"class":433,"line":434},[431,7729,7700],{"class":437},[431,7731,7732],{"class":441},"(arg1, arg2, ",[431,7734,1357],{"class":654},[431,7736,7737],{"class":441},"args[, key])\n",[415,7739,7740],{},"Это значит, что max() принимает на вход два параметра и больше:",[422,7742,7744],{"className":424,"code":7743,"language":396,"meta":426,"style":426},"max(1, 3, 2, 4, 2)  # 4\n",[428,7745,7746],{"__ignoreMap":426},[431,7747,7748,7750,7752,7754,7756,7758,7760,7762,7764,7766,7768,7770,7772],{"class":433,"line":434},[431,7749,7700],{"class":437},[431,7751,442],{"class":441},[431,7753,1192],{"class":437},[431,7755,4846],{"class":441},[431,7757,971],{"class":437},[431,7759,4846],{"class":441},[431,7761,651],{"class":437},[431,7763,4846],{"class":441},[431,7765,762],{"class":437},[431,7767,4846],{"class":441},[431,7769,651],{"class":437},[431,7771,526],{"class":441},[431,7773,7774],{"class":455},"# 4\n",[415,7776,7777],{},"Если функция найдет несколько параметров с максимальным значением, значит, она вернет самый первый из них.",[632,7779,7781],{"id":7780},"именованные-аргументы","Именованные аргументы",[415,7783,7784],{},"Разберем, какие параметры существуют, чем они отличаются и в каких случаях их применять.",[458,7786,7788],{"id":7787},"какие-параметры-существуют","Какие параметры существуют",[415,7790,7791,7794],{},[800,7792,7793],{},"Аргументы"," — это данные, которые передаются в вызов функции. Они бывают двух типов:",[415,7796,7797,7798,7801],{},"Первый тип — ",[800,7799,7800],{},"позиционные аргументы",". Они передаются в том же порядке, в котором определены параметры функции:",[422,7803,7805],{"className":424,"code":7804,"language":396,"meta":426,"style":426},"# (text, length)\ntruncate('My Text', 3)\n",[428,7806,7807,7812],{"__ignoreMap":426},[431,7808,7809],{"class":433,"line":434},[431,7810,7811],{"class":455},"# (text, length)\n",[431,7813,7814,7817,7820,7822,7824],{"class":433,"line":452},[431,7815,7816],{"class":441},"truncate(",[431,7818,7819],{"class":445},"'My Text'",[431,7821,4846],{"class":441},[431,7823,971],{"class":437},[431,7825,449],{"class":441},[415,7827,7828,7829,7832],{},"Второй тип — ",[800,7830,7831],{},"именованные аргументы",".\nОни передаются не просто как значения, а как пары «имя=значение».\nПоэтому их можно передавать в любом порядке:",[422,7834,7836],{"className":424,"code":7835,"language":396,"meta":426,"style":426},"# Аргументы переданы в другом порядке\ntruncate(length=3, text='My Text')\n",[428,7837,7838,7843],{"__ignoreMap":426},[431,7839,7840],{"class":433,"line":434},[431,7841,7842],{"class":455},"# Аргументы переданы в другом порядке\n",[431,7844,7845,7847,7851,7853,7855,7857,7860,7862,7864],{"class":433,"line":452},[431,7846,7816],{"class":441},[431,7848,7850],{"class":7849},"sqxcx","length",[431,7852,1189],{"class":654},[431,7854,971],{"class":437},[431,7856,4846],{"class":441},[431,7858,7859],{"class":7849},"text",[431,7861,1189],{"class":654},[431,7863,7819],{"class":445},[431,7865,449],{"class":441},[415,7867,7868],{},"Если внимательно посмотреть на два примера выше, то можно понять, что это две одинаковые функции.",[415,7870,7871],{},"Теперь разберемся, в каких случаях нужно применять эти типы аргументов.",[458,7873,7875],{"id":7874},"какие-параметры-использовать","Какие параметры использовать",[415,7877,7878],{},"Выбор типа параметра зависит от того, кто вызывает функцию.",[415,7880,7881],{},"Есть две причины использовать именованные аргументы:",[697,7883,7884,7887],{},[700,7885,7886],{},"Они повышают читаемость, так как сразу видно имена.",[700,7888,7889],{},"Можно не указывать все промежуточные параметры, которые нам сейчас не нужны.",[415,7891,7892],{},"Последнее полезно, если у функции много необязательных параметров. Посмотрим на примере:",[422,7894,7896],{"className":424,"code":7895,"language":396,"meta":426,"style":426},"def print_params(a=1, b=2, c=None, d=4):\n    print(a, b, c, d)\n\n# Нужно передать только d, но приходится передавать все\nprint_params(1, 2, None, 8)\n\n# Именованные аргументы позволяют передавать только d\n# Для остальных аргументов используются значения по умолчанию\nprint_params(d=8)\n",[428,7897,7898,7932,7939,7943,7948,7969,7973,7978,7983],{"__ignoreMap":426},[431,7899,7900,7902,7904,7906,7908,7910,7912,7914,7916,7918,7920,7923,7926,7928,7930],{"class":433,"line":434},[431,7901,6330],{"class":654},[431,7903,7508],{"class":6333},[431,7905,7511],{"class":441},[431,7907,1189],{"class":654},[431,7909,1192],{"class":437},[431,7911,7518],{"class":441},[431,7913,1189],{"class":654},[431,7915,651],{"class":437},[431,7917,7525],{"class":441},[431,7919,1189],{"class":654},[431,7921,7922],{"class":437},"None",[431,7924,7925],{"class":441},", d",[431,7927,1189],{"class":654},[431,7929,762],{"class":437},[431,7931,7381],{"class":441},[431,7933,7934,7936],{"class":433,"line":452},[431,7935,6357],{"class":437},[431,7937,7938],{"class":441},"(a, b, c, d)\n",[431,7940,7941],{"class":433,"line":578},[431,7942,1662],{"emptyLinePlaceholder":393},[431,7944,7945],{"class":433,"line":584},[431,7946,7947],{"class":455},"# Нужно передать только d, но приходится передавать все\n",[431,7949,7950,7953,7955,7957,7959,7961,7963,7965,7967],{"class":433,"line":1244},[431,7951,7952],{"class":441},"print_params(",[431,7954,1192],{"class":437},[431,7956,4846],{"class":441},[431,7958,651],{"class":437},[431,7960,4846],{"class":441},[431,7962,7922],{"class":437},[431,7964,4846],{"class":441},[431,7966,1021],{"class":437},[431,7968,449],{"class":441},[431,7970,7971],{"class":433,"line":1985},[431,7972,1662],{"emptyLinePlaceholder":393},[431,7974,7975],{"class":433,"line":2041},[431,7976,7977],{"class":455},"# Именованные аргументы позволяют передавать только d\n",[431,7979,7980],{"class":433,"line":4018},[431,7981,7982],{"class":455},"# Для остальных аргументов используются значения по умолчанию\n",[431,7984,7985,7987,7990,7992,7994],{"class":433,"line":4030},[431,7986,7952],{"class":441},[431,7988,7989],{"class":7849},"d",[431,7991,1189],{"class":654},[431,7993,1021],{"class":437},[431,7995,449],{"class":441},[415,7997,7998],{},"Именованные аргументы можно передавать одновременно с позиционными. Тогда позиционные должны идти в самом начале:",[422,8000,8002],{"className":424,"code":8001,"language":396,"meta":426,"style":426},"# Передаем только a (позиционно) и d (как именованный)\nprint_params(3, d=3)\n",[428,8003,8004,8009],{"__ignoreMap":426},[431,8005,8006],{"class":433,"line":434},[431,8007,8008],{"class":455},"# Передаем только a (позиционно) и d (как именованный)\n",[431,8010,8011,8013,8015,8017,8019,8021,8023],{"class":433,"line":452},[431,8012,7952],{"class":441},[431,8014,971],{"class":437},[431,8016,4846],{"class":441},[431,8018,7989],{"class":7849},[431,8020,1189],{"class":654},[431,8022,971],{"class":437},[431,8024,449],{"class":441},[415,8026,8027],{},"Итак, мы ограничились только базовыми знаниями, которые помогут вам читать примеры кода с именованными аргументами.\nВ дальнейшем необходимо изучить эту тему подробнее.",[632,8029,8031],{"id":8030},"аннотации-типов","Аннотации типов",[415,8033,8034,8036],{},[800,8035,8031],{}," — это возможность указать типы параметров и возвращаемого значения у функции в Python.\nЭто не является обязательным требованием языка, но может помочь программистам в дальнейшей разработке, улучшить читаемость кода и повысить его надежность.",[415,8038,8039],{},"Давайте рассмотрим простой пример функции без аннотаций типов:",[422,8041,8043],{"className":424,"code":8042,"language":396,"meta":426,"style":426},"def concat(first, second):\n    return first + second\n",[428,8044,8045,8055],{"__ignoreMap":426},[431,8046,8047,8049,8052],{"class":433,"line":434},[431,8048,6330],{"class":654},[431,8050,8051],{"class":6333}," concat",[431,8053,8054],{"class":441},"(first, second):\n",[431,8056,8057,8059,8062,8064],{"class":433,"line":452},[431,8058,6599],{"class":654},[431,8060,8061],{"class":441}," first ",[431,8063,802],{"class":654},[431,8065,8066],{"class":441}," second\n",[415,8068,8069],{},"Эта функция конкатенирует две строки в одну.\nПри этом с первого взгляда на код сложно понять, что происходит в нем: какие типы у аргументов, почему функция работает со строками, а не складывает, например, два числа.\nЕсли в дальнейшем использовать эту функцию в коде, то может возникнуть необходимость проверять типы аргументов перед передачей их в функцию, что увеличивает объем кода и затрудняет его понимание.",[415,8071,8072],{},"Теперь давайте добавим аннотации типов к функции:",[422,8074,8076],{"className":424,"code":8075,"language":396,"meta":426,"style":426},"def concat(first: str, second: str) -> str:\n    return first + second\n",[428,8077,8078,8103],{"__ignoreMap":426},[431,8079,8080,8082,8084,8087,8090,8093,8095,8098,8100],{"class":433,"line":434},[431,8081,6330],{"class":654},[431,8083,8051],{"class":6333},[431,8085,8086],{"class":441},"(first: ",[431,8088,8089],{"class":437},"str",[431,8091,8092],{"class":441},", second: ",[431,8094,8089],{"class":437},[431,8096,8097],{"class":441},") -> ",[431,8099,8089],{"class":437},[431,8101,8102],{"class":441},":\n",[431,8104,8105,8107,8109,8111],{"class":433,"line":452},[431,8106,6599],{"class":654},[431,8108,8061],{"class":441},[431,8110,802],{"class":654},[431,8112,8066],{"class":441},[415,8114,8115],{},"Здесь указали, что аргументы first и second должны быть строкового типа (str).\nС помощью стрелки -> указали тип возвращаемого значения функции, оно также будет строковым (-> str).\nКогда мы будем использовать эту функцию в коде, нам будет проще понять, какие типы аргументов можно передавать и какой тип возвращаемого значения ожидается.\nАннотации типов также могут быть использованы для определения типов переменных внутри функции. Например:",[422,8117,8119],{"className":424,"code":8118,"language":396,"meta":426,"style":426},"def double(n: int) -> int:\n    result: int = n * 2\n    return result\n",[428,8120,8121,8139,8155],{"__ignoreMap":426},[431,8122,8123,8125,8128,8131,8133,8135,8137],{"class":433,"line":434},[431,8124,6330],{"class":654},[431,8126,8127],{"class":6333}," double",[431,8129,8130],{"class":441},"(n: ",[431,8132,2266],{"class":437},[431,8134,8097],{"class":441},[431,8136,2266],{"class":437},[431,8138,8102],{"class":441},[431,8140,8141,8144,8146,8148,8151,8153],{"class":433,"line":452},[431,8142,8143],{"class":441},"    result: ",[431,8145,2266],{"class":437},[431,8147,2146],{"class":654},[431,8149,8150],{"class":441}," n ",[431,8152,1357],{"class":654},[431,8154,658],{"class":437},[431,8156,8157,8159],{"class":433,"line":578},[431,8158,6599],{"class":654},[431,8160,6812],{"class":441},[415,8162,8163],{},"В этом примере мы определили тип переменной result как int, используя аннотацию типа.\nАннотации типов — это нестрогая проверка типов в Python.\nИх использование не гарантирует, что функция будет вызвана с аргументами и возвращаемым значением указанных типов.\nPython остаётся динамически типизированным языком.\nВ нем аннотации типов не влияют на возможность передачи аргументов различных типов и возвращения значений других типов.\nТем не менее их использование упрощает чтение и понимание кода и помогает отслеживать ошибки.",[632,8165,8167],{"id":8166},"окружение","Окружение",[415,8169,8170,8171,8174,8175,3228,8178,8181],{},"Поработаем с функцией ",[800,8172,8173],{},"generate()"," и переменными ",[800,8176,8177],{},"result",[800,8179,8180],{},"age",".\nТакже разберем, что такое локальная переменная и как она работает.\nВозьмем для примера следующий код:",[422,8183,8185],{"className":424,"code":8184,"language":396,"meta":426,"style":426},"age = 18\n\ndef generate():\n    return age + 3\n\nresult = generate()\n",[428,8186,8187,8197,8201,8210,8221,8225],{"__ignoreMap":426},[431,8188,8189,8192,8194],{"class":433,"line":434},[431,8190,8191],{"class":441},"age ",[431,8193,1189],{"class":654},[431,8195,8196],{"class":437}," 18\n",[431,8198,8199],{"class":433,"line":452},[431,8200,1662],{"emptyLinePlaceholder":393},[431,8202,8203,8205,8208],{"class":433,"line":578},[431,8204,6330],{"class":654},[431,8206,8207],{"class":6333}," generate",[431,8209,6337],{"class":441},[431,8211,8212,8214,8217,8219],{"class":433,"line":584},[431,8213,6599],{"class":654},[431,8215,8216],{"class":441}," age ",[431,8218,802],{"class":654},[431,8220,1197],{"class":437},[431,8222,8223],{"class":433,"line":1244},[431,8224,1662],{"emptyLinePlaceholder":393},[431,8226,8227,8229,8231],{"class":433,"line":1985},[431,8228,4799],{"class":441},[431,8230,1189],{"class":654},[431,8232,8233],{"class":441}," generate()\n",[415,8235,8236],{},"Когда код выполнится, внутри переменной result окажется значение 21.\nХоть переменная age — это не аргумент функции generate(), ее все равно видно в теле функции.\nТак происходит, потому что переменную age определили ранее вызова функции, а интерпретатор Python читает файл сверху вниз.\nЭто правило относится и к другим переменным.\nРассмотрим другой пример:",[422,8238,8240],{"className":424,"code":8239,"language":396,"meta":426,"style":426},"age = 18\n\ndef generate():\n    age = 20\n    return age + 3\n\nresult = generate()\n",[428,8241,8242,8250,8254,8262,8272,8282,8286],{"__ignoreMap":426},[431,8243,8244,8246,8248],{"class":433,"line":434},[431,8245,8191],{"class":441},[431,8247,1189],{"class":654},[431,8249,8196],{"class":437},[431,8251,8252],{"class":433,"line":452},[431,8253,1662],{"emptyLinePlaceholder":393},[431,8255,8256,8258,8260],{"class":433,"line":578},[431,8257,6330],{"class":654},[431,8259,8207],{"class":6333},[431,8261,6337],{"class":441},[431,8263,8264,8267,8269],{"class":433,"line":584},[431,8265,8266],{"class":441},"    age ",[431,8268,1189],{"class":654},[431,8270,8271],{"class":437}," 20\n",[431,8273,8274,8276,8278,8280],{"class":433,"line":1244},[431,8275,6599],{"class":654},[431,8277,8216],{"class":441},[431,8279,802],{"class":654},[431,8281,1197],{"class":437},[431,8283,8284],{"class":433,"line":1985},[431,8285,1662],{"emptyLinePlaceholder":393},[431,8287,8288,8290,8292],{"class":433,"line":2041},[431,8289,4799],{"class":441},[431,8291,1189],{"class":654},[431,8293,8233],{"class":441},[415,8295,8296],{},"В данном случае результатом будет число 23.\nВнешнее значение age = 18 не влияет на код функции, потому что в теле функции определили свою переменную age — локальную переменную.\nЕе не видно за пределами функции.\nИ последний пример:",[422,8298,8300],{"className":424,"code":8299,"language":396,"meta":426,"style":426},"age = 20\n\ndef generate():\n    age = 18\n\ngenerate()\nresult = age\n",[428,8301,8302,8310,8314,8322,8330,8334,8339],{"__ignoreMap":426},[431,8303,8304,8306,8308],{"class":433,"line":434},[431,8305,8191],{"class":441},[431,8307,1189],{"class":654},[431,8309,8271],{"class":437},[431,8311,8312],{"class":433,"line":452},[431,8313,1662],{"emptyLinePlaceholder":393},[431,8315,8316,8318,8320],{"class":433,"line":578},[431,8317,6330],{"class":654},[431,8319,8207],{"class":6333},[431,8321,6337],{"class":441},[431,8323,8324,8326,8328],{"class":433,"line":584},[431,8325,8266],{"class":441},[431,8327,1189],{"class":654},[431,8329,8196],{"class":437},[431,8331,8332],{"class":433,"line":1244},[431,8333,1662],{"emptyLinePlaceholder":393},[431,8335,8336],{"class":433,"line":1985},[431,8337,8338],{"class":441},"generate()\n",[431,8340,8341,8343,8345],{"class":433,"line":2041},[431,8342,4799],{"class":441},[431,8344,1189],{"class":654},[431,8346,8347],{"class":441}," age\n",[415,8349,8350],{},"Результат будет 20.\nЛокальная переменная, которую создали внутри функции generate(), не влияет на внешнюю переменную age.\nПоэтому, когда функцию вызвали, значение внешней age не изменилось и осталось 5.",[415,8352,1849,8353,1853,8355,1857],{},[800,8354,1852],{},[800,8356,1856],{},[1859,8358],{},[1862,8360,8361],{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}",{"title":426,"searchDepth":452,"depth":1244,"links":8363},[8364],{"id":6232,"depth":452,"text":318,"children":8365},[8366,8367,8368,8369,8372,8376,8377],{"id":6238,"depth":578,"text":6239},{"id":6423,"depth":578,"text":6424},{"id":6869,"depth":578,"text":6870},{"id":7346,"depth":578,"text":7347,"children":8370},[8371],{"id":7686,"depth":584,"text":7687},{"id":7780,"depth":578,"text":7781,"children":8373},[8374,8375],{"id":7787,"depth":584,"text":7788},{"id":7874,"depth":584,"text":7875},{"id":8030,"depth":578,"text":8031},{"id":8166,"depth":578,"text":8167},"2025-02-06","Создание функций. Параметры функций. Аннотации типов. Окружение","images\u002Fblog\u002Fpython\u002Fst7\u002Fimg.png",{},25,{"title":318,"description":8379},"donh8PvdtKUeudERZdminqaBhYpqxRkRE8GKc_e8kPs",{"id":8386,"title":322,"author":8387,"body":8389,"date":12478,"description":12479,"extension":1887,"image":12480,"meta":12481,"minRead":12482,"navigation":393,"num":4018,"path":323,"seo":12483,"stem":324,"__hash__":12484},"python\u002Fblog\u002Fpython\u002Fst8.md",{"name":402,"avatar":8388},{"src":404,"alt":405},{"type":407,"value":8390,"toc":12439},[8391,8394,8410,8413,8433,8436,8440,8443,8491,8498,8541,8544,8562,8565,8569,8572,8586,8589,8630,8634,8640,8648,8651,8662,8669,8680,8683,8744,8747,8758,8828,8831,8835,8838,8844,8847,8942,8964,8988,9078,9081,9246,9249,9255,9310,9316,9363,9370,9384,9409,9412,9473,9483,9507,9510,9578,9584,9588,9591,9595,9598,9620,9623,9664,9667,9690,9693,9715,9718,9750,9752,9767,9773,9776,9784,9787,9845,9848,9893,9897,9900,9908,9911,10018,10021,10142,10145,10167,10171,10174,10202,10205,10232,10237,10278,10282,10285,10308,10311,10334,10337,10351,10354,10386,10390,10393,10400,10403,10496,10509,10516,10519,10632,10647,10727,10730,10737,10740,10889,10892,10900,10903,11043,11049,11060,11065,11069,11072,11113,11116,11150,11164,11239,11242,11246,11249,11315,11318,11424,11427,11523,11526,11530,11533,11539,11544,11615,11618,11695,11698,11710,11717,11766,11770,11773,11778,11888,11893,11953,11956,11960,11963,12128,12133,12136,12274,12278,12281,12425,12428,12434,12436],[410,8392,322],{"id":8393},"логика",[415,8395,8396,8397,8399,8400,8403,8404,8399,8407,2699],{},"Кроме арифметических операций в математике есть операции сравнения, например, 6 > 2 или 5 \u003C 10. Они есть и в программировании.\nДопустим, когда мы заходим на сайт, введенные логин и пароль сравниваются с теми, какие есть в базе.\nЕсли они есть, нас пускают внутрь — аутентифицируют.\nЯзыки программирования адаптировали все математические операции сравнения в неизменном виде, кроме операторов равенства и неравенства.\nВ математике для этого используется обычное равно =, но в программировании такое встречается редко.\nВо многих языках символ ",[800,8398,1189],{}," ",[800,8401,8402],{},"используется, чтобы присвоить переменным значения",". Поэтому в Python ",[800,8405,8406],{},"сравнивают с помощью",[800,8408,8409],{},"==",[415,8411,8412],{},"Список операций сравнения:",[697,8414,8415,8418,8421,8424,8427,8430],{},[700,8416,8417],{},"\u003C — меньше",[700,8419,8420],{},"\u003C= — меньше или равно",[700,8422,8423],{},"> — больше",[700,8425,8426],{},">= — больше или равно",[700,8428,8429],{},"== — равно",[700,8431,8432],{},"!= — не равно",[415,8434,8435],{},"Эти операции применяются не только к числам.\nНапример, с помощью оператора равенства можно сравнить строки: password == text — это сравнение идентичности строк, которые записаны в разных переменных.",[458,8437,8439],{"id":8438},"логический-тип","Логический тип",[415,8441,8442],{},"Логическая операция типа 6 > 3 или password == text — это выражение.\nЕго результат — специальное значение True («истина») или False («ложь»). Это тип данных — bool.",[422,8444,8446],{"className":424,"code":8445,"language":396,"meta":426,"style":426},"result = 6 > 3\nprint(result)  # => True\nprint('two' != 'two')  # => False\n",[428,8447,8448,8462,8471],{"__ignoreMap":426},[431,8449,8450,8452,8454,8457,8460],{"class":433,"line":434},[431,8451,4799],{"class":441},[431,8453,1189],{"class":654},[431,8455,8456],{"class":437}," 6",[431,8458,8459],{"class":654}," >",[431,8461,1197],{"class":437},[431,8463,8464,8466,8468],{"class":433,"line":452},[431,8465,438],{"class":437},[431,8467,4817],{"class":441},[431,8469,8470],{"class":455},"# => True\n",[431,8472,8473,8475,8477,8480,8483,8486,8488],{"class":433,"line":578},[431,8474,438],{"class":437},[431,8476,442],{"class":441},[431,8478,8479],{"class":445},"'two'",[431,8481,8482],{"class":654}," !=",[431,8484,8485],{"class":445}," 'two'",[431,8487,526],{"class":441},[431,8489,8490],{"class":455},"# => False\n",[415,8492,8493,8494,8497],{},"Наряду со строками (str) и целыми и рациональными числами, тип ",[800,8495,8496],{},"bool"," (булев) — это один из примитивных типов данных в Python.\nПопробуем написать простую функцию, которая принимает на вход возраст ребенка и определяет, младенец ли он. Младенцами считаются дети до года:",[422,8499,8501],{"className":424,"code":8500,"language":396,"meta":426,"style":426},"def is_infant(age):\n    return age \u003C 1\n\nprint(is_infant(3))  # => False\n",[428,8502,8503,8513,8524,8528],{"__ignoreMap":426},[431,8504,8505,8507,8510],{"class":433,"line":434},[431,8506,6330],{"class":654},[431,8508,8509],{"class":6333}," is_infant",[431,8511,8512],{"class":441},"(age):\n",[431,8514,8515,8517,8519,8522],{"class":433,"line":452},[431,8516,6599],{"class":654},[431,8518,8216],{"class":441},[431,8520,8521],{"class":654},"\u003C",[431,8523,3916],{"class":437},[431,8525,8526],{"class":433,"line":578},[431,8527,1662],{"emptyLinePlaceholder":393},[431,8529,8530,8532,8535,8537,8539],{"class":433,"line":584},[431,8531,438],{"class":437},[431,8533,8534],{"class":441},"(is_infant(",[431,8536,971],{"class":437},[431,8538,986],{"class":441},[431,8540,8490],{"class":455},[415,8542,8543],{},"Любая операция — это выражение, поэтому единственной строчкой функции пишем: «Вернуть то значение, которое получится в результате сравнения age \u003C 1».\nВ зависимости от того, какой аргумент пришел, сравнение будет истинным (True) или ложным (False), а return вернет этот результат.\nА теперь проверим ребенка, которому полгода(напишем вызов той же функции только с другим значением):",[422,8545,8547],{"className":424,"code":8546,"language":396,"meta":426,"style":426},"print(is_infant(0.5))  # => True\n",[428,8548,8549],{"__ignoreMap":426},[431,8550,8551,8553,8555,8558,8560],{"class":433,"line":434},[431,8552,438],{"class":437},[431,8554,8534],{"class":441},[431,8556,8557],{"class":437},"0.5",[431,8559,986],{"class":441},[431,8561,8470],{"class":455},[415,8563,8564],{},"Результат операции — True. Значит, ребенок в возрасте пол года — действительно младенец.",[458,8566,8568],{"id":8567},"предикаты","Предикаты",[415,8570,8571],{},"Функция is_infant() — это функция-предикат или функция-вопрос. Предикат отвечает на вопрос «да» или «нет», возвращая значение типа bool.\nПредикаты во всех языках принято именовать особым образом для простоты анализа. В Python предикаты начинаются с префикса is или has, например:",[697,8573,8574,8577,8580,8583],{},[700,8575,8576],{},"is_infant() — «младенец ли?»",[700,8578,8579],{},"has_children() — «есть ли дети?»",[700,8581,8582],{},"is_empty() — «пустой ли?»",[700,8584,8585],{},"has_errors() — «есть ли ошибки?»",[415,8587,8588],{},"Функция считается предикатом, если она возвращает булевы значения True или False.\nНапишем еще одну функцию-предикат. Она принимает строку и проверяет, является ли она словом 'Python':",[422,8590,8592],{"className":424,"code":8591,"language":396,"meta":426,"style":426},"def is_python(string):\n    return string.is_capitalize() == 'Python'\n\nprint(is_python('C#'))\n",[428,8593,8594,8603,8614,8618],{"__ignoreMap":426},[431,8595,8596,8598,8601],{"class":433,"line":434},[431,8597,6330],{"class":654},[431,8599,8600],{"class":6333}," is_python",[431,8602,7080],{"class":441},[431,8604,8605,8607,8610,8612],{"class":433,"line":452},[431,8606,6599],{"class":654},[431,8608,8609],{"class":441}," string.is_capitalize() ",[431,8611,8409],{"class":654},[431,8613,3648],{"class":445},[431,8615,8616],{"class":433,"line":578},[431,8617,1662],{"emptyLinePlaceholder":393},[431,8619,8620,8622,8625,8628],{"class":433,"line":584},[431,8621,438],{"class":437},[431,8623,8624],{"class":441},"(is_python(",[431,8626,8627],{"class":445},"'C#'",[431,8629,6157],{"class":441},[458,8631,8633],{"id":8632},"комбинирование-операций-и-функций","Комбинирование операций и функций",[415,8635,8636,8639],{},[1355,8637,8638],{},"Логические операции"," — это выражения, значит, их можно комбинировать с другими выражениями.\nНапример, мы хотим проверить четность числа — кратность двум.\nВ программировании используют такой подход — проверяют остаток от деления на два:",[697,8641,8642,8645],{},[700,8643,8644],{},"если остаток 0 — число четное",[700,8646,8647],{},"если остаток не 0 — число нечетное",[415,8649,8650],{},"Остаток от деления — простая, но важная концепция в арифметике, алгебре, в теории чисел и криптографии.\nНужно разделить число на несколько равных групп, и если в конце что-то останется — это остаток от деления.\nДелим конфеты поровну между людьми:",[697,8652,8653,8656,8659],{},[700,8654,8655],{},"7 конфет, 2 человека: 2 x 3 + остаток 1 — 7 не кратно 2",[700,8657,8658],{},"21 конфету, 3 человека: 3 x 7 + остаток 0 — 21 кратно 3",[700,8660,8661],{},"19 конфет, 5 человек: 5 x 3 + остаток 4 — 19 не кратно 5",[415,8663,8664,8665,8668],{},"Оператор ",[800,8666,8667],{},"%"," вычисляет остаток от деления:",[697,8670,8671,8674,8677],{},[700,8672,8673],{},"7 % 2 → 1",[700,8675,8676],{},"21 % 3 → 0",[700,8678,8679],{},"19 % 5 → 4",[415,8681,8682],{},"Скомбинируем в одном выражении логический оператор «проверка равенства» == и арифметический оператор % и напишем функцию проверки четности:",[422,8684,8686],{"className":424,"code":8685,"language":396,"meta":426,"style":426},"def is_even(number):\n    return number % 2 == 0\n\nprint(is_even(8))  # => True\nprint(is_even(5))   # => False\n",[428,8687,8688,8698,8714,8718,8731],{"__ignoreMap":426},[431,8689,8690,8692,8695],{"class":433,"line":434},[431,8691,6330],{"class":654},[431,8693,8694],{"class":6333}," is_even",[431,8696,8697],{"class":441},"(number):\n",[431,8699,8700,8702,8705,8707,8709,8712],{"class":433,"line":452},[431,8701,6599],{"class":654},[431,8703,8704],{"class":441}," number ",[431,8706,8667],{"class":654},[431,8708,689],{"class":437},[431,8710,8711],{"class":654}," ==",[431,8713,3459],{"class":437},[431,8715,8716],{"class":433,"line":578},[431,8717,1662],{"emptyLinePlaceholder":393},[431,8719,8720,8722,8725,8727,8729],{"class":433,"line":584},[431,8721,438],{"class":437},[431,8723,8724],{"class":441},"(is_even(",[431,8726,1021],{"class":437},[431,8728,986],{"class":441},[431,8730,8470],{"class":455},[431,8732,8733,8735,8737,8739,8742],{"class":433,"line":1244},[431,8734,438],{"class":437},[431,8736,8724],{"class":441},[431,8738,856],{"class":437},[431,8740,8741],{"class":441},"))   ",[431,8743,8490],{"class":455},[415,8745,8746],{},"Приоритет арифметических операций выше логических.\nЗначит, сначала вычисляется арифметическое выражение number % 2, а затем результат сравнивается с нулем и возвращается результат проверки равенства.\nТеперь напишем функцию, которая принимает строку и проверяет, начинается ли эта строка с латинской буквы A.\nАлгоритм:",[697,8748,8749,8752,8755],{},[700,8750,8751],{},"Получить и записать в переменную первый символ из строки-аргумента;",[700,8753,8754],{},"Сравнить, равен ли символ латинской букве A;",[700,8756,8757],{},"Вернуть результат.",[422,8759,8761],{"className":424,"code":8760,"language":396,"meta":426,"style":426},"def is_first_letter_an_a(string):\n    first_letter = string[0]\n    return first_letter == 'A'\n\nprint(is_first_letter_an_a('Orange'))  # => False\nprint(is_first_letter_an_a('Apple'))   # => True- \n",[428,8762,8763,8772,8785,8796,8800,8814],{"__ignoreMap":426},[431,8764,8765,8767,8770],{"class":433,"line":434},[431,8766,6330],{"class":654},[431,8768,8769],{"class":6333}," is_first_letter_an_a",[431,8771,7080],{"class":441},[431,8773,8774,8777,8779,8781,8783],{"class":433,"line":452},[431,8775,8776],{"class":441},"    first_letter ",[431,8778,1189],{"class":654},[431,8780,7087],{"class":441},[431,8782,3302],{"class":437},[431,8784,3568],{"class":441},[431,8786,8787,8789,8792,8794],{"class":433,"line":578},[431,8788,6599],{"class":654},[431,8790,8791],{"class":441}," first_letter ",[431,8793,8409],{"class":654},[431,8795,3198],{"class":445},[431,8797,8798],{"class":433,"line":584},[431,8799,1662],{"emptyLinePlaceholder":393},[431,8801,8802,8804,8807,8810,8812],{"class":433,"line":1244},[431,8803,438],{"class":437},[431,8805,8806],{"class":441},"(is_first_letter_an_a(",[431,8808,8809],{"class":445},"'Orange'",[431,8811,986],{"class":441},[431,8813,8490],{"class":455},[431,8815,8816,8818,8820,8823,8825],{"class":433,"line":1985},[431,8817,438],{"class":437},[431,8819,8806],{"class":441},[431,8821,8822],{"class":445},"'Apple'",[431,8824,8741],{"class":441},[431,8826,8827],{"class":455},"# => True-\n",[415,8829,8830],{},"Чтобы было понятно, что тут происходит, попробуйте проговорить происходящее аналогично тому, как мы расшифровывали процесс в примере с is_even().\nТеперь вы знаете, что операции сравнения применяются в программировании наравне с арифметическими.\nНо помните, что равенство обозначается ==.",[632,8832,8834],{"id":8833},"логические-операторы","Логические операторы",[415,8836,8837],{},"Логические операторы нужны, чтобы составлять сложные логические условия.\nПредположим, что сайт при регистрации требует, чтобы пароль был длиннее восьми символов и короче двадцати.\nВ математике бы написали 8 \u003C x \u003C 20, но во многих языках программирования так сделать нельзя.\nПопробуем написать два отдельных логических выражения и соединим их специальным оператором «И»:",[8839,8840,8841],"blockquote",{},[415,8842,8843],{},"Пароль длиннее 8 символов И пароль короче 20 символов",[415,8845,8846],{},"Напишем функцию, которая принимает пароль и говорит, соответствует ли он условиям (True) или не соответствует (False):",[422,8848,8850],{"className":424,"code":8849,"language":396,"meta":426,"style":426},"def is_correct_password(password):\n    length = len(password)\n    return length > 8 and length \u003C 20\n\nprint(is_correct_password('qwerty'))                   # => False\nprint(is_correct_password('qwerty1234'))               # => True\nprint(is_correct_password('zxcvbnmasdfghjkqwertyui'))  # => False\n",[428,8851,8852,8862,8874,8896,8900,8915,8929],{"__ignoreMap":426},[431,8853,8854,8856,8859],{"class":433,"line":434},[431,8855,6330],{"class":654},[431,8857,8858],{"class":6333}," is_correct_password",[431,8860,8861],{"class":441},"(password):\n",[431,8863,8864,8867,8869,8871],{"class":433,"line":452},[431,8865,8866],{"class":441},"    length ",[431,8868,1189],{"class":654},[431,8870,4804],{"class":437},[431,8872,8873],{"class":441},"(password)\n",[431,8875,8876,8878,8881,8884,8887,8890,8892,8894],{"class":433,"line":578},[431,8877,6599],{"class":654},[431,8879,8880],{"class":441}," length ",[431,8882,8883],{"class":654},">",[431,8885,8886],{"class":437}," 8",[431,8888,8889],{"class":654}," and",[431,8891,8880],{"class":441},[431,8893,8521],{"class":654},[431,8895,8271],{"class":437},[431,8897,8898],{"class":433,"line":584},[431,8899,1662],{"emptyLinePlaceholder":393},[431,8901,8902,8904,8907,8910,8913],{"class":433,"line":1244},[431,8903,438],{"class":437},[431,8905,8906],{"class":441},"(is_correct_password(",[431,8908,8909],{"class":445},"'qwerty'",[431,8911,8912],{"class":441},"))                   ",[431,8914,8490],{"class":455},[431,8916,8917,8919,8921,8924,8927],{"class":433,"line":1985},[431,8918,438],{"class":437},[431,8920,8906],{"class":441},[431,8922,8923],{"class":445},"'qwerty1234'",[431,8925,8926],{"class":441},"))               ",[431,8928,8470],{"class":455},[431,8930,8931,8933,8935,8938,8940],{"class":433,"line":2041},[431,8932,438],{"class":437},[431,8934,8906],{"class":441},[431,8936,8937],{"class":445},"'zxcvbnmasdfghjkqwertyui'",[431,8939,986],{"class":441},[431,8941,8490],{"class":455},[415,8943,8944,8947,8948,8951,8952,8955,8956,8959,8960,8963],{},[800,8945,8946],{},"and"," — означает «",[800,8949,8950],{},"И","». В математической логике это называют ",[1355,8953,8954],{},"конъюнкцией",".\nВсе выражение считается истинным, если истинен каждый операнд — каждое из составных выражений.\nИными словами, and означает «и то, и другое». ",[1355,8957,8958],{},"Приоритет этого оператора ниже, чем приоритет операторов сравнения",".\nПоэтому выражение ",[428,8961,8962],{},"length > 8 and length \u003C 20"," правильно отрабатывает без скобок.",[415,8965,8966,8967,8970,8971,8974,8975,8978,8979,8982,8983,3228,8985,8987],{},"Кроме and часто используется оператор ",[800,8968,8969],{},"or"," — «",[800,8972,8973],{},"ИЛИ","» (",[1355,8976,8977],{},"дизъюнкция",").\nОн означает «или то, или другое, или оба». Выражение ",[428,8980,8981],{},"a or b"," считается истинным, если хотя бы один из операндов или одновременно все — истинные.\nВ другом случае выражение ложное. Операторы можно комбинировать в любом количестве и любой последовательности.\nЕсли в коде одновременно встречаются ",[428,8984,8946],{},[428,8986,8969],{},", то приоритет задают скобками.\nНиже пример расширенной функции, которая определяет корректность пароля:",[422,8989,8991],{"className":424,"code":8990,"language":396,"meta":426,"style":426},"import string\n\ndef has_special_chars(string):\n    # Проверяет, есть ли специальные символы в строке\n    # ...\n\ndef is_strong_password(password):\n    length = len(password)\n    # Скобки задают приоритет. Понятно, что к чему относится.\n    return (length > 8 and length \u003C 20) and has_special_chars(password)\n",[428,8992,8993,9000,9004,9013,9018,9023,9027,9036,9046,9051],{"__ignoreMap":426},[431,8994,8995,8997],{"class":433,"line":434},[431,8996,5379],{"class":654},[431,8998,8999],{"class":441}," string\n",[431,9001,9002],{"class":433,"line":452},[431,9003,1662],{"emptyLinePlaceholder":393},[431,9005,9006,9008,9011],{"class":433,"line":578},[431,9007,6330],{"class":654},[431,9009,9010],{"class":6333}," has_special_chars",[431,9012,7080],{"class":441},[431,9014,9015],{"class":433,"line":584},[431,9016,9017],{"class":455},"    # Проверяет, есть ли специальные символы в строке\n",[431,9019,9020],{"class":433,"line":1244},[431,9021,9022],{"class":455},"    # ...\n",[431,9024,9025],{"class":433,"line":1985},[431,9026,1662],{"emptyLinePlaceholder":393},[431,9028,9029,9031,9034],{"class":433,"line":2041},[431,9030,6330],{"class":654},[431,9032,9033],{"class":6333}," is_strong_password",[431,9035,8861],{"class":441},[431,9037,9038,9040,9042,9044],{"class":433,"line":4018},[431,9039,8866],{"class":441},[431,9041,1189],{"class":654},[431,9043,4804],{"class":437},[431,9045,8873],{"class":441},[431,9047,9048],{"class":433,"line":4030},[431,9049,9050],{"class":455},"    # Скобки задают приоритет. Понятно, что к чему относится.\n",[431,9052,9053,9055,9058,9060,9062,9064,9066,9068,9071,9073,9075],{"class":433,"line":4419},[431,9054,6599],{"class":654},[431,9056,9057],{"class":441}," (length ",[431,9059,8883],{"class":654},[431,9061,8886],{"class":437},[431,9063,8889],{"class":654},[431,9065,8880],{"class":441},[431,9067,8521],{"class":654},[431,9069,9070],{"class":437}," 20",[431,9072,1014],{"class":441},[431,9074,8946],{"class":654},[431,9076,9077],{"class":441}," has_special_chars(password)\n",[415,9079,9080],{},"Теперь представим, что мы хотим купить квартиру, которая удовлетворяет таким условиям: площадь от 100 квадратных метров\nи больше на любой улице ИЛИ площадь от 80 квадратных метров и больше, но на центральной улице Main Street.\nНапишем функцию, которая проверит квартиру. Она принимает два аргумента: площадь — число и название улицы — строку:",[422,9082,9084],{"className":424,"code":9083,"language":396,"meta":426,"style":426},"def is_good_apartment(area, street):\n    return area >= 100 or (area >= 80 and street == 'Main Street')\n\nprint(is_good_apartment(91, 'Queens Street'))  # => False\nprint(is_good_apartment(78, 'Queens Street'))  # => False\nprint(is_good_apartment(70, 'Main Street'))    # => False\n\nprint(is_good_apartment(120, 'Queens Street'))  # => True\nprint(is_good_apartment(120, 'Main Street'))    # => True\nprint(is_good_apartment(80, 'Main Street'))     # => True\n",[428,9085,9086,9096,9132,9136,9155,9172,9191,9195,9212,9228],{"__ignoreMap":426},[431,9087,9088,9090,9093],{"class":433,"line":434},[431,9089,6330],{"class":654},[431,9091,9092],{"class":6333}," is_good_apartment",[431,9094,9095],{"class":441},"(area, street):\n",[431,9097,9098,9100,9103,9106,9109,9112,9115,9117,9120,9122,9125,9127,9130],{"class":433,"line":452},[431,9099,6599],{"class":654},[431,9101,9102],{"class":441}," area ",[431,9104,9105],{"class":654},">=",[431,9107,9108],{"class":437}," 100",[431,9110,9111],{"class":654}," or",[431,9113,9114],{"class":441}," (area ",[431,9116,9105],{"class":654},[431,9118,9119],{"class":437}," 80",[431,9121,8889],{"class":654},[431,9123,9124],{"class":441}," street ",[431,9126,8409],{"class":654},[431,9128,9129],{"class":445}," 'Main Street'",[431,9131,449],{"class":441},[431,9133,9134],{"class":433,"line":578},[431,9135,1662],{"emptyLinePlaceholder":393},[431,9137,9138,9140,9143,9146,9148,9151,9153],{"class":433,"line":584},[431,9139,438],{"class":437},[431,9141,9142],{"class":441},"(is_good_apartment(",[431,9144,9145],{"class":437},"91",[431,9147,4846],{"class":441},[431,9149,9150],{"class":445},"'Queens Street'",[431,9152,986],{"class":441},[431,9154,8490],{"class":455},[431,9156,9157,9159,9161,9164,9166,9168,9170],{"class":433,"line":1244},[431,9158,438],{"class":437},[431,9160,9142],{"class":441},[431,9162,9163],{"class":437},"78",[431,9165,4846],{"class":441},[431,9167,9150],{"class":445},[431,9169,986],{"class":441},[431,9171,8490],{"class":455},[431,9173,9174,9176,9178,9181,9183,9186,9189],{"class":433,"line":1985},[431,9175,438],{"class":437},[431,9177,9142],{"class":441},[431,9179,9180],{"class":437},"70",[431,9182,4846],{"class":441},[431,9184,9185],{"class":445},"'Main Street'",[431,9187,9188],{"class":441},"))    ",[431,9190,8490],{"class":455},[431,9192,9193],{"class":433,"line":2041},[431,9194,1662],{"emptyLinePlaceholder":393},[431,9196,9197,9199,9201,9204,9206,9208,9210],{"class":433,"line":4018},[431,9198,438],{"class":437},[431,9200,9142],{"class":441},[431,9202,9203],{"class":437},"120",[431,9205,4846],{"class":441},[431,9207,9150],{"class":445},[431,9209,986],{"class":441},[431,9211,8470],{"class":455},[431,9213,9214,9216,9218,9220,9222,9224,9226],{"class":433,"line":4030},[431,9215,438],{"class":437},[431,9217,9142],{"class":441},[431,9219,9203],{"class":437},[431,9221,4846],{"class":441},[431,9223,9185],{"class":445},[431,9225,9188],{"class":441},[431,9227,8470],{"class":455},[431,9229,9230,9232,9234,9237,9239,9241,9244],{"class":433,"line":4419},[431,9231,438],{"class":437},[431,9233,9142],{"class":441},[431,9235,9236],{"class":437},"80",[431,9238,4846],{"class":441},[431,9240,9185],{"class":445},[431,9242,9243],{"class":441},"))     ",[431,9245,8470],{"class":455},[415,9247,9248],{},"Раздел математики, в котором изучаются логические операторы, называется булевой алгеброй.\nНиже увидите таблицы истинности — по ним можно определить, каким будет результат, если применить оператор.",[458,9250,9252,9253],{"id":9251},"и-and","И ",[428,9254,8946],{},[9256,9257,9258,9274],"table",{},[9259,9260,9261],"thead",{},[9262,9263,9264,9268,9271],"tr",{},[9265,9266,9267],"th",{},"A",[9265,9269,9270],{},"B",[9265,9272,9273],{},"A and B",[9275,9276,9277,9286,9294,9302],"tbody",{},[9262,9278,9279,9282,9284],{},[9280,9281,4463],"td",{},[9280,9283,4463],{},[9280,9285,4463],{},[9262,9287,9288,9290,9292],{},[9280,9289,4463],{},[9280,9291,4431],{},[9280,9293,4431],{},[9262,9295,9296,9298,9300],{},[9280,9297,4431],{},[9280,9299,4463],{},[9280,9301,4431],{},[9262,9303,9304,9306,9308],{},[9280,9305,4431],{},[9280,9307,4431],{},[9280,9309,4431],{},[458,9311,9313,9314],{"id":9312},"или-or","ИЛИ ",[428,9315,8969],{},[9256,9317,9318,9329],{},[9259,9319,9320],{},[9262,9321,9322,9324,9326],{},[9265,9323,9267],{},[9265,9325,9270],{},[9265,9327,9328],{},"A or B",[9275,9330,9331,9339,9347,9355],{},[9262,9332,9333,9335,9337],{},[9280,9334,4463],{},[9280,9336,4463],{},[9280,9338,4463],{},[9262,9340,9341,9343,9345],{},[9280,9342,4463],{},[9280,9344,4431],{},[9280,9346,4463],{},[9262,9348,9349,9351,9353],{},[9280,9350,4431],{},[9280,9352,4463],{},[9280,9354,4463],{},[9262,9356,9357,9359,9361],{},[9280,9358,4431],{},[9280,9360,4431],{},[9280,9362,4431],{},[458,9364,9366,9367],{"id":9365},"отрицание-not","Отрицание ",[428,9368,9369],{},"not",[415,9371,9372,9373,9376,9377,9379,9380,9383],{},"Наряду с логическими операторами И и ИЛИ, часто используется операция «",[1355,9374,9375],{},"инверсия","».\nОна меняет логическое значение на противоположное.\nВ программировании отрицанию соответствует унарный оператор ",[428,9378,9369],{}," или ",[428,9381,9382],{},"!"," знак:",[422,9385,9387],{"className":424,"code":9386,"language":396,"meta":426,"style":426},"not True   # False\nnot False  # True\n",[428,9388,9389,9399],{"__ignoreMap":426},[431,9390,9391,9393,9396],{"class":433,"line":434},[431,9392,9369],{"class":654},[431,9394,9395],{"class":437}," True",[431,9397,9398],{"class":455},"   # False\n",[431,9400,9401,9403,9406],{"class":433,"line":452},[431,9402,9369],{"class":654},[431,9404,9405],{"class":437}," False",[431,9407,9408],{"class":455},"  # True\n",[415,9410,9411],{},"Например, если есть функция, которая проверяет четность числа, то с помощью её отрицания можно выполнить проверку нечетности:",[422,9413,9415],{"className":424,"code":9414,"language":396,"meta":426,"style":426},"def is_even(number):\n    return number % 2 == 0\n\nprint(is_even(10))      # => True\nprint(not is_even(10))  # => False\n",[428,9416,9417,9425,9439,9443,9456],{"__ignoreMap":426},[431,9418,9419,9421,9423],{"class":433,"line":434},[431,9420,6330],{"class":654},[431,9422,8694],{"class":6333},[431,9424,8697],{"class":441},[431,9426,9427,9429,9431,9433,9435,9437],{"class":433,"line":452},[431,9428,6599],{"class":654},[431,9430,8704],{"class":441},[431,9432,8667],{"class":654},[431,9434,689],{"class":437},[431,9436,8711],{"class":654},[431,9438,3459],{"class":437},[431,9440,9441],{"class":433,"line":578},[431,9442,1662],{"emptyLinePlaceholder":393},[431,9444,9445,9447,9449,9451,9454],{"class":433,"line":584},[431,9446,438],{"class":437},[431,9448,8724],{"class":441},[431,9450,3565],{"class":437},[431,9452,9453],{"class":441},"))      ",[431,9455,8470],{"class":455},[431,9457,9458,9460,9462,9464,9467,9469,9471],{"class":433,"line":1244},[431,9459,438],{"class":437},[431,9461,442],{"class":441},[431,9463,9369],{"class":654},[431,9465,9466],{"class":441}," is_even(",[431,9468,3565],{"class":437},[431,9470,986],{"class":441},[431,9472,8490],{"class":455},[415,9474,9475,9476,9478,9479,9482],{},"В примере выше мы добавили ",[428,9477,9369],{}," слева от вызова функции и получили обратное действие.\nОтрицание — инструмент, с помощью которого можно выражать задуманные правила в коде и не писать новые функции.\nЕсли написать ",[428,9480,9481],{},"not not is_even(10)",", то код сработает даже в таком случае:",[422,9484,9486],{"className":424,"code":9485,"language":396,"meta":426,"style":426},"print(not not is_even(10))  # => True\n",[428,9487,9488],{"__ignoreMap":426},[431,9489,9490,9492,9494,9496,9499,9501,9503,9505],{"class":433,"line":434},[431,9491,438],{"class":437},[431,9493,442],{"class":441},[431,9495,9369],{"class":654},[431,9497,9498],{"class":654}," not",[431,9500,9466],{"class":441},[431,9502,3565],{"class":437},[431,9504,986],{"class":441},[431,9506,8470],{"class":455},[415,9508,9509],{},"В логике двойное отрицание — это отсутствие отрицания:",[422,9511,9513],{"className":424,"code":9512,"language":396,"meta":426,"style":426},"not not True   # True\nnot not False  # False\n\nprint(not not is_even(10))  # => True\nprint(not not is_even(11))  # => False\n",[428,9514,9515,9526,9537,9541,9559],{"__ignoreMap":426},[431,9516,9517,9519,9521,9523],{"class":433,"line":434},[431,9518,9369],{"class":654},[431,9520,9498],{"class":654},[431,9522,9395],{"class":437},[431,9524,9525],{"class":455},"   # True\n",[431,9527,9528,9530,9532,9534],{"class":433,"line":452},[431,9529,9369],{"class":654},[431,9531,9498],{"class":654},[431,9533,9405],{"class":437},[431,9535,9536],{"class":455},"  # False\n",[431,9538,9539],{"class":433,"line":578},[431,9540,1662],{"emptyLinePlaceholder":393},[431,9542,9543,9545,9547,9549,9551,9553,9555,9557],{"class":433,"line":584},[431,9544,438],{"class":437},[431,9546,442],{"class":441},[431,9548,9369],{"class":654},[431,9550,9498],{"class":654},[431,9552,9466],{"class":441},[431,9554,3565],{"class":437},[431,9556,986],{"class":441},[431,9558,8470],{"class":455},[431,9560,9561,9563,9565,9567,9569,9571,9574,9576],{"class":433,"line":1244},[431,9562,438],{"class":437},[431,9564,442],{"class":441},[431,9566,9369],{"class":654},[431,9568,9498],{"class":654},[431,9570,9466],{"class":441},[431,9572,9573],{"class":437},"11",[431,9575,986],{"class":441},[431,9577,8490],{"class":455},[415,9579,9580,9581],{},"Итак, с помощью логических операторов можно задавать составные условия из двух и более логических выражений.\nБолее, подробнее по алгебру логики можно почитать по ссылкам: ",[1205,9582,9583],{"href":380},"Законы алгебры логики",[632,9585,9587],{"id":9586},"результаты-логических-операций","Результаты логических операций",[415,9589,9590],{},"Посмотрим на правила преобразования и составные выражения с двойным отрицанием.",[458,9592,9594],{"id":9593},"правила-преобразования","Правила преобразования",[415,9596,9597],{},"Посмотрите на пример:",[422,9599,9601],{"className":424,"code":9600,"language":396,"meta":426,"style":426},"print(0 or 1)  ## 1\n",[428,9602,9603],{"__ignoreMap":426},[431,9604,9605,9607,9609,9611,9613,9615,9617],{"class":433,"line":434},[431,9606,438],{"class":437},[431,9608,442],{"class":441},[431,9610,3302],{"class":437},[431,9612,9111],{"class":654},[431,9614,1032],{"class":437},[431,9616,526],{"class":441},[431,9618,9619],{"class":455},"## 1\n",[415,9621,9622],{},"В данном случае число 0 эквивалентно False, а число 1 эквивалентно True.\nТаким образом, оператор ИЛИ вернет 1, так как это первый аргумент, который может быть преобразован в True.\nВозьмем пример посложнее:",[422,9624,9626],{"className":424,"code":9625,"language":396,"meta":426,"style":426},"print(0 or False or '' or [] or 42 or \"Hello\")  ## 42\n",[428,9627,9628],{"__ignoreMap":426},[431,9629,9630,9632,9634,9636,9638,9640,9642,9645,9647,9650,9652,9654,9656,9659,9661],{"class":433,"line":434},[431,9631,438],{"class":437},[431,9633,442],{"class":441},[431,9635,3302],{"class":437},[431,9637,9111],{"class":654},[431,9639,9405],{"class":437},[431,9641,9111],{"class":654},[431,9643,9644],{"class":445}," ''",[431,9646,9111],{"class":654},[431,9648,9649],{"class":441}," [] ",[431,9651,8969],{"class":654},[431,9653,2320],{"class":437},[431,9655,9111],{"class":654},[431,9657,9658],{"class":445}," \"Hello\"",[431,9660,526],{"class":441},[431,9662,9663],{"class":455},"## 42\n",[415,9665,9666],{},"В данном случае:",[697,9668,9669,9672,9675,9678,9684,9687],{},[700,9670,9671],{},"Число 0 эквивалентно False",[700,9673,9674],{},"Значение False уже является False",[700,9676,9677],{},"Пустая строка ('') эквивалентна False",[700,9679,9680,9681,9683],{},"Пустой список ",[431,9682],{}," эквивалентен False",[700,9685,9686],{},"Число 42 эквивалентно True",[700,9688,9689],{},"Строка \"Hello\" также эквивалентна True",[415,9691,9692],{},"Оператор ИЛИ проверяет значения слева направо, и возвращает первый аргумент, который может быть преобразован в True.\nВ данном примере это число 42. Если ни одно значение не подходит, то вернется последнее значение в цепочке проверок.\nПример с оператором И:",[422,9694,9696],{"className":424,"code":9695,"language":396,"meta":426,"style":426},"print(0 and 1)  ## 0\n",[428,9697,9698],{"__ignoreMap":426},[431,9699,9700,9702,9704,9706,9708,9710,9712],{"class":433,"line":434},[431,9701,438],{"class":437},[431,9703,442],{"class":441},[431,9705,3302],{"class":437},[431,9707,8889],{"class":654},[431,9709,1032],{"class":437},[431,9711,526],{"class":441},[431,9713,9714],{"class":455},"## 0\n",[415,9716,9717],{},"Оператор И работает так, что его выполнение слева направо прерывается и возвращается результат первого аргумента, который можно преобразовать в False.\nЕсли такого аргумента нет, возвращается последний — правый.",[422,9719,9721],{"className":424,"code":9720,"language":396,"meta":426,"style":426},"print(42 and \"Hello\" and [] and 0)  ## []\n",[428,9722,9723],{"__ignoreMap":426},[431,9724,9725,9727,9729,9732,9734,9736,9738,9740,9742,9745,9747],{"class":433,"line":434},[431,9726,438],{"class":437},[431,9728,442],{"class":441},[431,9730,9731],{"class":437},"42",[431,9733,8889],{"class":654},[431,9735,9658],{"class":445},[431,9737,8889],{"class":654},[431,9739,9649],{"class":441},[431,9741,8946],{"class":654},[431,9743,9744],{"class":437}," 0",[431,9746,526],{"class":441},[431,9748,9749],{"class":455},"## []\n",[415,9751,9666],{},[697,9753,9754,9756,9759,9765],{},[700,9755,9686],{},[700,9757,9758],{},"Строка \"Hello\" эквивалентна True",[700,9760,9761,9762,9764],{},"Пустой список (",[431,9763],{},") эквивалентен False",[700,9766,9671],{},[415,9768,9769,9770,9772],{},"Оператор И будет проверять значения слева направо и возвращать первый аргумент, который может быть преобразован в False.\nВ данном примере это пустой список (",[431,9771],{},").",[415,9774,9775],{},"В Python есть два правила преобразования:",[697,9777,9778,9781],{},[700,9779,9780],{},"0, 0.0, '' и None приводятся к False. Эти значения называют falsy.",[700,9782,9783],{},"Все остальное приводится к True",[415,9785,9786],{},"Этими правилами пользуются в разработке, например, чтобы определить значение по умолчанию:",[422,9788,9790],{"className":424,"code":9789,"language":396,"meta":426,"style":426},"value = name or ''\n# Примеры\n234 or '' # 234\n'python' or '' # 'python'\nNone or '' # ''\n",[428,9791,9792,9806,9811,9823,9834],{"__ignoreMap":426},[431,9793,9794,9796,9798,9801,9803],{"class":433,"line":434},[431,9795,3643],{"class":441},[431,9797,1189],{"class":654},[431,9799,9800],{"class":441}," name ",[431,9802,8969],{"class":654},[431,9804,9805],{"class":445}," ''\n",[431,9807,9808],{"class":433,"line":452},[431,9809,9810],{"class":455},"# Примеры\n",[431,9812,9813,9816,9818,9820],{"class":433,"line":578},[431,9814,9815],{"class":437},"234",[431,9817,9111],{"class":654},[431,9819,9644],{"class":445},[431,9821,9822],{"class":455}," # 234\n",[431,9824,9825,9827,9829,9831],{"class":433,"line":584},[431,9826,7113],{"class":445},[431,9828,9111],{"class":654},[431,9830,9644],{"class":445},[431,9832,9833],{"class":455}," # 'python'\n",[431,9835,9836,9838,9840,9842],{"class":433,"line":1244},[431,9837,7922],{"class":437},[431,9839,9111],{"class":654},[431,9841,9644],{"class":445},[431,9843,9844],{"class":455}," # ''\n",[415,9846,9847],{},"Если name примет одно из falsy-значений, переменной value будет присвоена пустая строка.\nВ этом случае в последующем коде мы сможем работать с value как со строкой.\nНо здесь есть потенциальный баг.\nЕсли name содержит falsy значение, а переменной value можно присвоить значения типа 0, False, None, то код выше заработает неверно:",[422,9849,9851],{"className":424,"code":9850,"language":396,"meta":426,"style":426},"# Значение на самом деле есть,\n# но оно Falsy, поэтому не выбирается на условии OR\nFalse or '' # ''\n0 or '' # ''\nNone or '' # ''\n",[428,9852,9853,9858,9863,9873,9883],{"__ignoreMap":426},[431,9854,9855],{"class":433,"line":434},[431,9856,9857],{"class":455},"# Значение на самом деле есть,\n",[431,9859,9860],{"class":433,"line":452},[431,9861,9862],{"class":455},"# но оно Falsy, поэтому не выбирается на условии OR\n",[431,9864,9865,9867,9869,9871],{"class":433,"line":578},[431,9866,4431],{"class":437},[431,9868,9111],{"class":654},[431,9870,9644],{"class":445},[431,9872,9844],{"class":455},[431,9874,9875,9877,9879,9881],{"class":433,"line":584},[431,9876,3302],{"class":437},[431,9878,9111],{"class":654},[431,9880,9644],{"class":445},[431,9882,9844],{"class":455},[431,9884,9885,9887,9889,9891],{"class":433,"line":1244},[431,9886,7922],{"class":437},[431,9888,9111],{"class":654},[431,9890,9644],{"class":445},[431,9892,9844],{"class":455},[458,9894,9896],{"id":9895},"составные-выражения","Составные выражения",[415,9898,9899],{},"Если соединить логические выражения между собой, можно получить довольно интересные способы решения задач с кодом.\nДопустим, нам нужно реализовать код, в котором в переменную записывается:",[697,9901,9902,9905],{},[700,9903,9904],{},"Строка yes, если число четное",[700,9906,9907],{},"Строка no, если нечетное",[415,9909,9910],{},"Это можно сделать, если использовать знания, полученные выше:",[422,9912,9914],{"className":424,"code":9913,"language":396,"meta":426,"style":426},"# число четное\nresult = 10 % 2 == 0 and 'yes' or 'no' # 'yes'\n# или сразу печатаем на экране\nprint(10 % 2 == 0 and 'yes' or 'no') # => 'yes'\n# число нечетное\nprint(11 % 2 == 0 and 'yes' or 'no') # => 'no'\n",[428,9915,9916,9921,9950,9955,9984,9989],{"__ignoreMap":426},[431,9917,9918],{"class":433,"line":434},[431,9919,9920],{"class":455},"# число четное\n",[431,9922,9923,9925,9927,9929,9931,9933,9935,9937,9939,9942,9944,9947],{"class":433,"line":452},[431,9924,4799],{"class":441},[431,9926,1189],{"class":654},[431,9928,2254],{"class":437},[431,9930,784],{"class":654},[431,9932,689],{"class":437},[431,9934,8711],{"class":654},[431,9936,9744],{"class":437},[431,9938,8889],{"class":654},[431,9940,9941],{"class":445}," 'yes'",[431,9943,9111],{"class":654},[431,9945,9946],{"class":445}," 'no'",[431,9948,9949],{"class":455}," # 'yes'\n",[431,9951,9952],{"class":433,"line":578},[431,9953,9954],{"class":455},"# или сразу печатаем на экране\n",[431,9956,9957,9959,9961,9963,9965,9967,9969,9971,9973,9975,9977,9979,9981],{"class":433,"line":584},[431,9958,438],{"class":437},[431,9960,442],{"class":441},[431,9962,3565],{"class":437},[431,9964,784],{"class":654},[431,9966,689],{"class":437},[431,9968,8711],{"class":654},[431,9970,9744],{"class":437},[431,9972,8889],{"class":654},[431,9974,9941],{"class":445},[431,9976,9111],{"class":654},[431,9978,9946],{"class":445},[431,9980,1014],{"class":441},[431,9982,9983],{"class":455},"# => 'yes'\n",[431,9985,9986],{"class":433,"line":1244},[431,9987,9988],{"class":455},"# число нечетное\n",[431,9990,9991,9993,9995,9997,9999,10001,10003,10005,10007,10009,10011,10013,10015],{"class":433,"line":1985},[431,9992,438],{"class":437},[431,9994,442],{"class":441},[431,9996,9573],{"class":437},[431,9998,784],{"class":654},[431,10000,689],{"class":437},[431,10002,8711],{"class":654},[431,10004,9744],{"class":437},[431,10006,8889],{"class":654},[431,10008,9941],{"class":445},[431,10010,9111],{"class":654},[431,10012,9946],{"class":445},[431,10014,1014],{"class":441},[431,10016,10017],{"class":455},"# => 'no'\n",[415,10019,10020],{},"Эти выражения работают согласно порядку и приоритетам. Приоритет присваивания самый низкий, поэтому оно происходит в конце.\nПриоритет сравнения == выше, чем приоритет логических операторов and и or, поэтому сравнение происходит раньше.\nДальше код выполняется слева направо, так как приоритет and выше, чем приоритет or. Рассмотрим по шагам:",[422,10022,10024],{"className":424,"code":10023,"language":396,"meta":426,"style":426},"# Для четного\n# 1 шаг\n10 % 2 == 0 # True\n# 2 шаг\nTrue and 'yes' # Результат — 'yes'\n# 3 шаг\n'yes' or 'no' # Проверка на or выполняется, но правая часть не исполняется, так как сразу возвращается 'yes'\n\n# Для нечетного\n# 1 шаг\n11 % 2 == 0 # False\n# 2 шаг\nFalse and 'yes' # Результат — ложь, проверяем дальше\n# 3 шаг\nFalse or 'no' # Выбирается и возвращается 'no'\n",[428,10025,10026,10031,10036,10051,10056,10067,10072,10084,10088,10093,10097,10112,10116,10127,10131],{"__ignoreMap":426},[431,10027,10028],{"class":433,"line":434},[431,10029,10030],{"class":455},"# Для четного\n",[431,10032,10033],{"class":433,"line":452},[431,10034,10035],{"class":455},"# 1 шаг\n",[431,10037,10038,10040,10042,10044,10046,10048],{"class":433,"line":578},[431,10039,3565],{"class":437},[431,10041,784],{"class":654},[431,10043,689],{"class":437},[431,10045,8711],{"class":654},[431,10047,9744],{"class":437},[431,10049,10050],{"class":455}," # True\n",[431,10052,10053],{"class":433,"line":584},[431,10054,10055],{"class":455},"# 2 шаг\n",[431,10057,10058,10060,10062,10064],{"class":433,"line":1244},[431,10059,4463],{"class":437},[431,10061,8889],{"class":654},[431,10063,9941],{"class":445},[431,10065,10066],{"class":455}," # Результат — 'yes'\n",[431,10068,10069],{"class":433,"line":1985},[431,10070,10071],{"class":455},"# 3 шаг\n",[431,10073,10074,10077,10079,10081],{"class":433,"line":2041},[431,10075,10076],{"class":445},"'yes'",[431,10078,9111],{"class":654},[431,10080,9946],{"class":445},[431,10082,10083],{"class":455}," # Проверка на or выполняется, но правая часть не исполняется, так как сразу возвращается 'yes'\n",[431,10085,10086],{"class":433,"line":4018},[431,10087,1662],{"emptyLinePlaceholder":393},[431,10089,10090],{"class":433,"line":4030},[431,10091,10092],{"class":455},"# Для нечетного\n",[431,10094,10095],{"class":433,"line":4419},[431,10096,10035],{"class":455},[431,10098,10099,10101,10103,10105,10107,10109],{"class":433,"line":4436},[431,10100,9573],{"class":437},[431,10102,784],{"class":654},[431,10104,689],{"class":437},[431,10106,8711],{"class":654},[431,10108,9744],{"class":437},[431,10110,10111],{"class":455}," # False\n",[431,10113,10114],{"class":433,"line":4446},[431,10115,10055],{"class":455},[431,10117,10118,10120,10122,10124],{"class":433,"line":4451},[431,10119,4431],{"class":437},[431,10121,8889],{"class":654},[431,10123,9941],{"class":445},[431,10125,10126],{"class":455}," # Результат — ложь, проверяем дальше\n",[431,10128,10129],{"class":433,"line":4086},[431,10130,10071],{"class":455},[431,10132,10133,10135,10137,10139],{"class":433,"line":4477},[431,10134,4431],{"class":437},[431,10136,9111],{"class":654},[431,10138,9946],{"class":445},[431,10140,10141],{"class":455}," # Выбирается и возвращается 'no'\n",[415,10143,10144],{},"Такую же схему можно использовать с любым выражением в начале:",[422,10146,10148],{"className":424,"code":10147,"language":396,"meta":426,"style":426},"print(somefunc() and 'yes' or 'no')\n",[428,10149,10150],{"__ignoreMap":426},[431,10151,10152,10154,10157,10159,10161,10163,10165],{"class":433,"line":434},[431,10153,438],{"class":437},[431,10155,10156],{"class":441},"(somefunc() ",[431,10158,8946],{"class":654},[431,10160,9941],{"class":445},[431,10162,9111],{"class":654},[431,10164,9946],{"class":445},[431,10166,449],{"class":441},[458,10168,10170],{"id":10169},"двойное-отрицание","Двойное отрицание",[415,10172,10173],{},"Вспомним, как выглядит операция отрицания:",[422,10175,10177],{"className":424,"code":10176,"language":396,"meta":426,"style":426},"answer = True\nprint(not answer)  # => False\n",[428,10178,10179,10189],{"__ignoreMap":426},[431,10180,10181,10184,10186],{"class":433,"line":434},[431,10182,10183],{"class":441},"answer ",[431,10185,1189],{"class":654},[431,10187,10188],{"class":437}," True\n",[431,10190,10191,10193,10195,10197,10200],{"class":433,"line":452},[431,10192,438],{"class":437},[431,10194,442],{"class":441},[431,10196,9369],{"class":654},[431,10198,10199],{"class":441}," answer)  ",[431,10201,8490],{"class":455},[415,10203,10204],{},"При двойном отрицании итоговое значение равно начальному:",[422,10206,10208],{"className":424,"code":10207,"language":396,"meta":426,"style":426},"answer = True\nprint(not not answer)  # => True\n",[428,10209,10210,10218],{"__ignoreMap":426},[431,10211,10212,10214,10216],{"class":433,"line":434},[431,10213,10183],{"class":441},[431,10215,1189],{"class":654},[431,10217,10188],{"class":437},[431,10219,10220,10222,10224,10226,10228,10230],{"class":433,"line":452},[431,10221,438],{"class":437},[431,10223,442],{"class":441},[431,10225,9369],{"class":654},[431,10227,9498],{"class":654},[431,10229,10199],{"class":441},[431,10231,8470],{"class":455},[415,10233,8664,10234,10236],{},[428,10235,9369],{}," всегда возвращает булево значение, независимо от типа переданного аргумента, а не заменяет значение на противоположное.\nПоэтому двойное отрицание тоже вернет булево True\u002FFalse.",[422,10238,10240],{"className":424,"code":10239,"language":396,"meta":426,"style":426},"answer = 'python'\nprint(not answer) # => False\nprint(not not answer) # => True\n",[428,10241,10242,10251,10264],{"__ignoreMap":426},[431,10243,10244,10246,10248],{"class":433,"line":434},[431,10245,10183],{"class":441},[431,10247,1189],{"class":654},[431,10249,10250],{"class":445}," 'python'\n",[431,10252,10253,10255,10257,10259,10262],{"class":433,"line":452},[431,10254,438],{"class":437},[431,10256,442],{"class":441},[431,10258,9369],{"class":654},[431,10260,10261],{"class":441}," answer) ",[431,10263,8490],{"class":455},[431,10265,10266,10268,10270,10272,10274,10276],{"class":433,"line":578},[431,10267,438],{"class":437},[431,10269,442],{"class":441},[431,10271,9369],{"class":654},[431,10273,9498],{"class":654},[431,10275,10261],{"class":441},[431,10277,8470],{"class":455},[458,10279,10281],{"id":10280},"ошибки-выбора","Ошибки выбора",[415,10283,10284],{},"Представьте, что нам нужно проверить, равно ли значение одному или другому.\nНапример, переменная value должна содержать одно из двух значений: first или second.\nНачинающие разработчики иногда записывают это выражение так:",[422,10286,10288],{"className":424,"code":10287,"language":396,"meta":426,"style":426},"value == ('first' or 'second')\n",[428,10289,10290],{"__ignoreMap":426},[431,10291,10292,10294,10296,10298,10301,10303,10306],{"class":433,"line":434},[431,10293,3643],{"class":441},[431,10295,8409],{"class":654},[431,10297,976],{"class":441},[431,10299,10300],{"class":445},"'first'",[431,10302,9111],{"class":654},[431,10304,10305],{"class":445}," 'second'",[431,10307,449],{"class":441},[415,10309,10310],{},"Однако такой код приведет к неверному результату.\nНеобходимо вспомнить приоритет выполнения операций.\nПервым делом вычисляется все, что указано в скобках — 'first' or 'second'.\nЕсли выполнить этот код, то вывод будет таким:",[422,10312,10314],{"className":424,"code":10313,"language":396,"meta":426,"style":426},">>> 'first' or 'second'\n'first'\n",[428,10315,10316,10329],{"__ignoreMap":426},[431,10317,10318,10321,10324,10326],{"class":433,"line":434},[431,10319,10320],{"class":654},">>>",[431,10322,10323],{"class":445}," 'first'",[431,10325,9111],{"class":654},[431,10327,10328],{"class":445}," 'second'\n",[431,10330,10331],{"class":433,"line":452},[431,10332,10333],{"class":445},"'first'\n",[415,10335,10336],{},"Теперь заменим исходное выражение на частично вычисленное:",[422,10338,10340],{"className":424,"code":10339,"language":396,"meta":426,"style":426},"value == 'first'\n",[428,10341,10342],{"__ignoreMap":426},[431,10343,10344,10346,10348],{"class":433,"line":434},[431,10345,3643],{"class":441},[431,10347,8409],{"class":654},[431,10349,10350],{"class":445}," 'first'\n",[415,10352,10353],{},"Совсем не то, что мы ожидали. А теперь вернемся к началу и напишем проверку правильно:",[422,10355,10357],{"className":424,"code":10356,"language":396,"meta":426,"style":426},"# Скобки ставить не обязательно,\n# потому что приоритет == выше, чем приоритет or\nvalue == 'first' or value == 'second'\n",[428,10358,10359,10364,10369],{"__ignoreMap":426},[431,10360,10361],{"class":433,"line":434},[431,10362,10363],{"class":455},"# Скобки ставить не обязательно,\n",[431,10365,10366],{"class":433,"line":452},[431,10367,10368],{"class":455},"# потому что приоритет == выше, чем приоритет or\n",[431,10370,10371,10373,10375,10377,10379,10382,10384],{"class":433,"line":578},[431,10372,3643],{"class":441},[431,10374,8409],{"class":654},[431,10376,10323],{"class":445},[431,10378,9111],{"class":654},[431,10380,10381],{"class":441}," value ",[431,10383,8409],{"class":654},[431,10385,10328],{"class":445},[632,10387,10389],{"id":10388},"условные-конструкции","Условные конструкции",[415,10391,10392],{},"С помощью условных конструкций можно изменить поведение программы, которое будет зависеть от проверяемых условий.",[458,10394,10396,10397],{"id":10395},"если-if","Если ",[428,10398,10399],{},"if",[415,10401,10402],{},"Для примера рассмотрим функцию, которая определяет тип переданного предложения. Для начала она будет отличать повествовательные предложения от вопросительных:",[422,10404,10406],{"className":424,"code":10405,"language":396,"meta":426,"style":426},"def get_type_of_sentence(sentence):\n    last_char = sentence[-1]\n    if last_char == '?':\n        return 'question'\n    return 'normal'\n\nprint(get_type_of_sentence('Python'))   # => normal\nprint(get_type_of_sentence('Python?'))  # => question\n",[428,10407,10408,10418,10434,10449,10457,10464,10468,10482],{"__ignoreMap":426},[431,10409,10410,10412,10415],{"class":433,"line":434},[431,10411,6330],{"class":654},[431,10413,10414],{"class":6333}," get_type_of_sentence",[431,10416,10417],{"class":441},"(sentence):\n",[431,10419,10420,10423,10425,10428,10430,10432],{"class":433,"line":452},[431,10421,10422],{"class":441},"    last_char ",[431,10424,1189],{"class":654},[431,10426,10427],{"class":441}," sentence[",[431,10429,853],{"class":654},[431,10431,1192],{"class":437},[431,10433,3568],{"class":441},[431,10435,10436,10439,10442,10444,10447],{"class":433,"line":578},[431,10437,10438],{"class":654},"    if",[431,10440,10441],{"class":441}," last_char ",[431,10443,8409],{"class":654},[431,10445,10446],{"class":445}," '?'",[431,10448,8102],{"class":441},[431,10450,10451,10454],{"class":433,"line":584},[431,10452,10453],{"class":654},"        return",[431,10455,10456],{"class":445}," 'question'\n",[431,10458,10459,10461],{"class":433,"line":1244},[431,10460,6599],{"class":654},[431,10462,10463],{"class":445}," 'normal'\n",[431,10465,10466],{"class":433,"line":1985},[431,10467,1662],{"emptyLinePlaceholder":393},[431,10469,10470,10472,10475,10477,10479],{"class":433,"line":2041},[431,10471,438],{"class":437},[431,10473,10474],{"class":441},"(get_type_of_sentence(",[431,10476,1304],{"class":445},[431,10478,8741],{"class":441},[431,10480,10481],{"class":455},"# => normal\n",[431,10483,10484,10486,10488,10491,10493],{"class":433,"line":4018},[431,10485,438],{"class":437},[431,10487,10474],{"class":441},[431,10489,10490],{"class":445},"'Python?'",[431,10492,986],{"class":441},[431,10494,10495],{"class":455},"# => question\n",[415,10497,10498,10500,10501,10504,10505,10508],{},[800,10499,10399],{}," — конструкция языка, которая управляет порядком выполнения инструкций.\nПосле слова if ей передается выражение-предикат, и в конце ставится двоеточие.\nПосле этого идет блок кода. Он выполнится, если предикат — истина.\nЕсли предикат — ложь, то блок кода пропускается, и функция выполняется дальше.\nВ нашем случае следующая строчка кода — ",[428,10502,10503],{},"return 'normal'"," — заставит функцию вернуть строку и завершиться.\n",[428,10506,10507],{},"return"," может находиться в любом месте функции — даже внутри блока кода с условием.",[458,10510,10512,10513],{"id":10511},"иначе-else","Иначе ",[428,10514,10515],{},"else",[415,10517,10518],{},"Теперь изменим функцию из предыдущего примера так, чтобы она возвращала не просто тип предложения, а целую строку Sentence is normal или Sentence is question:",[422,10520,10522],{"className":424,"code":10521,"language":396,"meta":426,"style":426},"def get_type_of_sentence(sentence):\n    last_char = sentence[-1]\n\n    if last_char == '?':\n        sentence_type = 'question'\n    else:\n        sentence_type = 'normal'\n\n    return \"Sentence is \" + sentence_type\n\nprint(get_type_of_sentence('Python'))   # => 'Sentence is normal'\nprint(get_type_of_sentence('Python?'))  # => 'Sentence is question'\n",[428,10523,10524,10532,10546,10550,10562,10571,10578,10586,10590,10602,10606,10619],{"__ignoreMap":426},[431,10525,10526,10528,10530],{"class":433,"line":434},[431,10527,6330],{"class":654},[431,10529,10414],{"class":6333},[431,10531,10417],{"class":441},[431,10533,10534,10536,10538,10540,10542,10544],{"class":433,"line":452},[431,10535,10422],{"class":441},[431,10537,1189],{"class":654},[431,10539,10427],{"class":441},[431,10541,853],{"class":654},[431,10543,1192],{"class":437},[431,10545,3568],{"class":441},[431,10547,10548],{"class":433,"line":578},[431,10549,1662],{"emptyLinePlaceholder":393},[431,10551,10552,10554,10556,10558,10560],{"class":433,"line":584},[431,10553,10438],{"class":654},[431,10555,10441],{"class":441},[431,10557,8409],{"class":654},[431,10559,10446],{"class":445},[431,10561,8102],{"class":441},[431,10563,10564,10567,10569],{"class":433,"line":1244},[431,10565,10566],{"class":441},"        sentence_type ",[431,10568,1189],{"class":654},[431,10570,10456],{"class":445},[431,10572,10573,10576],{"class":433,"line":1985},[431,10574,10575],{"class":654},"    else",[431,10577,8102],{"class":441},[431,10579,10580,10582,10584],{"class":433,"line":2041},[431,10581,10566],{"class":441},[431,10583,1189],{"class":654},[431,10585,10463],{"class":445},[431,10587,10588],{"class":433,"line":4018},[431,10589,1662],{"emptyLinePlaceholder":393},[431,10591,10592,10594,10597,10599],{"class":433,"line":4030},[431,10593,6599],{"class":654},[431,10595,10596],{"class":445}," \"Sentence is \"",[431,10598,655],{"class":654},[431,10600,10601],{"class":441}," sentence_type\n",[431,10603,10604],{"class":433,"line":4419},[431,10605,1662],{"emptyLinePlaceholder":393},[431,10607,10608,10610,10612,10614,10616],{"class":433,"line":4436},[431,10609,438],{"class":437},[431,10611,10474],{"class":441},[431,10613,1304],{"class":445},[431,10615,8741],{"class":441},[431,10617,10618],{"class":455},"# => 'Sentence is normal'\n",[431,10620,10621,10623,10625,10627,10629],{"class":433,"line":4446},[431,10622,438],{"class":437},[431,10624,10474],{"class":441},[431,10626,10490],{"class":445},[431,10628,986],{"class":441},[431,10630,10631],{"class":455},"# => 'Sentence is question'\n",[415,10633,10634,10635,10637,10638,10640,10641,10643,10644,10646],{},"Мы добавили ",[428,10636,10515],{}," и новый блок. Он выполнится, если условие в ",[428,10639,10399],{}," — ложь. Еще в блок ",[428,10642,10515],{}," можно вкладывать другие условия ",[428,10645,10399],{},".\nElse переводится «иначе», «в ином случае».\nОформить конструкцию if-else можно двумя способами. С помощью отрицания можно изменить порядок блоков:",[422,10648,10650],{"className":424,"code":10649,"language":396,"meta":426,"style":426},"def get_type_of_sentence(sentence):\n    last_char = sentence[-1]\n\n    if last_char != '?':\n        sentence_type = 'normal'\n    else:\n        sentence_type = 'question'\n\n    return \"Sentence is \" + sentence_type\n",[428,10651,10652,10660,10674,10678,10691,10699,10705,10713,10717],{"__ignoreMap":426},[431,10653,10654,10656,10658],{"class":433,"line":434},[431,10655,6330],{"class":654},[431,10657,10414],{"class":6333},[431,10659,10417],{"class":441},[431,10661,10662,10664,10666,10668,10670,10672],{"class":433,"line":452},[431,10663,10422],{"class":441},[431,10665,1189],{"class":654},[431,10667,10427],{"class":441},[431,10669,853],{"class":654},[431,10671,1192],{"class":437},[431,10673,3568],{"class":441},[431,10675,10676],{"class":433,"line":578},[431,10677,1662],{"emptyLinePlaceholder":393},[431,10679,10680,10682,10684,10687,10689],{"class":433,"line":584},[431,10681,10438],{"class":654},[431,10683,10441],{"class":441},[431,10685,10686],{"class":654},"!=",[431,10688,10446],{"class":445},[431,10690,8102],{"class":441},[431,10692,10693,10695,10697],{"class":433,"line":1244},[431,10694,10566],{"class":441},[431,10696,1189],{"class":654},[431,10698,10463],{"class":445},[431,10700,10701,10703],{"class":433,"line":1985},[431,10702,10575],{"class":654},[431,10704,8102],{"class":441},[431,10706,10707,10709,10711],{"class":433,"line":2041},[431,10708,10566],{"class":441},[431,10710,1189],{"class":654},[431,10712,10456],{"class":445},[431,10714,10715],{"class":433,"line":4018},[431,10716,1662],{"emptyLinePlaceholder":393},[431,10718,10719,10721,10723,10725],{"class":433,"line":4030},[431,10720,6599],{"class":654},[431,10722,10596],{"class":445},[431,10724,655],{"class":654},[431,10726,10601],{"class":441},[415,10728,10729],{},"Чтобы конструкцию было легче оформлять, старайтесь выбирать проверку без отрицаний и подстраивайте содержимое блоков под нее.",[458,10731,10733,10734],{"id":10732},"конструкция-else-if-elif","Конструкция else + if = ",[428,10735,10736],{},"elif",[415,10738,10739],{},"Функция get_type_of_sentence() различает только вопросительные и повествовательные предложения. Добавим в нее поддержку восклицательных предложений:",[422,10741,10743],{"className":424,"code":10742,"language":396,"meta":426,"style":426},"def get_type_of_sentence(sentence):\n    last_char = sentence[-1]\n\n    if last_char == '?':\n        sentence_type = 'question'\n\n    if last_char == '!':\n        sentence_type = 'exclamation'\n    else:\n        sentence_type = 'normal'\n\n    return 'Sentence is ' + sentence_type\n\nprint(get_type_of_sentence('Who?'))  # => 'Sentence is normal'\nprint(get_type_of_sentence('No'))    # => 'Sentence is normal'\nprint(get_type_of_sentence('No!'))   # => 'Sentence is exclamation'\n",[428,10744,10745,10753,10767,10771,10783,10791,10795,10807,10816,10822,10830,10834,10845,10849,10862,10875],{"__ignoreMap":426},[431,10746,10747,10749,10751],{"class":433,"line":434},[431,10748,6330],{"class":654},[431,10750,10414],{"class":6333},[431,10752,10417],{"class":441},[431,10754,10755,10757,10759,10761,10763,10765],{"class":433,"line":452},[431,10756,10422],{"class":441},[431,10758,1189],{"class":654},[431,10760,10427],{"class":441},[431,10762,853],{"class":654},[431,10764,1192],{"class":437},[431,10766,3568],{"class":441},[431,10768,10769],{"class":433,"line":578},[431,10770,1662],{"emptyLinePlaceholder":393},[431,10772,10773,10775,10777,10779,10781],{"class":433,"line":584},[431,10774,10438],{"class":654},[431,10776,10441],{"class":441},[431,10778,8409],{"class":654},[431,10780,10446],{"class":445},[431,10782,8102],{"class":441},[431,10784,10785,10787,10789],{"class":433,"line":1244},[431,10786,10566],{"class":441},[431,10788,1189],{"class":654},[431,10790,10456],{"class":445},[431,10792,10793],{"class":433,"line":1985},[431,10794,1662],{"emptyLinePlaceholder":393},[431,10796,10797,10799,10801,10803,10805],{"class":433,"line":2041},[431,10798,10438],{"class":654},[431,10800,10441],{"class":441},[431,10802,8409],{"class":654},[431,10804,5920],{"class":445},[431,10806,8102],{"class":441},[431,10808,10809,10811,10813],{"class":433,"line":4018},[431,10810,10566],{"class":441},[431,10812,1189],{"class":654},[431,10814,10815],{"class":445}," 'exclamation'\n",[431,10817,10818,10820],{"class":433,"line":4030},[431,10819,10575],{"class":654},[431,10821,8102],{"class":441},[431,10823,10824,10826,10828],{"class":433,"line":4419},[431,10825,10566],{"class":441},[431,10827,1189],{"class":654},[431,10829,10463],{"class":445},[431,10831,10832],{"class":433,"line":4436},[431,10833,1662],{"emptyLinePlaceholder":393},[431,10835,10836,10838,10841,10843],{"class":433,"line":4446},[431,10837,6599],{"class":654},[431,10839,10840],{"class":445}," 'Sentence is '",[431,10842,655],{"class":654},[431,10844,10601],{"class":441},[431,10846,10847],{"class":433,"line":4451},[431,10848,1662],{"emptyLinePlaceholder":393},[431,10850,10851,10853,10855,10858,10860],{"class":433,"line":4086},[431,10852,438],{"class":437},[431,10854,10474],{"class":441},[431,10856,10857],{"class":445},"'Who?'",[431,10859,986],{"class":441},[431,10861,10618],{"class":455},[431,10863,10864,10866,10868,10871,10873],{"class":433,"line":4477},[431,10865,438],{"class":437},[431,10867,10474],{"class":441},[431,10869,10870],{"class":445},"'No'",[431,10872,9188],{"class":441},[431,10874,10618],{"class":455},[431,10876,10877,10879,10881,10884,10886],{"class":433,"line":4482},[431,10878,438],{"class":437},[431,10880,10474],{"class":441},[431,10882,10883],{"class":445},"'No!'",[431,10885,8741],{"class":441},[431,10887,10888],{"class":455},"# => 'Sentence is exclamation'\n",[415,10890,10891],{},"Мы добавили проверку восклицательных предложений — exclamation.\nТехнически эта функция работает, но вопросительные предложения трактует неверно.\nЕще в ней есть проблемы с точки зрения семантики:",[697,10893,10894,10897],{},[700,10895,10896],{},"Наличие восклицательного знака проверяется в любом случае, даже если уже обнаружился вопросительный знак;",[700,10898,10899],{},"Ветка else описана для второго условия, но не для первого. Поэтому вопросительное предложение становится \"normal\";",[415,10901,10902],{},"Чтобы исправить ситуацию, воспользуемся еще одним элементом условной конструкции:",[422,10904,10906],{"className":424,"code":10905,"language":396,"meta":426,"style":426},"def get_type_of_sentence(sentence):\n    last_char = sentence[-1]\n\n    if last_char == '?':\n        sentence_type = 'question'\n    elif last_char == '!':\n        sentence_type = 'exclamation'\n    else:\n        sentence_type = 'normal'\n\n    return 'Sentence is ' + sentence_type\n\nprint(get_type_of_sentence('Who?'))  # => 'Sentence is question'\nprint(get_type_of_sentence('No'))    # => 'Sentence is normal'\nprint(get_type_of_sentence('No!'))   # => 'Sentence is exclamation'\n",[428,10907,10908,10916,10930,10934,10946,10954,10967,10975,10981,10989,10993,11003,11007,11019,11031],{"__ignoreMap":426},[431,10909,10910,10912,10914],{"class":433,"line":434},[431,10911,6330],{"class":654},[431,10913,10414],{"class":6333},[431,10915,10417],{"class":441},[431,10917,10918,10920,10922,10924,10926,10928],{"class":433,"line":452},[431,10919,10422],{"class":441},[431,10921,1189],{"class":654},[431,10923,10427],{"class":441},[431,10925,853],{"class":654},[431,10927,1192],{"class":437},[431,10929,3568],{"class":441},[431,10931,10932],{"class":433,"line":578},[431,10933,1662],{"emptyLinePlaceholder":393},[431,10935,10936,10938,10940,10942,10944],{"class":433,"line":584},[431,10937,10438],{"class":654},[431,10939,10441],{"class":441},[431,10941,8409],{"class":654},[431,10943,10446],{"class":445},[431,10945,8102],{"class":441},[431,10947,10948,10950,10952],{"class":433,"line":1244},[431,10949,10566],{"class":441},[431,10951,1189],{"class":654},[431,10953,10456],{"class":445},[431,10955,10956,10959,10961,10963,10965],{"class":433,"line":1985},[431,10957,10958],{"class":654},"    elif",[431,10960,10441],{"class":441},[431,10962,8409],{"class":654},[431,10964,5920],{"class":445},[431,10966,8102],{"class":441},[431,10968,10969,10971,10973],{"class":433,"line":2041},[431,10970,10566],{"class":441},[431,10972,1189],{"class":654},[431,10974,10815],{"class":445},[431,10976,10977,10979],{"class":433,"line":4018},[431,10978,10575],{"class":654},[431,10980,8102],{"class":441},[431,10982,10983,10985,10987],{"class":433,"line":4030},[431,10984,10566],{"class":441},[431,10986,1189],{"class":654},[431,10988,10463],{"class":445},[431,10990,10991],{"class":433,"line":4419},[431,10992,1662],{"emptyLinePlaceholder":393},[431,10994,10995,10997,10999,11001],{"class":433,"line":4436},[431,10996,6599],{"class":654},[431,10998,10840],{"class":445},[431,11000,655],{"class":654},[431,11002,10601],{"class":441},[431,11004,11005],{"class":433,"line":4446},[431,11006,1662],{"emptyLinePlaceholder":393},[431,11008,11009,11011,11013,11015,11017],{"class":433,"line":4451},[431,11010,438],{"class":437},[431,11012,10474],{"class":441},[431,11014,10857],{"class":445},[431,11016,986],{"class":441},[431,11018,10631],{"class":455},[431,11020,11021,11023,11025,11027,11029],{"class":433,"line":4086},[431,11022,438],{"class":437},[431,11024,10474],{"class":441},[431,11026,10870],{"class":445},[431,11028,9188],{"class":441},[431,11030,10618],{"class":455},[431,11032,11033,11035,11037,11039,11041],{"class":433,"line":4477},[431,11034,438],{"class":437},[431,11036,10474],{"class":441},[431,11038,10883],{"class":445},[431,11040,8741],{"class":441},[431,11042,10888],{"class":455},[415,11044,11045,11046,11048],{},"Теперь все условия выстроились в единую конструкцию.\n",[428,11047,10736],{}," означает — «если не выполнено предыдущее условие, но выполнено текущее». Получается такая схема:",[697,11050,11051,11054,11057],{},[700,11052,11053],{},"Если последний символ — ?, то 'question'",[700,11055,11056],{},"Если последний символ — !, то 'exclamation'",[700,11058,11059],{},"Остальные варианты — 'normal'",[415,11061,11062,11063,2699],{},"Выполнится только один из блоков кода, который относится ко всей конструкции ",[800,11064,10399],{},[458,11066,11068],{"id":11067},"тернарный-оператор","Тернарный оператор",[415,11070,11071],{},"Посмотрите на определение функции, которая возвращает модуль переданного числа:",[422,11073,11075],{"className":424,"code":11074,"language":396,"meta":426,"style":426},"def abs(number):\n    if number >= 0:\n        return number\n    return -number\n",[428,11076,11077,11085,11097,11104],{"__ignoreMap":426},[431,11078,11079,11081,11083],{"class":433,"line":434},[431,11080,6330],{"class":654},[431,11082,4683],{"class":437},[431,11084,8697],{"class":441},[431,11086,11087,11089,11091,11093,11095],{"class":433,"line":452},[431,11088,10438],{"class":654},[431,11090,8704],{"class":441},[431,11092,9105],{"class":654},[431,11094,9744],{"class":437},[431,11096,8102],{"class":441},[431,11098,11099,11101],{"class":433,"line":578},[431,11100,10453],{"class":654},[431,11102,11103],{"class":441}," number\n",[431,11105,11106,11108,11110],{"class":433,"line":584},[431,11107,6599],{"class":654},[431,11109,981],{"class":654},[431,11111,11112],{"class":441},"number\n",[415,11114,11115],{},"Но можно записать более лаконично.\nДля этого справа от return должно быть выражение, но if — это инструкция, а не выражение.\nВ Python есть конструкция, которая работает как if-else, но считается выражением.\nОна называется тернарный оператор — единственный оператор в Python, который требует три операнда:",[422,11117,11119],{"className":424,"code":11118,"language":396,"meta":426,"style":426},"def abs(number):\n    return number if number >= 0 else -number\n",[428,11120,11121,11129],{"__ignoreMap":426},[431,11122,11123,11125,11127],{"class":433,"line":434},[431,11124,6330],{"class":654},[431,11126,4683],{"class":437},[431,11128,8697],{"class":441},[431,11130,11131,11133,11135,11137,11139,11141,11143,11146,11148],{"class":433,"line":452},[431,11132,6599],{"class":654},[431,11134,8704],{"class":441},[431,11136,10399],{"class":654},[431,11138,8704],{"class":441},[431,11140,9105],{"class":654},[431,11142,9744],{"class":437},[431,11144,11145],{"class":654}," else",[431,11147,981],{"class":654},[431,11149,11112],{"class":441},[415,11151,11152,11153],{},"Общий паттерн выглядит так: ",[11154,11155,11156,11157],"expression",{"true":426}," if ",[11158,11159,11160,11161],"predicate",{}," else ",[11154,11162,11163],{"false":426},".\nДавайте перепишем начальный вариант get_type_of_sentence() аналогично.",[422,11165,11167],{"className":424,"code":11166,"language":396,"meta":426,"style":426},"def get_type_of_sentence(sentence):\n    last_char = sentence[-1]\n    return 'question' if last_char == '?' else 'normal'\n\nprint(get_type_of_sentence('Python'))   # => normal\nprint(get_type_of_sentence('Python?'))  # => question\n",[428,11168,11169,11177,11191,11211,11215,11227],{"__ignoreMap":426},[431,11170,11171,11173,11175],{"class":433,"line":434},[431,11172,6330],{"class":654},[431,11174,10414],{"class":6333},[431,11176,10417],{"class":441},[431,11178,11179,11181,11183,11185,11187,11189],{"class":433,"line":452},[431,11180,10422],{"class":441},[431,11182,1189],{"class":654},[431,11184,10427],{"class":441},[431,11186,853],{"class":654},[431,11188,1192],{"class":437},[431,11190,3568],{"class":441},[431,11192,11193,11195,11198,11201,11203,11205,11207,11209],{"class":433,"line":578},[431,11194,6599],{"class":654},[431,11196,11197],{"class":445}," 'question'",[431,11199,11200],{"class":654}," if",[431,11202,10441],{"class":441},[431,11204,8409],{"class":654},[431,11206,10446],{"class":445},[431,11208,11145],{"class":654},[431,11210,10463],{"class":445},[431,11212,11213],{"class":433,"line":584},[431,11214,1662],{"emptyLinePlaceholder":393},[431,11216,11217,11219,11221,11223,11225],{"class":433,"line":1244},[431,11218,438],{"class":437},[431,11220,10474],{"class":441},[431,11222,1304],{"class":445},[431,11224,8741],{"class":441},[431,11226,10481],{"class":455},[431,11228,11229,11231,11233,11235,11237],{"class":433,"line":1985},[431,11230,438],{"class":437},[431,11232,10474],{"class":441},[431,11234,10490],{"class":445},[431,11236,986],{"class":441},[431,11238,10495],{"class":455},[415,11240,11241],{},"Тернарный оператор можно вкладывать в тернарный оператор. Но не нужно так делать, так как такой код тяжело читать и отлаживать.",[632,11243,11245],{"id":11244},"отступы-и-блоки","Отступы и блоки",[415,11247,11248],{},"В Python, в отличие от других языков, блоки кода принято выделять не скобками, а новой строкой с отступом.\nОтступы обычно состоят из 4 пробелов или одного символа табуляции, который нужно настроить в редакторе на использование пробелов.\nВсе строки в одном блоке должны иметь одинаковый отступ.\nУвеличение отступа означает начало нового блока, а уменьшение отступа означает конец блока.",[422,11250,11252],{"className":424,"code":11251,"language":396,"meta":426,"style":426},"if a == 42:\n    # отступ и начало блока if\n    # все строки кода с одним отступом выполняются в одном блоке\n    print('First')\n    print('Second')\n# конец отступа и выход из блока\nprint('Goodbye!')\n",[428,11253,11254,11267,11272,11277,11288,11299,11304],{"__ignoreMap":426},[431,11255,11256,11258,11261,11263,11265],{"class":433,"line":434},[431,11257,10399],{"class":654},[431,11259,11260],{"class":441}," a ",[431,11262,8409],{"class":654},[431,11264,2320],{"class":437},[431,11266,8102],{"class":441},[431,11268,11269],{"class":433,"line":452},[431,11270,11271],{"class":455},"    # отступ и начало блока if\n",[431,11273,11274],{"class":433,"line":578},[431,11275,11276],{"class":455},"    # все строки кода с одним отступом выполняются в одном блоке\n",[431,11278,11279,11281,11283,11286],{"class":433,"line":584},[431,11280,6357],{"class":437},[431,11282,442],{"class":441},[431,11284,11285],{"class":445},"'First'",[431,11287,449],{"class":441},[431,11289,11290,11292,11294,11297],{"class":433,"line":1244},[431,11291,6357],{"class":437},[431,11293,442],{"class":441},[431,11295,11296],{"class":445},"'Second'",[431,11298,449],{"class":441},[431,11300,11301],{"class":433,"line":1985},[431,11302,11303],{"class":455},"# конец отступа и выход из блока\n",[431,11305,11306,11308,11310,11313],{"class":433,"line":2041},[431,11307,438],{"class":437},[431,11309,442],{"class":441},[431,11311,11312],{"class":445},"'Goodbye!'",[431,11314,449],{"class":441},[415,11316,11317],{},"На примере использования else видно, как важно не забывать отделять блоки.",[422,11319,11321],{"className":424,"code":11320,"language":396,"meta":426,"style":426},"# Неправильно\ndef check_number(number):\n    if number > 0:\n        print(\"Число положительное\")\n    if number > 10:\n        print(\"Число больше 10\")\n    else:\n        print(\"Число не положительное\")\n\ncheck_number(3)\n# => Число положительное\n# => Число не положительное\n",[428,11322,11323,11328,11337,11349,11361,11373,11384,11390,11401,11405,11414,11419],{"__ignoreMap":426},[431,11324,11325],{"class":433,"line":434},[431,11326,11327],{"class":455},"# Неправильно\n",[431,11329,11330,11332,11335],{"class":433,"line":452},[431,11331,6330],{"class":654},[431,11333,11334],{"class":6333}," check_number",[431,11336,8697],{"class":441},[431,11338,11339,11341,11343,11345,11347],{"class":433,"line":578},[431,11340,10438],{"class":654},[431,11342,8704],{"class":441},[431,11344,8883],{"class":654},[431,11346,9744],{"class":437},[431,11348,8102],{"class":441},[431,11350,11351,11354,11356,11359],{"class":433,"line":584},[431,11352,11353],{"class":437},"        print",[431,11355,442],{"class":441},[431,11357,11358],{"class":445},"\"Число положительное\"",[431,11360,449],{"class":441},[431,11362,11363,11365,11367,11369,11371],{"class":433,"line":1244},[431,11364,10438],{"class":654},[431,11366,8704],{"class":441},[431,11368,8883],{"class":654},[431,11370,2254],{"class":437},[431,11372,8102],{"class":441},[431,11374,11375,11377,11379,11382],{"class":433,"line":1985},[431,11376,11353],{"class":437},[431,11378,442],{"class":441},[431,11380,11381],{"class":445},"\"Число больше 10\"",[431,11383,449],{"class":441},[431,11385,11386,11388],{"class":433,"line":2041},[431,11387,10575],{"class":654},[431,11389,8102],{"class":441},[431,11391,11392,11394,11396,11399],{"class":433,"line":4018},[431,11393,11353],{"class":437},[431,11395,442],{"class":441},[431,11397,11398],{"class":445},"\"Число не положительное\"",[431,11400,449],{"class":441},[431,11402,11403],{"class":433,"line":4030},[431,11404,1662],{"emptyLinePlaceholder":393},[431,11406,11407,11410,11412],{"class":433,"line":4419},[431,11408,11409],{"class":441},"check_number(",[431,11411,971],{"class":437},[431,11413,449],{"class":441},[431,11415,11416],{"class":433,"line":4436},[431,11417,11418],{"class":455},"# => Число положительное\n",[431,11420,11421],{"class":433,"line":4446},[431,11422,11423],{"class":455},"# => Число не положительное\n",[415,11425,11426],{},"В примере выше мы забыли \"вложить\" с помощью отступа второй if, потому else теперь относится к нему, а не первому if.",[422,11428,11430],{"className":424,"code":11429,"language":396,"meta":426,"style":426},"# Правильно\ndef check_number(number):\n    if number > 0:\n        print(\"Число положительное\")\n        if number > 10:\n            print(\"Число больше 10\")\n    else:\n        print(\"Число не положительное\")\n\ncheck_number(3)\n# => Число положительное\n",[428,11431,11432,11437,11445,11457,11467,11480,11491,11497,11507,11511,11519],{"__ignoreMap":426},[431,11433,11434],{"class":433,"line":434},[431,11435,11436],{"class":455},"# Правильно\n",[431,11438,11439,11441,11443],{"class":433,"line":452},[431,11440,6330],{"class":654},[431,11442,11334],{"class":6333},[431,11444,8697],{"class":441},[431,11446,11447,11449,11451,11453,11455],{"class":433,"line":578},[431,11448,10438],{"class":654},[431,11450,8704],{"class":441},[431,11452,8883],{"class":654},[431,11454,9744],{"class":437},[431,11456,8102],{"class":441},[431,11458,11459,11461,11463,11465],{"class":433,"line":584},[431,11460,11353],{"class":437},[431,11462,442],{"class":441},[431,11464,11358],{"class":445},[431,11466,449],{"class":441},[431,11468,11469,11472,11474,11476,11478],{"class":433,"line":1244},[431,11470,11471],{"class":654},"        if",[431,11473,8704],{"class":441},[431,11475,8883],{"class":654},[431,11477,2254],{"class":437},[431,11479,8102],{"class":441},[431,11481,11482,11485,11487,11489],{"class":433,"line":1985},[431,11483,11484],{"class":437},"            print",[431,11486,442],{"class":441},[431,11488,11381],{"class":445},[431,11490,449],{"class":441},[431,11492,11493,11495],{"class":433,"line":2041},[431,11494,10575],{"class":654},[431,11496,8102],{"class":441},[431,11498,11499,11501,11503,11505],{"class":433,"line":4018},[431,11500,11353],{"class":437},[431,11502,442],{"class":441},[431,11504,11398],{"class":445},[431,11506,449],{"class":441},[431,11508,11509],{"class":433,"line":4030},[431,11510,1662],{"emptyLinePlaceholder":393},[431,11512,11513,11515,11517],{"class":433,"line":4419},[431,11514,11409],{"class":441},[431,11516,971],{"class":437},[431,11518,449],{"class":441},[431,11520,11521],{"class":433,"line":4436},[431,11522,11418],{"class":455},[415,11524,11525],{},"Теперь второй if вложен в первый, а else на одном уровне с первым и противопоставляется ему.",[632,11527,11529],{"id":11528},"оператор-match","Оператор match",[415,11531,11532],{},"Многие языки в дополнение к условной конструкции if включают в себя switch.\nС выходом версии Python 3.10 также был добавлен оператор с аналогичной функциональностью — match.",[458,11534,8664,11536],{"id":11535},"оператор-match-1",[428,11537,11538],{},"match",[415,11540,8664,11541,11543],{},[800,11542,11538],{}," — это специализированная версия if, которую создали для особых ситуаций.\nНапример, ее нужно использовать там, где есть цепочка if else с проверками на равенство:",[422,11545,11547],{"className":424,"code":11546,"language":396,"meta":426,"style":426},"if status == 'processing':\n    # Делаем раз\nelif status == 'paid':\n    # Делаем два\nelif status == 'new':\n    # Делаем три\nelse:\n    # Делаем четыре\n",[428,11548,11549,11563,11568,11581,11586,11599,11604,11610],{"__ignoreMap":426},[431,11550,11551,11553,11556,11558,11561],{"class":433,"line":434},[431,11552,10399],{"class":654},[431,11554,11555],{"class":441}," status ",[431,11557,8409],{"class":654},[431,11559,11560],{"class":445}," 'processing'",[431,11562,8102],{"class":441},[431,11564,11565],{"class":433,"line":452},[431,11566,11567],{"class":455},"    # Делаем раз\n",[431,11569,11570,11572,11574,11576,11579],{"class":433,"line":578},[431,11571,10736],{"class":654},[431,11573,11555],{"class":441},[431,11575,8409],{"class":654},[431,11577,11578],{"class":445}," 'paid'",[431,11580,8102],{"class":441},[431,11582,11583],{"class":433,"line":584},[431,11584,11585],{"class":455},"    # Делаем два\n",[431,11587,11588,11590,11592,11594,11597],{"class":433,"line":1244},[431,11589,10736],{"class":654},[431,11591,11555],{"class":441},[431,11593,8409],{"class":654},[431,11595,11596],{"class":445}," 'new'",[431,11598,8102],{"class":441},[431,11600,11601],{"class":433,"line":1985},[431,11602,11603],{"class":455},"    # Делаем три\n",[431,11605,11606,11608],{"class":433,"line":2041},[431,11607,10515],{"class":654},[431,11609,8102],{"class":441},[431,11611,11612],{"class":433,"line":4018},[431,11613,11614],{"class":455},"    # Делаем четыре\n",[415,11616,11617],{},"У этой составной проверки есть одна отличительная черта: каждая ветка здесь — это проверка значения переменной status.\nОператор match позволяет записать этот код короче и выразительнее:",[422,11619,11621],{"className":424,"code":11620,"language":396,"meta":426,"style":426},"match status:\n    case 'processing':  # status == 'processing'\n        # Делаем раз\n    case 'paid':  # status == 'paid'\n        # Делаем два\n    case 'new':  # status == 'new'\n        # Делаем три\n    case _:  # else\n        # Делаем четыре\n",[428,11622,11623,11630,11643,11648,11659,11664,11675,11680,11690],{"__ignoreMap":426},[431,11624,11625,11627],{"class":433,"line":434},[431,11626,11538],{"class":654},[431,11628,11629],{"class":441}," status:\n",[431,11631,11632,11635,11637,11640],{"class":433,"line":452},[431,11633,11634],{"class":654},"    case",[431,11636,11560],{"class":445},[431,11638,11639],{"class":441},":  ",[431,11641,11642],{"class":455},"# status == 'processing'\n",[431,11644,11645],{"class":433,"line":578},[431,11646,11647],{"class":455},"        # Делаем раз\n",[431,11649,11650,11652,11654,11656],{"class":433,"line":584},[431,11651,11634],{"class":654},[431,11653,11578],{"class":445},[431,11655,11639],{"class":441},[431,11657,11658],{"class":455},"# status == 'paid'\n",[431,11660,11661],{"class":433,"line":1244},[431,11662,11663],{"class":455},"        # Делаем два\n",[431,11665,11666,11668,11670,11672],{"class":433,"line":1985},[431,11667,11634],{"class":654},[431,11669,11596],{"class":445},[431,11671,11639],{"class":441},[431,11673,11674],{"class":455},"# status == 'new'\n",[431,11676,11677],{"class":433,"line":2041},[431,11678,11679],{"class":455},"        # Делаем три\n",[431,11681,11682,11684,11687],{"class":433,"line":4018},[431,11683,11634],{"class":654},[431,11685,11686],{"class":441}," _:  ",[431,11688,11689],{"class":455},"# else\n",[431,11691,11692],{"class":433,"line":4030},[431,11693,11694],{"class":455},"        # Делаем четыре\n",[415,11696,11697],{},"С точки зрения количества элементов match — это сложная конструкция. Она состоит из таких элементов:",[697,11699,11700,11703],{},[700,11701,11702],{},"Внешнее описание, в которое входит ключевое слово match. Это переменная, по значениям которой match и будет выбирать поведение",[700,11704,11705,11706,11709],{},"Конструкции ",[800,11707,11708],{},"case",", внутри которых описывается поведение для разных значений рассматриваемой переменной.",[415,11711,11712,11713,11716],{},"Каждый case соответствует if в примере выше. При этом ",[800,11714,11715],{},"case _"," — это особая ситуация, которая соответствует ветке else в условных конструкциях.\nКак и else, указывать case _ необязательно. Внутри match допустим только тот синтаксис, который показан выше.\nДругими словами, там можно использовать case. А вот внутри каждого case ситуация другая.\nЗдесь можно выполнять любой произвольный код:",[422,11718,11720],{"className":424,"code":11719,"language":396,"meta":426,"style":426},"match count:\n    case 1:\n        # Делаем что-то полезное\n    case 2:\n        # Делаем что-то полезное\n    case _:\n        # Что-то делаем\n",[428,11721,11722,11729,11737,11742,11750,11754,11761],{"__ignoreMap":426},[431,11723,11724,11726],{"class":433,"line":434},[431,11725,11538],{"class":654},[431,11727,11728],{"class":441}," count:\n",[431,11730,11731,11733,11735],{"class":433,"line":452},[431,11732,11634],{"class":654},[431,11734,1032],{"class":437},[431,11736,8102],{"class":441},[431,11738,11739],{"class":433,"line":578},[431,11740,11741],{"class":455},"        # Делаем что-то полезное\n",[431,11743,11744,11746,11748],{"class":433,"line":584},[431,11745,11634],{"class":654},[431,11747,689],{"class":437},[431,11749,8102],{"class":441},[431,11751,11752],{"class":433,"line":1244},[431,11753,11741],{"class":455},[431,11755,11756,11758],{"class":433,"line":1985},[431,11757,11634],{"class":654},[431,11759,11760],{"class":441}," _:\n",[431,11762,11763],{"class":433,"line":2041},[431,11764,11765],{"class":455},"        # Что-то делаем\n",[458,11767,11769],{"id":11768},"два-способа-вернуть-результат","Два способа вернуть результат",[415,11771,11772],{},"Иногда результат, полученный внутри case — это конец выполнения функции, которая содержит match.\nВ таком случае его нужно как-то вернуть наружу. Есть два способа для решения этой задачи:",[1588,11774,11775],{},[700,11776,11777],{},"Создать переменную перед match, заполнить ее в case и затем в конце вернуть значение этой переменной наружу:",[422,11779,11781],{"className":424,"code":11780,"language":396,"meta":426,"style":426},"def count_items(count):\n    # Объявляем переменную\n    result = ''\n\n    # Заполняем\n    match count:\n        case 1:\n            result = 'one'\n        case 2:\n            result = 'two'\n        case _:\n            result = None\n\n    # Возвращаем\n    return result \n",[428,11782,11783,11793,11798,11806,11810,11815,11822,11831,11841,11849,11858,11864,11873,11877,11882],{"__ignoreMap":426},[431,11784,11785,11787,11790],{"class":433,"line":434},[431,11786,6330],{"class":654},[431,11788,11789],{"class":6333}," count_items",[431,11791,11792],{"class":441},"(count):\n",[431,11794,11795],{"class":433,"line":452},[431,11796,11797],{"class":455},"    # Объявляем переменную\n",[431,11799,11800,11802,11804],{"class":433,"line":578},[431,11801,6796],{"class":441},[431,11803,1189],{"class":654},[431,11805,9805],{"class":445},[431,11807,11808],{"class":433,"line":584},[431,11809,1662],{"emptyLinePlaceholder":393},[431,11811,11812],{"class":433,"line":1244},[431,11813,11814],{"class":455},"    # Заполняем\n",[431,11816,11817,11820],{"class":433,"line":1985},[431,11818,11819],{"class":654},"    match",[431,11821,11728],{"class":441},[431,11823,11824,11827,11829],{"class":433,"line":2041},[431,11825,11826],{"class":654},"        case",[431,11828,1032],{"class":437},[431,11830,8102],{"class":441},[431,11832,11833,11836,11838],{"class":433,"line":4018},[431,11834,11835],{"class":441},"            result ",[431,11837,1189],{"class":654},[431,11839,11840],{"class":445}," 'one'\n",[431,11842,11843,11845,11847],{"class":433,"line":4030},[431,11844,11826],{"class":654},[431,11846,689],{"class":437},[431,11848,8102],{"class":441},[431,11850,11851,11853,11855],{"class":433,"line":4419},[431,11852,11835],{"class":441},[431,11854,1189],{"class":654},[431,11856,11857],{"class":445}," 'two'\n",[431,11859,11860,11862],{"class":433,"line":4436},[431,11861,11826],{"class":654},[431,11863,11760],{"class":441},[431,11865,11866,11868,11870],{"class":433,"line":4446},[431,11867,11835],{"class":441},[431,11869,1189],{"class":654},[431,11871,11872],{"class":437}," None\n",[431,11874,11875],{"class":433,"line":4451},[431,11876,1662],{"emptyLinePlaceholder":393},[431,11878,11879],{"class":433,"line":4086},[431,11880,11881],{"class":455},"    # Возвращаем\n",[431,11883,11884,11886],{"class":433,"line":4477},[431,11885,6599],{"class":654},[431,11887,6812],{"class":441},[1588,11889,11890],{"start":452},[700,11891,11892],{},"Вместо создания переменной при работе с case можно делать обычный возврат из функции:",[422,11894,11896],{"className":424,"code":11895,"language":396,"meta":426,"style":426},"def count_items(count):\n    match count:\n        case 1:\n            return 'one'\n        case 2:\n            return 'two'\n        case _:\n            return None \n",[428,11897,11898,11906,11912,11920,11927,11935,11941,11947],{"__ignoreMap":426},[431,11899,11900,11902,11904],{"class":433,"line":434},[431,11901,6330],{"class":654},[431,11903,11789],{"class":6333},[431,11905,11792],{"class":441},[431,11907,11908,11910],{"class":433,"line":452},[431,11909,11819],{"class":654},[431,11911,11728],{"class":441},[431,11913,11914,11916,11918],{"class":433,"line":578},[431,11915,11826],{"class":654},[431,11917,1032],{"class":437},[431,11919,8102],{"class":441},[431,11921,11922,11925],{"class":433,"line":584},[431,11923,11924],{"class":654},"            return",[431,11926,11840],{"class":445},[431,11928,11929,11931,11933],{"class":433,"line":1244},[431,11930,11826],{"class":654},[431,11932,689],{"class":437},[431,11934,8102],{"class":441},[431,11936,11937,11939],{"class":433,"line":1985},[431,11938,11924],{"class":654},[431,11940,11857],{"class":445},[431,11942,11943,11945],{"class":433,"line":2041},[431,11944,11826],{"class":654},[431,11946,11760],{"class":441},[431,11948,11949,11951],{"class":433,"line":4018},[431,11950,11924],{"class":654},[431,11952,11872],{"class":437},[415,11954,11955],{},"Оператор match хоть и встречается в коде, но технически всегда можно обойтись без него.\nЕго главное достоинство в том, что он лучше выражает намерение программиста, когда нужно проверять конкретные значения переменной.\nХотя кода и стало физически чуть больше, читать его легче, в отличие от блоков elif.",[458,11957,11959],{"id":11958},"несколько-значений-в-case","Несколько значений в case",[415,11961,11962],{},"С помощью оператора | (или) можно объединять несколько значений в один case, чтобы выполнять одну и ту же операцию ветвления. Например:",[422,11964,11966],{"className":424,"code":11965,"language":396,"meta":426,"style":426},"def match_input(input):\n    match input:\n        case 'start' | 'begin':\n            print('Starting...')\n        case 'stop' | 'end':\n            print('Stopping...')\n        case 'pause':\n            print('Pausing...')\n        case _:\n            print('Invalid input')\n\nmatch_input('begin')  # => Starting...\nmatch_input('stop')  # => Stopping...\nmatch_input('pause')  # => Pausing...\nmatch_input('test')  # => Invalid input\n",[428,11967,11968,11978,11987,12002,12013,12027,12038,12047,12058,12064,12075,12079,12092,12104,12116],{"__ignoreMap":426},[431,11969,11970,11972,11975],{"class":433,"line":434},[431,11971,6330],{"class":654},[431,11973,11974],{"class":6333}," match_input",[431,11976,11977],{"class":441},"(input):\n",[431,11979,11980,11982,11985],{"class":433,"line":452},[431,11981,11819],{"class":654},[431,11983,11984],{"class":437}," input",[431,11986,8102],{"class":441},[431,11988,11989,11991,11994,11997,12000],{"class":433,"line":578},[431,11990,11826],{"class":654},[431,11992,11993],{"class":445}," 'start'",[431,11995,11996],{"class":654}," |",[431,11998,11999],{"class":445}," 'begin'",[431,12001,8102],{"class":441},[431,12003,12004,12006,12008,12011],{"class":433,"line":584},[431,12005,11484],{"class":437},[431,12007,442],{"class":441},[431,12009,12010],{"class":445},"'Starting...'",[431,12012,449],{"class":441},[431,12014,12015,12017,12020,12022,12025],{"class":433,"line":1244},[431,12016,11826],{"class":654},[431,12018,12019],{"class":445}," 'stop'",[431,12021,11996],{"class":654},[431,12023,12024],{"class":445}," 'end'",[431,12026,8102],{"class":441},[431,12028,12029,12031,12033,12036],{"class":433,"line":1985},[431,12030,11484],{"class":437},[431,12032,442],{"class":441},[431,12034,12035],{"class":445},"'Stopping...'",[431,12037,449],{"class":441},[431,12039,12040,12042,12045],{"class":433,"line":2041},[431,12041,11826],{"class":654},[431,12043,12044],{"class":445}," 'pause'",[431,12046,8102],{"class":441},[431,12048,12049,12051,12053,12056],{"class":433,"line":4018},[431,12050,11484],{"class":437},[431,12052,442],{"class":441},[431,12054,12055],{"class":445},"'Pausing...'",[431,12057,449],{"class":441},[431,12059,12060,12062],{"class":433,"line":4030},[431,12061,11826],{"class":654},[431,12063,11760],{"class":441},[431,12065,12066,12068,12070,12073],{"class":433,"line":4419},[431,12067,11484],{"class":437},[431,12069,442],{"class":441},[431,12071,12072],{"class":445},"'Invalid input'",[431,12074,449],{"class":441},[431,12076,12077],{"class":433,"line":4436},[431,12078,1662],{"emptyLinePlaceholder":393},[431,12080,12081,12084,12087,12089],{"class":433,"line":4446},[431,12082,12083],{"class":441},"match_input(",[431,12085,12086],{"class":445},"'begin'",[431,12088,526],{"class":441},[431,12090,12091],{"class":455},"# => Starting...\n",[431,12093,12094,12096,12099,12101],{"class":433,"line":4451},[431,12095,12083],{"class":441},[431,12097,12098],{"class":445},"'stop'",[431,12100,526],{"class":441},[431,12102,12103],{"class":455},"# => Stopping...\n",[431,12105,12106,12108,12111,12113],{"class":433,"line":4086},[431,12107,12083],{"class":441},[431,12109,12110],{"class":445},"'pause'",[431,12112,526],{"class":441},[431,12114,12115],{"class":455},"# => Pausing...\n",[431,12117,12118,12120,12123,12125],{"class":433,"line":4477},[431,12119,12083],{"class":441},[431,12121,12122],{"class":445},"'test'",[431,12124,526],{"class":441},[431,12126,12127],{"class":455},"# => Invalid input\n",[12129,12130,12132],"h5",{"id":12131},"проверка-типов","Проверка типов",[415,12134,12135],{},"В операторе case можно использовать функции приведения типов, например, str(), int(). Это нужно, чтобы проверять тип переменной после match:",[422,12137,12139],{"className":424,"code":12138,"language":396,"meta":426,"style":426},"def get_type(val):\n    match val:\n        case str(val):\n            print(f'It is a string: {val}')\n        case int(val):\n            print(f'It is an integer: {val}')\n        case _:\n            print(\"I don't know this type\")\n\nget_type('hello')  # => It is a string: hello\nget_type(123)  # => It is an integer: 123\nget_type(None)  # => I don't know this type\n",[428,12140,12141,12151,12158,12166,12188,12196,12217,12223,12234,12238,12251,12263],{"__ignoreMap":426},[431,12142,12143,12145,12148],{"class":433,"line":434},[431,12144,6330],{"class":654},[431,12146,12147],{"class":6333}," get_type",[431,12149,12150],{"class":441},"(val):\n",[431,12152,12153,12155],{"class":433,"line":452},[431,12154,11819],{"class":654},[431,12156,12157],{"class":441}," val:\n",[431,12159,12160,12162,12164],{"class":433,"line":578},[431,12161,11826],{"class":654},[431,12163,2485],{"class":437},[431,12165,12150],{"class":441},[431,12167,12168,12170,12172,12174,12177,12179,12182,12184,12186],{"class":433,"line":584},[431,12169,11484],{"class":437},[431,12171,442],{"class":441},[431,12173,2990],{"class":654},[431,12175,12176],{"class":445},"'It is a string: ",[431,12178,2996],{"class":437},[431,12180,12181],{"class":441},"val",[431,12183,3002],{"class":437},[431,12185,2993],{"class":445},[431,12187,449],{"class":441},[431,12189,12190,12192,12194],{"class":433,"line":1244},[431,12191,11826],{"class":654},[431,12193,4312],{"class":437},[431,12195,12150],{"class":441},[431,12197,12198,12200,12202,12204,12207,12209,12211,12213,12215],{"class":433,"line":1985},[431,12199,11484],{"class":437},[431,12201,442],{"class":441},[431,12203,2990],{"class":654},[431,12205,12206],{"class":445},"'It is an integer: ",[431,12208,2996],{"class":437},[431,12210,12181],{"class":441},[431,12212,3002],{"class":437},[431,12214,2993],{"class":445},[431,12216,449],{"class":441},[431,12218,12219,12221],{"class":433,"line":2041},[431,12220,11826],{"class":654},[431,12222,11760],{"class":441},[431,12224,12225,12227,12229,12232],{"class":433,"line":4018},[431,12226,11484],{"class":437},[431,12228,442],{"class":441},[431,12230,12231],{"class":445},"\"I don't know this type\"",[431,12233,449],{"class":441},[431,12235,12236],{"class":433,"line":4030},[431,12237,1662],{"emptyLinePlaceholder":393},[431,12239,12240,12243,12246,12248],{"class":433,"line":4419},[431,12241,12242],{"class":441},"get_type(",[431,12244,12245],{"class":445},"'hello'",[431,12247,526],{"class":441},[431,12249,12250],{"class":455},"# => It is a string: hello\n",[431,12252,12253,12255,12258,12260],{"class":433,"line":4436},[431,12254,12242],{"class":441},[431,12256,12257],{"class":437},"123",[431,12259,526],{"class":441},[431,12261,12262],{"class":455},"# => It is an integer: 123\n",[431,12264,12265,12267,12269,12271],{"class":433,"line":4446},[431,12266,12242],{"class":441},[431,12268,7922],{"class":437},[431,12270,526],{"class":441},[431,12272,12273],{"class":455},"# => I don't know this type\n",[12129,12275,12277],{"id":12276},"определение-переменной-в-case","Определение переменной в case",[415,12279,12280],{},"Если определить переменную после case, то ей будет присвоено значение, которое связано с соответствием с match:",[422,12282,12284],{"className":424,"code":12283,"language":396,"meta":426,"style":426},"def match_input(input):\n    match input:\n        case 'start':\n            message = 'Starting...'\n        case 'stop':\n            message = 'Stopping...'\n        case 'pause':\n            message = 'Pausing...'\n        case _:\n            message = 'Invalid input'\n\n    print(message)\n\nmatch_input('start')  # => Starting...\nmatch_input('stop')  # => Stopping...\nmatch_input('pause')  # => Pausing...\nmatch_input('test')  # => Invalid input\n",[428,12285,12286,12294,12302,12310,12320,12328,12337,12345,12354,12360,12369,12373,12380,12384,12395,12405,12415],{"__ignoreMap":426},[431,12287,12288,12290,12292],{"class":433,"line":434},[431,12289,6330],{"class":654},[431,12291,11974],{"class":6333},[431,12293,11977],{"class":441},[431,12295,12296,12298,12300],{"class":433,"line":452},[431,12297,11819],{"class":654},[431,12299,11984],{"class":437},[431,12301,8102],{"class":441},[431,12303,12304,12306,12308],{"class":433,"line":578},[431,12305,11826],{"class":654},[431,12307,11993],{"class":445},[431,12309,8102],{"class":441},[431,12311,12312,12315,12317],{"class":433,"line":584},[431,12313,12314],{"class":441},"            message ",[431,12316,1189],{"class":654},[431,12318,12319],{"class":445}," 'Starting...'\n",[431,12321,12322,12324,12326],{"class":433,"line":1244},[431,12323,11826],{"class":654},[431,12325,12019],{"class":445},[431,12327,8102],{"class":441},[431,12329,12330,12332,12334],{"class":433,"line":1985},[431,12331,12314],{"class":441},[431,12333,1189],{"class":654},[431,12335,12336],{"class":445}," 'Stopping...'\n",[431,12338,12339,12341,12343],{"class":433,"line":2041},[431,12340,11826],{"class":654},[431,12342,12044],{"class":445},[431,12344,8102],{"class":441},[431,12346,12347,12349,12351],{"class":433,"line":4018},[431,12348,12314],{"class":441},[431,12350,1189],{"class":654},[431,12352,12353],{"class":445}," 'Pausing...'\n",[431,12355,12356,12358],{"class":433,"line":4030},[431,12357,11826],{"class":654},[431,12359,11760],{"class":441},[431,12361,12362,12364,12366],{"class":433,"line":4419},[431,12363,12314],{"class":441},[431,12365,1189],{"class":654},[431,12367,12368],{"class":445}," 'Invalid input'\n",[431,12370,12371],{"class":433,"line":4436},[431,12372,1662],{"emptyLinePlaceholder":393},[431,12374,12375,12377],{"class":433,"line":4446},[431,12376,6357],{"class":437},[431,12378,12379],{"class":441},"(message)\n",[431,12381,12382],{"class":433,"line":4451},[431,12383,1662],{"emptyLinePlaceholder":393},[431,12385,12386,12388,12391,12393],{"class":433,"line":4086},[431,12387,12083],{"class":441},[431,12389,12390],{"class":445},"'start'",[431,12392,526],{"class":441},[431,12394,12091],{"class":455},[431,12396,12397,12399,12401,12403],{"class":433,"line":4477},[431,12398,12083],{"class":441},[431,12400,12098],{"class":445},[431,12402,526],{"class":441},[431,12404,12103],{"class":455},[431,12406,12407,12409,12411,12413],{"class":433,"line":4482},[431,12408,12083],{"class":441},[431,12410,12110],{"class":445},[431,12412,526],{"class":441},[431,12414,12115],{"class":455},[431,12416,12417,12419,12421,12423],{"class":433,"line":4488},[431,12418,12083],{"class":441},[431,12420,12122],{"class":445},[431,12422,526],{"class":441},[431,12424,12127],{"class":455},[415,12426,12427],{},"Здесь обязательно нужно задать \"дефолтный\" случай — _.\nТак как если ни один case не соответствует входному значению, переменная message не будет определена.\nЭто вызовет ошибку NameError.",[415,12429,1849,12430,1853,12432,1857],{},[800,12431,1852],{},[800,12433,1856],{},[1859,12435],{},[1862,12437,12438],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":426,"searchDepth":452,"depth":1244,"links":12440},[12441],{"id":8393,"depth":452,"text":322,"children":12442},[12443,12444,12445,12446,12454,12460,12469,12470],{"id":8438,"depth":584,"text":8439},{"id":8567,"depth":584,"text":8568},{"id":8632,"depth":584,"text":8633},{"id":8833,"depth":578,"text":8834,"children":12447},[12448,12450,12452],{"id":9251,"depth":584,"text":12449},"И and",{"id":9312,"depth":584,"text":12451},"ИЛИ or",{"id":9365,"depth":584,"text":12453},"Отрицание not",{"id":9586,"depth":578,"text":9587,"children":12455},[12456,12457,12458,12459],{"id":9593,"depth":584,"text":9594},{"id":9895,"depth":584,"text":9896},{"id":10169,"depth":584,"text":10170},{"id":10280,"depth":584,"text":10281},{"id":10388,"depth":578,"text":10389,"children":12461},[12462,12464,12466,12468],{"id":10395,"depth":584,"text":12463},"Если if",{"id":10511,"depth":584,"text":12465},"Иначе else",{"id":10732,"depth":584,"text":12467},"Конструкция else + if = elif",{"id":11067,"depth":584,"text":11068},{"id":11244,"depth":578,"text":11245},{"id":11528,"depth":578,"text":11529,"children":12471},[12472,12473,12474],{"id":11535,"depth":584,"text":11529},{"id":11768,"depth":584,"text":11769},{"id":11958,"depth":584,"text":11959,"children":12475},[12476,12477],{"id":12131,"depth":1244,"text":12132},{"id":12276,"depth":1244,"text":12277},"2025-02-13","Логические операции. Условные конструкции","images\u002Fblog\u002Fpython\u002Fst8\u002Fimg.png",{},40,{"title":322,"description":12479},"0b4VIHtrZsEAOMLEHdj8L4RpF0CZ1KDCvcc0KuHYLHg",{"id":12486,"title":326,"author":12487,"body":12489,"date":15012,"description":15013,"extension":1887,"image":15014,"meta":15015,"minRead":15016,"navigation":393,"num":4030,"path":327,"seo":15017,"stem":328,"__hash__":15018},"python\u002Fblog\u002Fpython\u002Fst9.md",{"name":402,"avatar":12488},{"src":404,"alt":405},{"type":407,"value":12490,"toc":14984},[12491,12495,12498,12502,12509,12587,12590,12616,12619,12731,12738,12743,12754,12760,12908,12912,12915,12972,12975,12993,12996,13000,13015,13037,13041,13044,13048,13051,13054,13135,13138,13248,13251,13335,13338,13342,13345,13366,13369,13462,13465,13529,13533,13536,13540,13543,13645,13655,13659,13662,13665,13673,13822,13825,13869,13872,13876,13879,13923,13926,14025,14028,14032,14039,14042,14053,14060,14063,14113,14120,14134,14137,14141,14144,14152,14155,14321,14324,14330,14333,14397,14400,14451,14454,14460,14463,14466,14477,14480,14527,14530,14583,14586,14589,14643,14647,14650,14707,14710,14813,14816,14970,14973,14979,14981],[410,12492,12494],{"id":12493},"циклические-конструкции","Циклические конструкции",[415,12496,12497],{},"Программы, которые мы пишем, со временем становятся сложнее и объемнее.\nОни еще далеки от реальных программ, хотя уже заставляют напрячься.\nВ этой статье рассматриваются одни из самых сложных базовых тем в программировании — циклы.",[458,12499,12501],{"id":12500},"зачем-нужны-циклы","Зачем нужны циклы",[415,12503,12504,12505,12508],{},"Прикладные программы помогают управлять сотрудниками, финансами и могут развлекать.\nНесмотря на различия, они выполняют заложенные в них алгоритмы, которые похожи.\nАлгоритм — это последовательность действий, которая приводит к ожидаемому результату.\nПредставим, что у нас есть книга, и мы хотим найти в ней конкретную фразу.\nСаму фразу мы помним, но не знаем, на какой она странице.\nНам придется последовательно просматривать страницы до тех пор, пока не найдем нужную.\nАлгоритм включает логические проверки и перебор страниц.\nКоличество страниц, которое придется посмотреть, заранее неизвестно.\nНо сам процесс просмотра повторяется одинаковым образом.\nЧтобы выполнять повторяющиеся действия, нужны циклы.\nКаждый повтор называется ",[800,12506,12507],{},"итерацией",".\nНапишем функцию с простым циклом, который будет n раз выводить на экран строку 'Python':",[422,12510,12512],{"className":424,"code":12511,"language":396,"meta":426,"style":426},"def print_python(n):\n    counter = 0\n    while counter \u003C n:\n        print('Python')\n        counter += 1\n\nprint_hello(2)\n# => Python\n# => Python\n",[428,12513,12514,12524,12533,12546,12556,12566,12570,12579,12583],{"__ignoreMap":426},[431,12515,12516,12518,12521],{"class":433,"line":434},[431,12517,6330],{"class":654},[431,12519,12520],{"class":6333}," print_python",[431,12522,12523],{"class":441},"(n):\n",[431,12525,12526,12529,12531],{"class":433,"line":452},[431,12527,12528],{"class":441},"    counter ",[431,12530,1189],{"class":654},[431,12532,3459],{"class":437},[431,12534,12535,12538,12541,12543],{"class":433,"line":578},[431,12536,12537],{"class":654},"    while",[431,12539,12540],{"class":441}," counter ",[431,12542,8521],{"class":654},[431,12544,12545],{"class":441}," n:\n",[431,12547,12548,12550,12552,12554],{"class":433,"line":584},[431,12549,11353],{"class":437},[431,12551,442],{"class":441},[431,12553,1304],{"class":445},[431,12555,449],{"class":441},[431,12557,12558,12561,12564],{"class":433,"line":1244},[431,12559,12560],{"class":441},"        counter ",[431,12562,12563],{"class":654},"+=",[431,12565,3916],{"class":437},[431,12567,12568],{"class":433,"line":1985},[431,12569,1662],{"emptyLinePlaceholder":393},[431,12571,12572,12575,12577],{"class":433,"line":2041},[431,12573,12574],{"class":441},"print_hello(",[431,12576,651],{"class":437},[431,12578,449],{"class":441},[431,12580,12581],{"class":433,"line":4018},[431,12582,1770],{"class":455},[431,12584,12585],{"class":433,"line":4030},[431,12586,1770],{"class":455},[415,12588,12589],{},"Теперь проанализируем пример функции с циклом, который выводит на экран числа от одного до числа-аргумента:",[422,12591,12593],{"className":424,"code":12592,"language":396,"meta":426,"style":426},"print_numbers(3)\n# => 1\n# => 2\n# => 3\n",[428,12594,12595,12604,12608,12612],{"__ignoreMap":426},[431,12596,12597,12600,12602],{"class":433,"line":434},[431,12598,12599],{"class":441},"print_numbers(",[431,12601,971],{"class":437},[431,12603,449],{"class":441},[431,12605,12606],{"class":433,"line":452},[431,12607,791],{"class":455},[431,12609,12610],{"class":433,"line":578},[431,12611,3518],{"class":455},[431,12613,12614],{"class":433,"line":584},[431,12615,4513],{"class":455},[415,12617,12618],{},"Эту функцию невозможно реализовать с помощью уже изученных средств, так как количество выводов на экран заранее неизвестно.\nА с циклами проблем не будет:",[422,12620,12622],{"className":424,"code":12621,"language":396,"meta":426,"style":426},"def print_numbers(last_number):\n    # i — сокращение от index (порядковый номер)\n    # используется по общему соглашению во множестве языков\n    # как счетчик цикла\n    i = 1\n    while i \u003C= last_number:\n        print(i)\n        i = i + 1\n    print('finished!')\n\nprint_numbers(3)\n# => 1\n# => 2\n# => 3\n# => finished!\n",[428,12623,12624,12634,12639,12644,12649,12658,12671,12678,12691,12702,12706,12714,12718,12722,12726],{"__ignoreMap":426},[431,12625,12626,12628,12631],{"class":433,"line":434},[431,12627,6330],{"class":654},[431,12629,12630],{"class":6333}," print_numbers",[431,12632,12633],{"class":441},"(last_number):\n",[431,12635,12636],{"class":433,"line":452},[431,12637,12638],{"class":455},"    # i — сокращение от index (порядковый номер)\n",[431,12640,12641],{"class":433,"line":578},[431,12642,12643],{"class":455},"    # используется по общему соглашению во множестве языков\n",[431,12645,12646],{"class":433,"line":584},[431,12647,12648],{"class":455},"    # как счетчик цикла\n",[431,12650,12651,12654,12656],{"class":433,"line":1244},[431,12652,12653],{"class":441},"    i ",[431,12655,1189],{"class":654},[431,12657,3916],{"class":437},[431,12659,12660,12662,12665,12668],{"class":433,"line":1985},[431,12661,12537],{"class":654},[431,12663,12664],{"class":441}," i ",[431,12666,12667],{"class":654},"\u003C=",[431,12669,12670],{"class":441}," last_number:\n",[431,12672,12673,12675],{"class":433,"line":2041},[431,12674,11353],{"class":437},[431,12676,12677],{"class":441},"(i)\n",[431,12679,12680,12683,12685,12687,12689],{"class":433,"line":4018},[431,12681,12682],{"class":441},"        i ",[431,12684,1189],{"class":654},[431,12686,12664],{"class":441},[431,12688,802],{"class":654},[431,12690,3916],{"class":437},[431,12692,12693,12695,12697,12700],{"class":433,"line":4030},[431,12694,6357],{"class":437},[431,12696,442],{"class":441},[431,12698,12699],{"class":445},"'finished!'",[431,12701,449],{"class":441},[431,12703,12704],{"class":433,"line":4419},[431,12705,1662],{"emptyLinePlaceholder":393},[431,12707,12708,12710,12712],{"class":433,"line":4436},[431,12709,12599],{"class":441},[431,12711,971],{"class":437},[431,12713,449],{"class":441},[431,12715,12716],{"class":433,"line":4446},[431,12717,791],{"class":455},[431,12719,12720],{"class":433,"line":4451},[431,12721,3518],{"class":455},[431,12723,12724],{"class":433,"line":4086},[431,12725,4513],{"class":455},[431,12727,12728],{"class":433,"line":4477},[431,12729,12730],{"class":455},"# => finished!\n",[632,12732,12734,12735],{"id":12733},"цикл-while","Цикл ",[428,12736,12737],{},"while",[415,12739,12734,12740,12742],{},[428,12741,12737],{}," состоит из трех элементов:",[697,12744,12745,12748,12751],{},[700,12746,12747],{},"Ключевое слово while",[700,12749,12750],{},"Предикат — условие, которое указывается после while и вычисляется на каждой итерации",[700,12752,12753],{},"Блок кода — тело цикла",[415,12755,12756,12757,12759],{},"Каждое выполнение тела цикла называется ",[800,12758,12507],{},".\nВ примере выше print_numbers(3) вызвал три итерации, на каждой из которых была выведена на экран переменная i.\nКонструкция читается так: «делать то, что указано в теле цикла, пока истинно условие i \u003C= last_number».\nРазберем работу этого кода для вызова print_numbers(3):",[422,12761,12763],{"className":424,"code":12762,"language":396,"meta":426,"style":426},"# Инициализируется i\ni = 1\n\n# Предикат возвращает true, поэтому выполняется тело цикла\nwhile 1 \u003C= 3\n# print(1)\n# i = 1 + 1\n\n# Закончилось тело цикла, поэтому происходит возврат в начало\nwhile 2 \u003C= 3\n# print(2)\n# i = 2 + 1\n\n# Закончилось тело цикла, поэтому происходит возврат в начало\nwhile 3 \u003C= 3\n# print(3)\n# i = 3 + 1\n\n# Предикат возвращает false, поэтому выполнение переходит за цикл\nwhile 4 \u003C= 3\n\n# print('finished!')\n# На этом этапе i равен 4, но он нам уже не нужен\n# Функция завершается\n",[428,12764,12765,12770,12778,12782,12787,12798,12803,12808,12812,12817,12827,12832,12837,12841,12845,12855,12860,12865,12869,12875,12885,12890,12896,12902],{"__ignoreMap":426},[431,12766,12767],{"class":433,"line":434},[431,12768,12769],{"class":455},"# Инициализируется i\n",[431,12771,12772,12774,12776],{"class":433,"line":452},[431,12773,3454],{"class":441},[431,12775,1189],{"class":654},[431,12777,3916],{"class":437},[431,12779,12780],{"class":433,"line":578},[431,12781,1662],{"emptyLinePlaceholder":393},[431,12783,12784],{"class":433,"line":584},[431,12785,12786],{"class":455},"# Предикат возвращает true, поэтому выполняется тело цикла\n",[431,12788,12789,12791,12793,12796],{"class":433,"line":1244},[431,12790,12737],{"class":654},[431,12792,1032],{"class":437},[431,12794,12795],{"class":654}," \u003C=",[431,12797,1197],{"class":437},[431,12799,12800],{"class":433,"line":1985},[431,12801,12802],{"class":455},"# print(1)\n",[431,12804,12805],{"class":433,"line":2041},[431,12806,12807],{"class":455},"# i = 1 + 1\n",[431,12809,12810],{"class":433,"line":4018},[431,12811,1662],{"emptyLinePlaceholder":393},[431,12813,12814],{"class":433,"line":4030},[431,12815,12816],{"class":455},"# Закончилось тело цикла, поэтому происходит возврат в начало\n",[431,12818,12819,12821,12823,12825],{"class":433,"line":4419},[431,12820,12737],{"class":654},[431,12822,689],{"class":437},[431,12824,12795],{"class":654},[431,12826,1197],{"class":437},[431,12828,12829],{"class":433,"line":4436},[431,12830,12831],{"class":455},"# print(2)\n",[431,12833,12834],{"class":433,"line":4446},[431,12835,12836],{"class":455},"# i = 2 + 1\n",[431,12838,12839],{"class":433,"line":4451},[431,12840,1662],{"emptyLinePlaceholder":393},[431,12842,12843],{"class":433,"line":4086},[431,12844,12816],{"class":455},[431,12846,12847,12849,12851,12853],{"class":433,"line":4477},[431,12848,12737],{"class":654},[431,12850,900],{"class":437},[431,12852,12795],{"class":654},[431,12854,1197],{"class":437},[431,12856,12857],{"class":433,"line":4482},[431,12858,12859],{"class":455},"# print(3)\n",[431,12861,12862],{"class":433,"line":4488},[431,12863,12864],{"class":455},"# i = 3 + 1\n",[431,12866,12867],{"class":433,"line":4505},[431,12868,1662],{"emptyLinePlaceholder":393},[431,12870,12872],{"class":433,"line":12871},19,[431,12873,12874],{"class":455},"# Предикат возвращает false, поэтому выполнение переходит за цикл\n",[431,12876,12877,12879,12881,12883],{"class":433,"line":2874},[431,12878,12737],{"class":654},[431,12880,905],{"class":437},[431,12882,12795],{"class":654},[431,12884,1197],{"class":437},[431,12886,12888],{"class":433,"line":12887},21,[431,12889,1662],{"emptyLinePlaceholder":393},[431,12891,12893],{"class":433,"line":12892},22,[431,12894,12895],{"class":455},"# print('finished!')\n",[431,12897,12899],{"class":433,"line":12898},23,[431,12900,12901],{"class":455},"# На этом этапе i равен 4, но он нам уже не нужен\n",[431,12903,12905],{"class":433,"line":12904},24,[431,12906,12907],{"class":455},"# Функция завершается\n",[458,12909,12911],{"id":12910},"завершение-цикла","Завершение цикла",[415,12913,12914],{},"Процесс, который порождает цикл, должен остановиться. За это отвечает программист.\nОбычно задача сводится к введению переменной — счетчика цикла.\nСначала он инициализируется — ему задается начальное значение.\nВ нашем примере это строчка i = 1. Затем в условии цикла проверяется, не достиг ли счетчик своего предельного значения.\nПредельное значение в примере определяется аргументом функции.\nЕсли условие цикла ложно, то тело не выполняется и интерпретатор двигается дальше — работает с инструкциями после цикла.\nЕсли условие цикла истинно, то выполняется тело, в котором находится элемент остановки — изменение значения счетчика.\nОбычно его делают в конце тела, и это изменение — место, где нельзя обойтись без переменной.\nВ примере выше за изменение отвечает строчка i = i + 1. На этом моменте новички много ошибаются.\nНапример, можно забыть увеличить значение счетчика или неправильно проверить его в предикате.\nЭто приведет к зацикливанию — цикл будет работать бесконечно, и программа никогда не остановится.\nВ таком случае ее нужно завершить принудительно.",[422,12916,12918],{"className":424,"code":12917,"language":396,"meta":426,"style":426},"def print_numbers(last_number):\n    i = 1\n    # Этот цикл никогда не остановится\n    # и будет печатать всегда одно значение\n    while i \u003C= last_number:\n        print(i)\n    print('finished!')\n",[428,12919,12920,12928,12936,12941,12946,12956,12962],{"__ignoreMap":426},[431,12921,12922,12924,12926],{"class":433,"line":434},[431,12923,6330],{"class":654},[431,12925,12630],{"class":6333},[431,12927,12633],{"class":441},[431,12929,12930,12932,12934],{"class":433,"line":452},[431,12931,12653],{"class":441},[431,12933,1189],{"class":654},[431,12935,3916],{"class":437},[431,12937,12938],{"class":433,"line":578},[431,12939,12940],{"class":455},"    # Этот цикл никогда не остановится\n",[431,12942,12943],{"class":433,"line":584},[431,12944,12945],{"class":455},"    # и будет печатать всегда одно значение\n",[431,12947,12948,12950,12952,12954],{"class":433,"line":1244},[431,12949,12537],{"class":654},[431,12951,12664],{"class":441},[431,12953,12667],{"class":654},[431,12955,12670],{"class":441},[431,12957,12958,12960],{"class":433,"line":1985},[431,12959,11353],{"class":437},[431,12961,12677],{"class":441},[431,12963,12964,12966,12968,12970],{"class":433,"line":2041},[431,12965,6357],{"class":437},[431,12967,442],{"class":441},[431,12969,12699],{"class":445},[431,12971,449],{"class":441},[415,12973,12974],{},"В некоторых случаях бесконечные циклы полезны.\nНе будем пока рассматривать такие ситуации, но код в таких циклах начинается так:",[422,12976,12978],{"className":424,"code":12977,"language":396,"meta":426,"style":426},"while True:\n    # Что-то делаем\n",[428,12979,12980,12988],{"__ignoreMap":426},[431,12981,12982,12984,12986],{"class":433,"line":434},[431,12983,12737],{"class":654},[431,12985,9395],{"class":437},[431,12987,8102],{"class":441},[431,12989,12990],{"class":433,"line":452},[431,12991,12992],{"class":455},"    # Что-то делаем\n",[415,12994,12995],{},"Без циклов невозможно обойтись, когда алгоритм решения задачи требует повторения каких-то действий и количество этих операций заранее неизвестно.",[458,12997,12999],{"id":12998},"синтаксический-сахар","Синтаксический сахар",[415,13001,13002,13003,13006,13007,13010,13011,13014],{},"Конструкции типа ",[428,13004,13005],{},"x = x + 1"," часто используются в Python, поэтому создатели языка добавили сокращенный вариант: ",[428,13008,13009],{},"x += 1",".\nОни отличаются только способом записи. Интерпретатор превратит сокращенную конструкцию в развернутую.\nТакие сокращения называют ",[1355,13012,13013],{},"синтаксическим сахаром",", потому что они делают процесс написания кода немного проще и приятнее.\nСуществуют сокращенные формы для всех арифметических операций и для конкатенации строк:",[697,13016,13017,13022,13027,13032],{},[700,13018,13019],{},[428,13020,13021],{},"x = x + 1 → x += 1",[700,13023,13024],{},[428,13025,13026],{},"x = x - 1 → x -= 1",[700,13028,13029],{},[428,13030,13031],{},"x = x * 2 → x *= 2",[700,13033,13034],{},[428,13035,13036],{},"x = x \u002F 1 → x \u002F= 1",[632,13038,13040],{"id":13039},"агрегация-данных","Агрегация данных",[415,13042,13043],{},"Отдельный класс задач, который не обходится без циклов, называется агрегированием данных.\nК таким задачам относятся: поиск максимального или минимального значения, суммы, среднего арифметического.\nВ этом случае результат зависит от всего набора данных.\nЧтобы рассчитать сумму, нужно сложить все числа, а чтобы вычислить максимальное, нужно их сравнить.\nС такими задачами хорошо знакомы бухгалтеры и маркетологи. Они работают с таблицами Microsoft Excel или Google Sheets.\nРазберем, как агрегация применяется к числам и строкам.",[458,13045,13047],{"id":13046},"числа","Числа",[415,13049,13050],{},"Допустим, нам нужно найти суммы набора чисел.\nРеализуем функцию, которая складывает числа в указанном диапазоне, включая границы.\nДиапазон — ряд чисел от конкретного начала до определенного конца.\nНапример, диапазон [1, 10] включает целые числа от одного до десяти.",[415,13052,13053],{},"Пример:",[422,13055,13057],{"className":424,"code":13056,"language":396,"meta":426,"style":426},"sum_numbers_from_range(5, 7)  # 5 + 6 + 7 = 18\nsum_numbers_from_range(1, 2)  # 1 + 2 = 3\n\n# [1, 1] — диапазон с одинаковым началом и концом — тоже диапазон\n# Он включает одно число — саму границу диапазона\nsum_numbers_from_range(1, 1)      # 1\nsum_numbers_from_range(100, 100)  # 100\n",[428,13058,13059,13075,13090,13094,13099,13104,13120],{"__ignoreMap":426},[431,13060,13061,13064,13066,13068,13070,13072],{"class":433,"line":434},[431,13062,13063],{"class":441},"sum_numbers_from_range(",[431,13065,856],{"class":437},[431,13067,4846],{"class":441},[431,13069,781],{"class":437},[431,13071,526],{"class":441},[431,13073,13074],{"class":455},"# 5 + 6 + 7 = 18\n",[431,13076,13077,13079,13081,13083,13085,13087],{"class":433,"line":452},[431,13078,13063],{"class":441},[431,13080,1192],{"class":437},[431,13082,4846],{"class":441},[431,13084,651],{"class":437},[431,13086,526],{"class":441},[431,13088,13089],{"class":455},"# 1 + 2 = 3\n",[431,13091,13092],{"class":433,"line":578},[431,13093,1662],{"emptyLinePlaceholder":393},[431,13095,13096],{"class":433,"line":584},[431,13097,13098],{"class":455},"# [1, 1] — диапазон с одинаковым началом и концом — тоже диапазон\n",[431,13100,13101],{"class":433,"line":1244},[431,13102,13103],{"class":455},"# Он включает одно число — саму границу диапазона\n",[431,13105,13106,13108,13110,13112,13114,13117],{"class":433,"line":1985},[431,13107,13063],{"class":441},[431,13109,1192],{"class":437},[431,13111,4846],{"class":441},[431,13113,1192],{"class":437},[431,13115,13116],{"class":441},")      ",[431,13118,13119],{"class":455},"# 1\n",[431,13121,13122,13124,13126,13128,13130,13132],{"class":433,"line":2041},[431,13123,13063],{"class":441},[431,13125,2249],{"class":437},[431,13127,4846],{"class":441},[431,13129,2249],{"class":437},[431,13131,526],{"class":441},[431,13133,13134],{"class":455},"# 100\n",[415,13136,13137],{},"Чтобы реализовать такой код, понадобится цикл, так как сложение чисел — это итеративный процесс, то есть повторяется для каждого числа.\nКоличество итераций зависит от размера диапазона.\nПосмотрите код ниже:",[422,13139,13141],{"className":424,"code":13140,"language":396,"meta":426,"style":426},"def sum_numbers_from_range(start, finish):\n    # Технически можно менять start\n    # Но входные аргументы нужно оставлять в исходном значении\n    # Это сделает код проще для анализа\n    i = start\n    sum = 0  # Инициализация суммы\n    while i \u003C= finish:  # Двигаемся до конца диапазона\n        sum = sum + i   # Считаем сумму для каждого числа\n        i = i + 1       # Переходим к следующему числу в диапазоне\n    # Возвращаем получившийся результат\n    return sum\n",[428,13142,13143,13153,13158,13163,13168,13177,13189,13203,13221,13236,13241],{"__ignoreMap":426},[431,13144,13145,13147,13150],{"class":433,"line":434},[431,13146,6330],{"class":654},[431,13148,13149],{"class":6333}," sum_numbers_from_range",[431,13151,13152],{"class":441},"(start, finish):\n",[431,13154,13155],{"class":433,"line":452},[431,13156,13157],{"class":455},"    # Технически можно менять start\n",[431,13159,13160],{"class":433,"line":578},[431,13161,13162],{"class":455},"    # Но входные аргументы нужно оставлять в исходном значении\n",[431,13164,13165],{"class":433,"line":584},[431,13166,13167],{"class":455},"    # Это сделает код проще для анализа\n",[431,13169,13170,13172,13174],{"class":433,"line":1244},[431,13171,12653],{"class":441},[431,13173,1189],{"class":654},[431,13175,13176],{"class":441}," start\n",[431,13178,13179,13182,13184,13186],{"class":433,"line":1985},[431,13180,13181],{"class":437},"    sum",[431,13183,2146],{"class":654},[431,13185,9744],{"class":437},[431,13187,13188],{"class":455},"  # Инициализация суммы\n",[431,13190,13191,13193,13195,13197,13200],{"class":433,"line":2041},[431,13192,12537],{"class":654},[431,13194,12664],{"class":441},[431,13196,12667],{"class":654},[431,13198,13199],{"class":441}," finish:  ",[431,13201,13202],{"class":455},"# Двигаемся до конца диапазона\n",[431,13204,13205,13208,13210,13213,13215,13218],{"class":433,"line":4018},[431,13206,13207],{"class":437},"        sum",[431,13209,2146],{"class":654},[431,13211,13212],{"class":437}," sum",[431,13214,655],{"class":654},[431,13216,13217],{"class":441}," i   ",[431,13219,13220],{"class":455},"# Считаем сумму для каждого числа\n",[431,13222,13223,13225,13227,13229,13231,13233],{"class":433,"line":4030},[431,13224,12682],{"class":441},[431,13226,1189],{"class":654},[431,13228,12664],{"class":441},[431,13230,802],{"class":654},[431,13232,1032],{"class":437},[431,13234,13235],{"class":455},"       # Переходим к следующему числу в диапазоне\n",[431,13237,13238],{"class":433,"line":4419},[431,13239,13240],{"class":455},"    # Возвращаем получившийся результат\n",[431,13242,13243,13245],{"class":433,"line":4436},[431,13244,6599],{"class":654},[431,13246,13247],{"class":437}," sum\n",[415,13249,13250],{},"Структура цикла здесь стандартная: есть счетчик, который инициализируется начальным значением диапазона, цикл с условием остановки при достижении конца диапазона и изменении значения счетчика в конце тела цикла.\nКоличество итераций в таком цикле равно finish - start + 1. Для диапазона [5, 7] — это 7 - 5 + 1, то есть три итерации.\nГлавное отличие от обычной обработки — логика вычисления результата.\nВ задачах на агрегацию всегда есть переменная, которая хранит внутри себя результат работы цикла. В коде выше это sum.\nОна изменяется на каждой итерации цикла — прибавляется следующее число в диапазоне: sum = sum + i.\nЭтот процесс выглядит так:",[422,13252,13254],{"className":424,"code":13253,"language":396,"meta":426,"style":426},"# Для вызова sum_numbers_from_range(2, 5)\nsum = 0\nsum = sum + 2  # 2\nsum = sum + 3  # 5\nsum = sum + 4  # 9\nsum = sum + 5  # 14\n# 14 – результат сложения чисел в диапазоне [2, 5]\n",[428,13255,13256,13261,13270,13285,13300,13315,13330],{"__ignoreMap":426},[431,13257,13258],{"class":433,"line":434},[431,13259,13260],{"class":455},"# Для вызова sum_numbers_from_range(2, 5)\n",[431,13262,13263,13266,13268],{"class":433,"line":452},[431,13264,13265],{"class":437},"sum",[431,13267,2146],{"class":654},[431,13269,3459],{"class":437},[431,13271,13272,13274,13276,13278,13280,13282],{"class":433,"line":578},[431,13273,13265],{"class":437},[431,13275,2146],{"class":654},[431,13277,13212],{"class":437},[431,13279,655],{"class":654},[431,13281,689],{"class":437},[431,13283,13284],{"class":455},"  # 2\n",[431,13286,13287,13289,13291,13293,13295,13297],{"class":433,"line":584},[431,13288,13265],{"class":437},[431,13290,2146],{"class":654},[431,13292,13212],{"class":437},[431,13294,655],{"class":654},[431,13296,900],{"class":437},[431,13298,13299],{"class":455},"  # 5\n",[431,13301,13302,13304,13306,13308,13310,13312],{"class":433,"line":1244},[431,13303,13265],{"class":437},[431,13305,2146],{"class":654},[431,13307,13212],{"class":437},[431,13309,655],{"class":654},[431,13311,905],{"class":437},[431,13313,13314],{"class":455},"  # 9\n",[431,13316,13317,13319,13321,13323,13325,13327],{"class":433,"line":1985},[431,13318,13265],{"class":437},[431,13320,2146],{"class":654},[431,13322,13212],{"class":437},[431,13324,655],{"class":654},[431,13326,910],{"class":437},[431,13328,13329],{"class":455},"  # 14\n",[431,13331,13332],{"class":433,"line":2041},[431,13333,13334],{"class":455},"# 14 – результат сложения чисел в диапазоне [2, 5]\n",[415,13336,13337],{},"У переменной sum есть начальное значение — с него начинается любая повторяющаяся операция. В примере выше — это 0.\nВ математике есть понятие нейтральный элемент, и у каждой операции он свой.\nОперация с этим элементом не изменяет то значение, над которым работает.\nНапример, при сложении любое число плюс ноль дает само число. При вычитании — то же самое.\nУ конкатенации тоже есть нейтральный элемент — это пустая строка: '' + 'one' будет 'one'.\nДалее разберем, как агрегация применяется к строкам.",[458,13339,13341],{"id":13340},"строки","Строки",[415,13343,13344],{},"Агрегация строк — это такие задачи, в которых заранее неизвестно, что содержат строки и какой у них размер.\nПредставьте функцию, которая умеет умножать строку — повторяет ее указанное количество раз:",[422,13346,13348],{"className":424,"code":13347,"language":396,"meta":426,"style":426},"repeat('python', 3)  # 'pythonpythonpython'\n",[428,13349,13350],{"__ignoreMap":426},[431,13351,13352,13355,13357,13359,13361,13363],{"class":433,"line":434},[431,13353,13354],{"class":441},"repeat(",[431,13356,7113],{"class":445},[431,13358,4846],{"class":441},[431,13360,971],{"class":437},[431,13362,526],{"class":441},[431,13364,13365],{"class":455},"# 'pythonpythonpython'\n",[415,13367,13368],{},"Принцип работы этой функции — в цикле происходит «наращивание» строки указанное количество раз:",[422,13370,13372],{"className":424,"code":13371,"language":396,"meta":426,"style":426},"def repeat(text, times):\n    # Нейтральный элемент для строк — пустая строка\n    result = ''\n    i = 1\n\n    while i \u003C= times:\n        # Каждый раз добавляем строку к результату\n        result = result + text\n        i = i + 1\n\n    return result\n",[428,13373,13374,13384,13389,13397,13405,13409,13420,13425,13440,13452,13456],{"__ignoreMap":426},[431,13375,13376,13378,13381],{"class":433,"line":434},[431,13377,6330],{"class":654},[431,13379,13380],{"class":6333}," repeat",[431,13382,13383],{"class":441},"(text, times):\n",[431,13385,13386],{"class":433,"line":452},[431,13387,13388],{"class":455},"    # Нейтральный элемент для строк — пустая строка\n",[431,13390,13391,13393,13395],{"class":433,"line":578},[431,13392,6796],{"class":441},[431,13394,1189],{"class":654},[431,13396,9805],{"class":445},[431,13398,13399,13401,13403],{"class":433,"line":584},[431,13400,12653],{"class":441},[431,13402,1189],{"class":654},[431,13404,3916],{"class":437},[431,13406,13407],{"class":433,"line":1244},[431,13408,1662],{"emptyLinePlaceholder":393},[431,13410,13411,13413,13415,13417],{"class":433,"line":1985},[431,13412,12537],{"class":654},[431,13414,12664],{"class":441},[431,13416,12667],{"class":654},[431,13418,13419],{"class":441}," times:\n",[431,13421,13422],{"class":433,"line":2041},[431,13423,13424],{"class":455},"        # Каждый раз добавляем строку к результату\n",[431,13426,13427,13430,13432,13435,13437],{"class":433,"line":4018},[431,13428,13429],{"class":441},"        result ",[431,13431,1189],{"class":654},[431,13433,13434],{"class":441}," result ",[431,13436,802],{"class":654},[431,13438,13439],{"class":441}," text\n",[431,13441,13442,13444,13446,13448,13450],{"class":433,"line":4030},[431,13443,12682],{"class":441},[431,13445,1189],{"class":654},[431,13447,12664],{"class":441},[431,13449,802],{"class":654},[431,13451,3916],{"class":437},[431,13453,13454],{"class":433,"line":4419},[431,13455,1662],{"emptyLinePlaceholder":393},[431,13457,13458,13460],{"class":433,"line":4436},[431,13459,6599],{"class":654},[431,13461,6812],{"class":441},[415,13463,13464],{},"Распишем выполнение этого кода по шагам:",[422,13466,13468],{"className":424,"code":13467,"language":396,"meta":426,"style":426},"# Для вызова repeat('python', 3)\nresult = ''\nresult = result + 'python'  # python\nresult = result + 'python'  # pythonpython\nresult = result + 'python'  # pythonpythonpython\n",[428,13469,13470,13475,13483,13499,13514],{"__ignoreMap":426},[431,13471,13472],{"class":433,"line":434},[431,13473,13474],{"class":455},"# Для вызова repeat('python', 3)\n",[431,13476,13477,13479,13481],{"class":433,"line":452},[431,13478,4799],{"class":441},[431,13480,1189],{"class":654},[431,13482,9805],{"class":445},[431,13484,13485,13487,13489,13491,13493,13496],{"class":433,"line":578},[431,13486,4799],{"class":441},[431,13488,1189],{"class":654},[431,13490,13434],{"class":441},[431,13492,802],{"class":654},[431,13494,13495],{"class":445}," 'python'",[431,13497,13498],{"class":455},"  # python\n",[431,13500,13501,13503,13505,13507,13509,13511],{"class":433,"line":584},[431,13502,4799],{"class":441},[431,13504,1189],{"class":654},[431,13506,13434],{"class":441},[431,13508,802],{"class":654},[431,13510,13495],{"class":445},[431,13512,13513],{"class":455},"  # pythonpython\n",[431,13515,13516,13518,13520,13522,13524,13526],{"class":433,"line":1244},[431,13517,4799],{"class":441},[431,13519,1189],{"class":654},[431,13521,13434],{"class":441},[431,13523,802],{"class":654},[431,13525,13495],{"class":445},[431,13527,13528],{"class":455},"  # pythonpythonpython\n",[632,13530,13532],{"id":13531},"обход-строк","Обход строк",[415,13534,13535],{},"С помощью циклов не только обрабатывают числа, но работают и со строками.\nНапример, можно получить конкретный символ по его индексу, а также формировать строки в циклах.",[458,13537,13539],{"id":13538},"получить-символ-по-индексу","Получить символ по индексу",[415,13541,13542],{},"Ниже пример кода, который печатает каждую букву каждого слова на отдельной строке:",[422,13544,13546],{"className":424,"code":13545,"language":396,"meta":426,"style":426},"def print_name_by_symbol(name):\n    i = 0\n    # Такая проверка будет выполняться до конца строки,\n    # включая последний символ. Его индекс len(name) - 1.\n    while i \u003C len(name):\n        # Обращаемся к символу по индексу\n        print(name[i])\n        i += 1\n\nname = 'Alex'\nprint_name_by_symbol(name)\n# => 'A'\n# => 'l'\n# => 'e'\n# => 'x'\n",[428,13547,13548,13558,13566,13571,13576,13588,13593,13600,13608,13612,13620,13625,13630,13635,13640],{"__ignoreMap":426},[431,13549,13550,13552,13555],{"class":433,"line":434},[431,13551,6330],{"class":654},[431,13553,13554],{"class":6333}," print_name_by_symbol",[431,13556,13557],{"class":441},"(name):\n",[431,13559,13560,13562,13564],{"class":433,"line":452},[431,13561,12653],{"class":441},[431,13563,1189],{"class":654},[431,13565,3459],{"class":437},[431,13567,13568],{"class":433,"line":578},[431,13569,13570],{"class":455},"    # Такая проверка будет выполняться до конца строки,\n",[431,13572,13573],{"class":433,"line":584},[431,13574,13575],{"class":455},"    # включая последний символ. Его индекс len(name) - 1.\n",[431,13577,13578,13580,13582,13584,13586],{"class":433,"line":1244},[431,13579,12537],{"class":654},[431,13581,12664],{"class":441},[431,13583,8521],{"class":654},[431,13585,4804],{"class":437},[431,13587,13557],{"class":441},[431,13589,13590],{"class":433,"line":1985},[431,13591,13592],{"class":455},"        # Обращаемся к символу по индексу\n",[431,13594,13595,13597],{"class":433,"line":2041},[431,13596,11353],{"class":437},[431,13598,13599],{"class":441},"(name[i])\n",[431,13601,13602,13604,13606],{"class":433,"line":4018},[431,13603,12682],{"class":441},[431,13605,12563],{"class":654},[431,13607,3916],{"class":437},[431,13609,13610],{"class":433,"line":4030},[431,13611,1662],{"emptyLinePlaceholder":393},[431,13613,13614,13616,13618],{"class":433,"line":4419},[431,13615,3287],{"class":441},[431,13617,1189],{"class":654},[431,13619,5905],{"class":445},[431,13621,13622],{"class":433,"line":4436},[431,13623,13624],{"class":441},"print_name_by_symbol(name)\n",[431,13626,13627],{"class":433,"line":4446},[431,13628,13629],{"class":455},"# => 'A'\n",[431,13631,13632],{"class":433,"line":4451},[431,13633,13634],{"class":455},"# => 'l'\n",[431,13636,13637],{"class":433,"line":4086},[431,13638,13639],{"class":455},"# => 'e'\n",[431,13641,13642],{"class":433,"line":4477},[431,13643,13644],{"class":455},"# => 'x'\n",[415,13646,13647,13648,9379,13651,13654],{},"Главное в этом коде — поставить правильное условие в while.\nЭто можно сделать двумя способами: ",[428,13649,13650],{},"i \u003C len(name)",[428,13652,13653],{},"i \u003C= len(name) - 1"," — они приведут к одному результату.",[458,13656,13658],{"id":13657},"как-формировать-строки-в-циклах","Как формировать строки в циклах",[415,13660,13661],{},"Еще циклы можно использовать, чтобы формировать строки. Подобная задача часто встречается в веб-программировании.\nОна сводится к обычной агрегации, когда применяется интерполяция или конкатенация.\nПереворот строки — алгоритмическая задача, которую задают на собеседованиях.\nПравильный способ перевернуть строку — использовать функцию из стандартной библиотеки. Но важно знать, как ее реализовать.",[415,13663,13664],{},"Один из алгоритмов выглядит так:",[697,13666,13667,13670],{},[700,13668,13669],{},"Строим новую строку;",[700,13671,13672],{},"Перебираем символы исходной строки в обратном порядке.",[422,13674,13676],{"className":424,"code":13675,"language":396,"meta":426,"style":426},"def reverse_string(string):\n    index = len(string) - 1\n    reversed_string = ''\n\n    while index >= 0:\n        current_char = string[index]\n        reversed_string = reversed_string + current_char\n        # То же самое через интерполяцию\n        # reversed_string = f'{reversed_string}{current_char}'\n        index = index - 1\n\n    return reversed_string\n\nreverse_string('Game Of Thrones')  # 'senorhT fO emaG'\n# Проверка нейтрального элемента\nreverse_string('')  # ''\n",[428,13677,13678,13687,13703,13712,13716,13729,13739,13754,13759,13764,13777,13781,13788,13792,13805,13810],{"__ignoreMap":426},[431,13679,13680,13682,13685],{"class":433,"line":434},[431,13681,6330],{"class":654},[431,13683,13684],{"class":6333}," reverse_string",[431,13686,7080],{"class":441},[431,13688,13689,13692,13694,13696,13699,13701],{"class":433,"line":452},[431,13690,13691],{"class":441},"    index ",[431,13693,1189],{"class":654},[431,13695,4804],{"class":437},[431,13697,13698],{"class":441},"(string) ",[431,13700,853],{"class":654},[431,13702,3916],{"class":437},[431,13704,13705,13708,13710],{"class":433,"line":578},[431,13706,13707],{"class":441},"    reversed_string ",[431,13709,1189],{"class":654},[431,13711,9805],{"class":445},[431,13713,13714],{"class":433,"line":584},[431,13715,1662],{"emptyLinePlaceholder":393},[431,13717,13718,13720,13723,13725,13727],{"class":433,"line":1244},[431,13719,12537],{"class":654},[431,13721,13722],{"class":441}," index ",[431,13724,9105],{"class":654},[431,13726,9744],{"class":437},[431,13728,8102],{"class":441},[431,13730,13731,13734,13736],{"class":433,"line":1985},[431,13732,13733],{"class":441},"        current_char ",[431,13735,1189],{"class":654},[431,13737,13738],{"class":441}," string[index]\n",[431,13740,13741,13744,13746,13749,13751],{"class":433,"line":2041},[431,13742,13743],{"class":441},"        reversed_string ",[431,13745,1189],{"class":654},[431,13747,13748],{"class":441}," reversed_string ",[431,13750,802],{"class":654},[431,13752,13753],{"class":441}," current_char\n",[431,13755,13756],{"class":433,"line":4018},[431,13757,13758],{"class":455},"        # То же самое через интерполяцию\n",[431,13760,13761],{"class":433,"line":4030},[431,13762,13763],{"class":455},"        # reversed_string = f'{reversed_string}{current_char}'\n",[431,13765,13766,13769,13771,13773,13775],{"class":433,"line":4419},[431,13767,13768],{"class":441},"        index ",[431,13770,1189],{"class":654},[431,13772,13722],{"class":441},[431,13774,853],{"class":654},[431,13776,3916],{"class":437},[431,13778,13779],{"class":433,"line":4436},[431,13780,1662],{"emptyLinePlaceholder":393},[431,13782,13783,13785],{"class":433,"line":4446},[431,13784,6599],{"class":654},[431,13786,13787],{"class":441}," reversed_string\n",[431,13789,13790],{"class":433,"line":4451},[431,13791,1662],{"emptyLinePlaceholder":393},[431,13793,13794,13797,13800,13802],{"class":433,"line":4086},[431,13795,13796],{"class":441},"reverse_string(",[431,13798,13799],{"class":445},"'Game Of Thrones'",[431,13801,526],{"class":441},[431,13803,13804],{"class":455},"# 'senorhT fO emaG'\n",[431,13806,13807],{"class":433,"line":4477},[431,13808,13809],{"class":455},"# Проверка нейтрального элемента\n",[431,13811,13812,13814,13817,13819],{"class":433,"line":4482},[431,13813,13796],{"class":441},[431,13815,13816],{"class":445},"''",[431,13818,526],{"class":441},[431,13820,13821],{"class":455},"# ''\n",[415,13823,13824],{},"Разберем функцию построчно:",[697,13826,13827,13833,13839,13845,13851,13857,13863],{},[700,13828,13829,13832],{},[428,13830,13831],{},"index = len(string) - 1"," — записываем в новую переменную индекс последнего символа строки (индексы начинаются с нуля);",[700,13834,13835,13838],{},[428,13836,13837],{},"reversed_string = ''"," — инициализируем строку, куда будем записывать результат;",[700,13840,13841,13844],{},[428,13842,13843],{},"while index >= 0:"," — условие: повторяем тело цикла, пока текущий индекс не дошел до 0 — до первого символа;",[700,13846,13847,13850],{},[428,13848,13849],{},"current_char = string[index]"," — берем из строки символ по текущему индексу;",[700,13852,13853,13856],{},[428,13854,13855],{},"reversed_string = reversed_string + current_char"," — записываем в строку-результат новое значение: текущая строка-результат + новый символ;",[700,13858,13859,13862],{},[428,13860,13861],{},"index = index - 1"," — обновляем счетчик;",[700,13864,13865,13868],{},[428,13866,13867],{},"return reversed_string"," — когда цикл завершился, возвращаем строку-результат.",[415,13870,13871],{},"Советуем скопировать эту функцию и поэкспериментировать с ней.\nРаботая со строками, программисты часто допускают ошибку — выходят за границы строки.\nЕсли неправильно подобрать начальное значение счетчика или допустить ошибку в предикате цикла, функция может обращаться к несуществующему символу.\nОсобенно часто забывают, что индекс последнего элемента всегда меньше на единицу размера строки.\nВ строках начальный индекс равен 0, значит, индекс последнего элемента — len(str) - 1.",[632,13873,13875],{"id":13874},"условия-внутри-цикла","Условия внутри цикла",[415,13877,13878],{},"В теле цикла, как и в теле функции, можно выполнять инструкции.\nПоэтому внутри цикла можно использовать все изученное ранее, например — условные конструкции.\nПредставьте функцию, которая считает, сколько раз входит буква в предложение. Пример ее работы:",[422,13880,13882],{"className":424,"code":13881,"language":396,"meta":426,"style":426},"count_chars('Fear cuts deeper than swords.', 'e')  # 4\n# Если вы ничего не нашли, то результат — 0 совпадений\ncount_chars('Sansa', 'y')  # 0\n",[428,13883,13884,13901,13906],{"__ignoreMap":426},[431,13885,13886,13889,13892,13894,13897,13899],{"class":433,"line":434},[431,13887,13888],{"class":441},"count_chars(",[431,13890,13891],{"class":445},"'Fear cuts deeper than swords.'",[431,13893,4846],{"class":441},[431,13895,13896],{"class":445},"'e'",[431,13898,526],{"class":441},[431,13900,7774],{"class":455},[431,13902,13903],{"class":433,"line":452},[431,13904,13905],{"class":455},"# Если вы ничего не нашли, то результат — 0 совпадений\n",[431,13907,13908,13910,13913,13915,13918,13920],{"class":433,"line":578},[431,13909,13888],{"class":441},[431,13911,13912],{"class":445},"'Sansa'",[431,13914,4846],{"class":441},[431,13916,13917],{"class":445},"'y'",[431,13919,526],{"class":441},[431,13921,13922],{"class":455},"# 0\n",[415,13924,13925],{},"Перед тем как посмотреть содержимое функции, подумайте: Является ли эта операция агрегацией? Какой будет проверка на вхождение символа?",[422,13927,13929],{"className":424,"code":13928,"language":396,"meta":426,"style":426},"def count_chars(string, char):\n    index = 0\n    count = 0\n    while index \u003C len(string):\n        if string[index] == char:\n            # Считаем только подходящие символы\n            count = count + 1\n        # Счетчик увеличивается в любом случае\n        index = index + 1\n    return count\n",[428,13930,13931,13941,13949,13958,13970,13982,13987,14001,14006,14018],{"__ignoreMap":426},[431,13932,13933,13935,13938],{"class":433,"line":434},[431,13934,6330],{"class":654},[431,13936,13937],{"class":6333}," count_chars",[431,13939,13940],{"class":441},"(string, char):\n",[431,13942,13943,13945,13947],{"class":433,"line":452},[431,13944,13691],{"class":441},[431,13946,1189],{"class":654},[431,13948,3459],{"class":437},[431,13950,13951,13954,13956],{"class":433,"line":578},[431,13952,13953],{"class":441},"    count ",[431,13955,1189],{"class":654},[431,13957,3459],{"class":437},[431,13959,13960,13962,13964,13966,13968],{"class":433,"line":584},[431,13961,12537],{"class":654},[431,13963,13722],{"class":441},[431,13965,8521],{"class":654},[431,13967,4804],{"class":437},[431,13969,7080],{"class":441},[431,13971,13972,13974,13977,13979],{"class":433,"line":1244},[431,13973,11471],{"class":654},[431,13975,13976],{"class":441}," string[index] ",[431,13978,8409],{"class":654},[431,13980,13981],{"class":441}," char:\n",[431,13983,13984],{"class":433,"line":1985},[431,13985,13986],{"class":455},"            # Считаем только подходящие символы\n",[431,13988,13989,13992,13994,13997,13999],{"class":433,"line":2041},[431,13990,13991],{"class":441},"            count ",[431,13993,1189],{"class":654},[431,13995,13996],{"class":441}," count ",[431,13998,802],{"class":654},[431,14000,3916],{"class":437},[431,14002,14003],{"class":433,"line":4018},[431,14004,14005],{"class":455},"        # Счетчик увеличивается в любом случае\n",[431,14007,14008,14010,14012,14014,14016],{"class":433,"line":4030},[431,14009,13768],{"class":441},[431,14011,1189],{"class":654},[431,14013,13722],{"class":441},[431,14015,802],{"class":654},[431,14017,3916],{"class":437},[431,14019,14020,14022],{"class":433,"line":4419},[431,14021,6599],{"class":654},[431,14023,14024],{"class":441}," count\n",[415,14026,14027],{},"Это агрегирующая задача.\nНесмотря на то, что функция считает не все символы, чтобы подсчитать сумму, приходится анализировать каждый символ.\nКлючевое отличие этого цикла от рассмотренных — внутри тела есть условие.\nПеременная count увеличивается только в том случае, когда рассматриваемый символ совпадает с ожидаемым.\nВ остальном — это типичная агрегатная функция, которая возвращает количество нужных символов.",[458,14029,14031],{"id":14030},"пограничные-случаи","Пограничные случаи",[415,14033,14034,14035,14038],{},"Функция my_substr(), которую вы реализовали ранее, содержит много ошибок.\nОна прошла проверку, так как в ней не было ",[1355,14036,14037],{},"пограничных случаев",".\nФункция работала с нормальными аргументами.",[415,14040,14041],{},"А теперь представим, что ей передали такие варианты длины:",[697,14043,14044,14047,14050],{},[700,14045,14046],{},"0;",[700,14048,14049],{},"Отрицательное число;",[700,14051,14052],{},"Число, которое превышает реальный размер строки;",[415,14054,14055,14056,14059],{},"Функция my_substr() не рассчитана на такие варианты.\nКод будет запускаться в разных ситуациях, с разными комбинациями условий и данных.\nНельзя быть уверенным, что аргументы всегда будут корректными, поэтому нужно учитывать все случаи.\n",[1355,14057,14058],{},"Ошибки в пограничных случаях — частая причина логических ошибок в программах.","\nПрограммисты всегда забывают что-нибудь учесть.\nТакие ошибки часто проявляются не сразу и могут долго не приводить к видимым проблемам.\nПрограмма продолжает работать, но в какой-то момент обнаруживается, что в результатах есть ошибки.\nЧасто причина в динамической типизации Python.\nВы научитесь справляться с такими ошибками с опытом.",[415,14061,14062],{},"Представим расширенную функцию my_substr().\nОна принимает три аргумента: строку, индекс и длину извлекаемой подстроки.\nФункция возвращает подстроку указанной длины, начиная с указанного индекса.\nПримеры вызова:",[422,14064,14066],{"className":424,"code":14065,"language":396,"meta":426,"style":426},"string = 'If I look back I am lost'\nprint(my_substr(string, 0, 1))  # => 'I'\nprint(my_substr(string, 3, 6))  # => 'I look'\n",[428,14067,14068,14078,14096],{"__ignoreMap":426},[431,14069,14070,14073,14075],{"class":433,"line":434},[431,14071,14072],{"class":441},"string ",[431,14074,1189],{"class":654},[431,14076,14077],{"class":445}," 'If I look back I am lost'\n",[431,14079,14080,14082,14085,14087,14089,14091,14093],{"class":433,"line":452},[431,14081,438],{"class":437},[431,14083,14084],{"class":441},"(my_substr(string, ",[431,14086,3302],{"class":437},[431,14088,4846],{"class":441},[431,14090,1192],{"class":437},[431,14092,986],{"class":441},[431,14094,14095],{"class":455},"# => 'I'\n",[431,14097,14098,14100,14102,14104,14106,14108,14110],{"class":433,"line":578},[431,14099,438],{"class":437},[431,14101,14084],{"class":441},[431,14103,971],{"class":437},[431,14105,4846],{"class":441},[431,14107,742],{"class":437},[431,14109,986],{"class":441},[431,14111,14112],{"class":455},"# => 'I look'\n",[415,14114,14115,14116,14119],{},"Какие ",[1355,14117,14118],{},"пограничные случаи"," стоит учитывать:",[697,14121,14122,14125,14128,14131],{},[700,14123,14124],{},"Отрицательная длина извлекаемой подстроки;",[700,14126,14127],{},"Отрицательный заданный индекс;",[700,14129,14130],{},"Заданный индекс выходит за границу всей строки;",[700,14132,14133],{},"Длина подстроки в сумме с заданным индексом выходит за границу всей строки.",[415,14135,14136],{},"Когда функция реализуется, каждый пограничный случай будет отдельным блоком кода. Скорее всего, он будет реализовываться с помощью if.\nЧтобы написать функцию my_substr() и защититься от этих случаев, стоит реализовать отдельную функцию, которая будет проверять аргументы на корректность.",[458,14138,14140],{"id":14139},"возврат-из-циклов","Возврат из циклов",[415,14142,14143],{},"Работа с циклами обычно сводится к двум сценариям:",[1588,14145,14146,14149],{},[700,14147,14148],{},"Агрегация. Накопление результата во время итераций и работа с ним после завершения цикла. Переворот строки относится к такому варианту",[700,14150,14151],{},"Выполнение цикла до достижения необходимого результата и выход. Например, задача поиска простых чисел — которые делятся без остатка только на себя и на единицу.",[415,14153,14154],{},"Рассмотрим алгоритм проверки простоты числа.\nБудем делить искомое число x на все числа из диапазона от двух до x - 1 и смотреть остаток.\nЕсли в этом диапазоне не найден делитель, который делит число x без остатка, значит, перед нами простое число.\nВ этом случае достаточно проверять числа не до x - 1, а до половины числа.\nНапример, 11 не делится на 2, 3, 4, 5. Но и дальше не будет делиться на числа больше своей половины.\nЗначит, можно оптимизировать алгоритм и проверять деление только до x \u002F 2:",[422,14156,14158],{"className":424,"code":14157,"language":396,"meta":426,"style":426},"def is_prime(number):\n    if number \u003C 2:\n        return False\n\n    divider = 2\n\n    while divider \u003C= number \u002F 2:\n        if number % divider == 0:\n            return False\n\n        divider += 1\n\n    return True\n\nprint(is_prime(1))  # => False\nprint(is_prime(2))  # => True\nprint(is_prime(3))  # => True\nprint(is_prime(4))  # => False\n",[428,14159,14160,14169,14181,14188,14192,14201,14205,14223,14239,14245,14249,14258,14262,14268,14272,14285,14297,14309],{"__ignoreMap":426},[431,14161,14162,14164,14167],{"class":433,"line":434},[431,14163,6330],{"class":654},[431,14165,14166],{"class":6333}," is_prime",[431,14168,8697],{"class":441},[431,14170,14171,14173,14175,14177,14179],{"class":433,"line":452},[431,14172,10438],{"class":654},[431,14174,8704],{"class":441},[431,14176,8521],{"class":654},[431,14178,689],{"class":437},[431,14180,8102],{"class":441},[431,14182,14183,14185],{"class":433,"line":578},[431,14184,10453],{"class":654},[431,14186,14187],{"class":437}," False\n",[431,14189,14190],{"class":433,"line":584},[431,14191,1662],{"emptyLinePlaceholder":393},[431,14193,14194,14197,14199],{"class":433,"line":1244},[431,14195,14196],{"class":441},"    divider ",[431,14198,1189],{"class":654},[431,14200,658],{"class":437},[431,14202,14203],{"class":433,"line":1985},[431,14204,1662],{"emptyLinePlaceholder":393},[431,14206,14207,14209,14212,14214,14216,14219,14221],{"class":433,"line":2041},[431,14208,12537],{"class":654},[431,14210,14211],{"class":441}," divider ",[431,14213,12667],{"class":654},[431,14215,8704],{"class":441},[431,14217,14218],{"class":654},"\u002F",[431,14220,689],{"class":437},[431,14222,8102],{"class":441},[431,14224,14225,14227,14229,14231,14233,14235,14237],{"class":433,"line":4018},[431,14226,11471],{"class":654},[431,14228,8704],{"class":441},[431,14230,8667],{"class":654},[431,14232,14211],{"class":441},[431,14234,8409],{"class":654},[431,14236,9744],{"class":437},[431,14238,8102],{"class":441},[431,14240,14241,14243],{"class":433,"line":4030},[431,14242,11924],{"class":654},[431,14244,14187],{"class":437},[431,14246,14247],{"class":433,"line":4419},[431,14248,1662],{"emptyLinePlaceholder":393},[431,14250,14251,14254,14256],{"class":433,"line":4436},[431,14252,14253],{"class":441},"        divider ",[431,14255,12563],{"class":654},[431,14257,3916],{"class":437},[431,14259,14260],{"class":433,"line":4446},[431,14261,1662],{"emptyLinePlaceholder":393},[431,14263,14264,14266],{"class":433,"line":4451},[431,14265,6599],{"class":654},[431,14267,10188],{"class":437},[431,14269,14270],{"class":433,"line":4086},[431,14271,1662],{"emptyLinePlaceholder":393},[431,14273,14274,14276,14279,14281,14283],{"class":433,"line":4477},[431,14275,438],{"class":437},[431,14277,14278],{"class":441},"(is_prime(",[431,14280,1192],{"class":437},[431,14282,986],{"class":441},[431,14284,8490],{"class":455},[431,14286,14287,14289,14291,14293,14295],{"class":433,"line":4482},[431,14288,438],{"class":437},[431,14290,14278],{"class":441},[431,14292,651],{"class":437},[431,14294,986],{"class":441},[431,14296,8470],{"class":455},[431,14298,14299,14301,14303,14305,14307],{"class":433,"line":4488},[431,14300,438],{"class":437},[431,14302,14278],{"class":441},[431,14304,971],{"class":437},[431,14306,986],{"class":441},[431,14308,8470],{"class":455},[431,14310,14311,14313,14315,14317,14319],{"class":433,"line":4505},[431,14312,438],{"class":437},[431,14314,14278],{"class":441},[431,14316,762],{"class":437},[431,14318,986],{"class":441},[431,14320,8490],{"class":455},[415,14322,14323],{},"Если быть честными, то для решения задачи хватит проверки чисел до значения квадратного корня number, но в нашем случае важно сосредоточиться на понимании работы с условиями внутри цикла.\nПредставим, что по алгоритму последовательного деления на числа до x \u002F 2 нашлось одно, которое делит без остатка.\nЗначит, переданный аргумент — не простое число, и дальнейшие вычисления не имеют смысла. В этом месте стоит возврат False.\nЕсли цикл отработал целиком, а число, которое делит без остатка, не нашлось, значит, число — простое.",[632,14325,12734,14327],{"id":14326},"цикл-for",[428,14328,14329],{},"for",[415,14331,14332],{},"Цикл while идеален для ситуаций, когда количество итераций неизвестно заранее — например, при поиске простого числа.\nКогда количество итераций известно, предпочтительнее использовать цикл for.\nПредставьте, что у нас есть ряд чисел от 0 до 9. Мы хотим сложить эти числа. Мы могли бы сделать это так:",[422,14334,14336],{"className":424,"code":14335,"language":396,"meta":426,"style":426},"sum = 0\ni = 0\nwhile i \u003C 10:\n    sum += i\n    i += 1\nprint(sum) # => 45\n",[428,14337,14338,14346,14354,14366,14376,14384],{"__ignoreMap":426},[431,14339,14340,14342,14344],{"class":433,"line":434},[431,14341,13265],{"class":437},[431,14343,2146],{"class":654},[431,14345,3459],{"class":437},[431,14347,14348,14350,14352],{"class":433,"line":452},[431,14349,3454],{"class":441},[431,14351,1189],{"class":654},[431,14353,3459],{"class":437},[431,14355,14356,14358,14360,14362,14364],{"class":433,"line":578},[431,14357,12737],{"class":654},[431,14359,12664],{"class":441},[431,14361,8521],{"class":654},[431,14363,2254],{"class":437},[431,14365,8102],{"class":441},[431,14367,14368,14370,14373],{"class":433,"line":584},[431,14369,13181],{"class":437},[431,14371,14372],{"class":654}," +=",[431,14374,14375],{"class":441}," i\n",[431,14377,14378,14380,14382],{"class":433,"line":1244},[431,14379,12653],{"class":441},[431,14381,12563],{"class":654},[431,14383,3916],{"class":437},[431,14385,14386,14388,14390,14392,14394],{"class":433,"line":1985},[431,14387,438],{"class":437},[431,14389,442],{"class":441},[431,14391,13265],{"class":437},[431,14393,1014],{"class":441},[431,14395,14396],{"class":455},"# => 45\n",[415,14398,14399],{},"Сначала мы устанавливаем начальную сумму 0.\nДалее запускается цикл, в котором переменная i начинает принимать значения начиная с 0 и доходя до 10.\nНа каждом шаге мы прибавляем значение i к нашей сумме и увеличиваем i на 1.\nКак только i становится равным 10, цикл заканчивается и программа выдаёт нам сумму всех чисел от 0 до 9 равную 45.\nТакой код мы можем переписать на цикл for:",[422,14401,14403],{"className":424,"code":14402,"language":396,"meta":426,"style":426},"sum = 0\nfor i in range(10):\n    sum += i\nprint(sum) # => 45\n",[428,14404,14405,14413,14431,14439],{"__ignoreMap":426},[431,14406,14407,14409,14411],{"class":433,"line":434},[431,14408,13265],{"class":437},[431,14410,2146],{"class":654},[431,14412,3459],{"class":437},[431,14414,14415,14417,14419,14422,14425,14427,14429],{"class":433,"line":452},[431,14416,14329],{"class":654},[431,14418,12664],{"class":441},[431,14420,14421],{"class":654},"in",[431,14423,14424],{"class":437}," range",[431,14426,442],{"class":441},[431,14428,3565],{"class":437},[431,14430,7381],{"class":441},[431,14432,14433,14435,14437],{"class":433,"line":578},[431,14434,13181],{"class":437},[431,14436,14372],{"class":654},[431,14438,14375],{"class":441},[431,14440,14441,14443,14445,14447,14449],{"class":433,"line":584},[431,14442,438],{"class":437},[431,14444,442],{"class":441},[431,14446,13265],{"class":437},[431,14448,1014],{"class":441},[431,14450,14396],{"class":455},[415,14452,14453],{},"Первый пример использует while, который продолжает работать пока i \u003C 10.\nВторой использует for и выполняет итерацию от 0 до 9 с помощью функции range().\nОба выполняют одно и то же: складывают числа от 0 до 9 в переменную sum, но используют разные способы выполнения итераций.",[458,14455,4875,14457],{"id":14456},"функция-range",[428,14458,14459],{},"range",[415,14461,14462],{},"Функция range в Python является встроенной функцией, которая создает последовательность чисел внутри определенного диапазона.\nПодобные функции, которые создают, еще говорят \"генерируют\"(называют генераторными функциями), можно использовать в цикле for для контроля количества итераций.",[415,14464,14465],{},"У range есть несколько вариантов использования:",[697,14467,14468,14471,14474],{},[700,14469,14470],{},"range(stop) создает последовательность от 0 до stop - 1;",[700,14472,14473],{},"range(start, stop) создает последовательность от start до stop - 1;",[700,14475,14476],{},"range(start, stop, step) создает последовательность из чисел от start до stop - 1, с шагом step.",[415,14478,14479],{},"Пример с одним конечным значением мы рассмотрели выше. Рассмотрим другой - распечатаем на экран числа от 1 до 3:",[422,14481,14483],{"className":424,"code":14482,"language":396,"meta":426,"style":426},"for i in range(1, 4):\n    print(i)\n\n# => 1\n# => 2\n# => 3\n",[428,14484,14485,14505,14511,14515,14519,14523],{"__ignoreMap":426},[431,14486,14487,14489,14491,14493,14495,14497,14499,14501,14503],{"class":433,"line":434},[431,14488,14329],{"class":654},[431,14490,12664],{"class":441},[431,14492,14421],{"class":654},[431,14494,14424],{"class":437},[431,14496,442],{"class":441},[431,14498,1192],{"class":437},[431,14500,4846],{"class":441},[431,14502,762],{"class":437},[431,14504,7381],{"class":441},[431,14506,14507,14509],{"class":433,"line":452},[431,14508,6357],{"class":437},[431,14510,12677],{"class":441},[431,14512,14513],{"class":433,"line":578},[431,14514,1662],{"emptyLinePlaceholder":393},[431,14516,14517],{"class":433,"line":584},[431,14518,791],{"class":455},[431,14520,14521],{"class":433,"line":1244},[431,14522,3518],{"class":455},[431,14524,14525],{"class":433,"line":1985},[431,14526,4513],{"class":455},[415,14528,14529],{},"Теперь попробуем вывести числа в обратном порядке:",[422,14531,14533],{"className":424,"code":14532,"language":396,"meta":426,"style":426},"for i in range(3, 0, -1):\n    print(i)\n\n# => 3\n# => 2\n# => 1\n",[428,14534,14535,14561,14567,14571,14575,14579],{"__ignoreMap":426},[431,14536,14537,14539,14541,14543,14545,14547,14549,14551,14553,14555,14557,14559],{"class":433,"line":434},[431,14538,14329],{"class":654},[431,14540,12664],{"class":441},[431,14542,14421],{"class":654},[431,14544,14424],{"class":437},[431,14546,442],{"class":441},[431,14548,971],{"class":437},[431,14550,4846],{"class":441},[431,14552,3302],{"class":437},[431,14554,4846],{"class":441},[431,14556,853],{"class":654},[431,14558,1192],{"class":437},[431,14560,7381],{"class":441},[431,14562,14563,14565],{"class":433,"line":452},[431,14564,6357],{"class":437},[431,14566,12677],{"class":441},[431,14568,14569],{"class":433,"line":578},[431,14570,1662],{"emptyLinePlaceholder":393},[431,14572,14573],{"class":433,"line":584},[431,14574,4513],{"class":455},[431,14576,14577],{"class":433,"line":1244},[431,14578,3518],{"class":455},[431,14580,14581],{"class":433,"line":1985},[431,14582,791],{"class":455},[415,14584,14585],{},"На примерах выше мы видим, что итерация завершается до конечного значения.",[415,14587,14588],{},"Если нужно просто повторить действие несколько раз, и переменная не нужна, то её можно опустить. Для этого имя переменной заменяют на символ _:",[422,14590,14592],{"className":424,"code":14591,"language":396,"meta":426,"style":426},"for _ in range(1, 4):\n    print('Python!')\n\n# => Python!\n# => Python!\n# => Python!\n",[428,14593,14594,14615,14626,14630,14635,14639],{"__ignoreMap":426},[431,14595,14596,14598,14601,14603,14605,14607,14609,14611,14613],{"class":433,"line":434},[431,14597,14329],{"class":654},[431,14599,14600],{"class":441}," _ ",[431,14602,14421],{"class":654},[431,14604,14424],{"class":437},[431,14606,442],{"class":441},[431,14608,1192],{"class":437},[431,14610,4846],{"class":441},[431,14612,762],{"class":437},[431,14614,7381],{"class":441},[431,14616,14617,14619,14621,14624],{"class":433,"line":452},[431,14618,6357],{"class":437},[431,14620,442],{"class":441},[431,14622,14623],{"class":445},"'Python!'",[431,14625,449],{"class":441},[431,14627,14628],{"class":433,"line":578},[431,14629,1662],{"emptyLinePlaceholder":393},[431,14631,14632],{"class":433,"line":584},[431,14633,14634],{"class":455},"# => Python!\n",[431,14636,14637],{"class":433,"line":1244},[431,14638,14634],{"class":455},[431,14640,14641],{"class":433,"line":1985},[431,14642,14634],{"class":455},[458,14644,14646],{"id":14645},"цикл-for-и-строки","Цикл for и строки",[415,14648,14649],{},"Например, если мы хотим перебрать символы в строке, то компьютер сам может понять, когда строка заканчивается.\nДля таких ситуаций в Python ввели цикл for.\nОн сам знает, когда нужно остановиться, так как работает только с коллекциями — наборами элементов, которые нужно перебрать.\nСтрока — это коллекция, так как состоит из набора символов.\nПример:",[422,14651,14653],{"className":424,"code":14652,"language":396,"meta":426,"style":426},"text = 'code'\nfor symbol in text:\n    print(symbol)\n\n# => c\n# => o\n# => d\n# => e\n",[428,14654,14655,14664,14676,14683,14687,14692,14697,14702],{"__ignoreMap":426},[431,14656,14657,14659,14661],{"class":433,"line":434},[431,14658,3100],{"class":441},[431,14660,1189],{"class":654},[431,14662,14663],{"class":445}," 'code'\n",[431,14665,14666,14668,14671,14673],{"class":433,"line":452},[431,14667,14329],{"class":654},[431,14669,14670],{"class":441}," symbol ",[431,14672,14421],{"class":654},[431,14674,14675],{"class":441}," text:\n",[431,14677,14678,14680],{"class":433,"line":578},[431,14679,6357],{"class":437},[431,14681,14682],{"class":441},"(symbol)\n",[431,14684,14685],{"class":433,"line":584},[431,14686,1662],{"emptyLinePlaceholder":393},[431,14688,14689],{"class":433,"line":1244},[431,14690,14691],{"class":455},"# => c\n",[431,14693,14694],{"class":433,"line":1985},[431,14695,14696],{"class":455},"# => o\n",[431,14698,14699],{"class":433,"line":2041},[431,14700,14701],{"class":455},"# => d\n",[431,14703,14704],{"class":433,"line":4018},[431,14705,14706],{"class":455},"# => e\n",[415,14708,14709],{},"В коде выше for проходит по каждому символу в строке, записывает его в переменную symbol и вызывает внутренний блок кода, где эта переменная используется.\nИмя этой переменной может быть любым. Общая структура цикла for выглядит так: for \u003Cпеременная> in \u003Cколлекция>.\nПосмотрим, как реализовать функцию переворота строки через цикл for:",[422,14711,14713],{"className":424,"code":14712,"language":396,"meta":426,"style":426},"def reverse_string(text):\n    # Начальное значение\n    result = ''\n    # char - переменная, в которую записывается текущий символ\n    for char in text:\n        # Соединяем в обратном порядке\n        result = char + result\n    # Цикл заканчивается, когда пройдена вся строка\n    return result\n\n\nresult = reverse_string('go!')\nprint(result) # => !og\n",[428,14714,14715,14723,14728,14736,14741,14753,14758,14770,14775,14781,14785,14789,14803],{"__ignoreMap":426},[431,14716,14717,14719,14721],{"class":433,"line":434},[431,14718,6330],{"class":654},[431,14720,13684],{"class":6333},[431,14722,7050],{"class":441},[431,14724,14725],{"class":433,"line":452},[431,14726,14727],{"class":455},"    # Начальное значение\n",[431,14729,14730,14732,14734],{"class":433,"line":578},[431,14731,6796],{"class":441},[431,14733,1189],{"class":654},[431,14735,9805],{"class":445},[431,14737,14738],{"class":433,"line":584},[431,14739,14740],{"class":455},"    # char - переменная, в которую записывается текущий символ\n",[431,14742,14743,14746,14749,14751],{"class":433,"line":1244},[431,14744,14745],{"class":654},"    for",[431,14747,14748],{"class":441}," char ",[431,14750,14421],{"class":654},[431,14752,14675],{"class":441},[431,14754,14755],{"class":433,"line":1985},[431,14756,14757],{"class":455},"        # Соединяем в обратном порядке\n",[431,14759,14760,14762,14764,14766,14768],{"class":433,"line":2041},[431,14761,13429],{"class":441},[431,14763,1189],{"class":654},[431,14765,14748],{"class":441},[431,14767,802],{"class":654},[431,14769,6812],{"class":441},[431,14771,14772],{"class":433,"line":4018},[431,14773,14774],{"class":455},"    # Цикл заканчивается, когда пройдена вся строка\n",[431,14776,14777,14779],{"class":433,"line":4030},[431,14778,6599],{"class":654},[431,14780,6812],{"class":441},[431,14782,14783],{"class":433,"line":4419},[431,14784,1662],{"emptyLinePlaceholder":393},[431,14786,14787],{"class":433,"line":4436},[431,14788,1662],{"emptyLinePlaceholder":393},[431,14790,14791,14793,14795,14798,14801],{"class":433,"line":4446},[431,14792,4799],{"class":441},[431,14794,1189],{"class":654},[431,14796,14797],{"class":441}," reverse_string(",[431,14799,14800],{"class":445},"'go!'",[431,14802,449],{"class":441},[431,14804,14805,14807,14810],{"class":433,"line":4451},[431,14806,438],{"class":437},[431,14808,14809],{"class":441},"(result) ",[431,14811,14812],{"class":455},"# => !og\n",[415,14814,14815],{},"Теперь посчитаем количество упоминаний символа в строке без учета регистра:",[422,14817,14819],{"className":424,"code":14818,"language":396,"meta":426,"style":426},"# text - произвольный текст\n# char - символ, который нужно учитывать\ndef chars_count(text, char):\n    # Так как ищем сумму, то начальное значение — 0\n    result = 0\n    for current_char in text:\n        # Приводим все к нижнему регистру,\n        # чтобы не зависеть от текущего регистра\n        if current_char.lower() == char.lower():\n            result += 1\n    return result\n\n\nchars_count('python!', 'o')  # 1\nchars_count('pYthon!', 'y')  # 1\nchars_count('pYthon!', 'Y')  # 1\nchars_count('python!', 'a')  # 0\n",[428,14820,14821,14826,14831,14841,14846,14854,14865,14870,14875,14887,14895,14901,14905,14909,14926,14941,14955],{"__ignoreMap":426},[431,14822,14823],{"class":433,"line":434},[431,14824,14825],{"class":455},"# text - произвольный текст\n",[431,14827,14828],{"class":433,"line":452},[431,14829,14830],{"class":455},"# char - символ, который нужно учитывать\n",[431,14832,14833,14835,14838],{"class":433,"line":578},[431,14834,6330],{"class":654},[431,14836,14837],{"class":6333}," chars_count",[431,14839,14840],{"class":441},"(text, char):\n",[431,14842,14843],{"class":433,"line":584},[431,14844,14845],{"class":455},"    # Так как ищем сумму, то начальное значение — 0\n",[431,14847,14848,14850,14852],{"class":433,"line":1244},[431,14849,6796],{"class":441},[431,14851,1189],{"class":654},[431,14853,3459],{"class":437},[431,14855,14856,14858,14861,14863],{"class":433,"line":1985},[431,14857,14745],{"class":654},[431,14859,14860],{"class":441}," current_char ",[431,14862,14421],{"class":654},[431,14864,14675],{"class":441},[431,14866,14867],{"class":433,"line":2041},[431,14868,14869],{"class":455},"        # Приводим все к нижнему регистру,\n",[431,14871,14872],{"class":433,"line":4018},[431,14873,14874],{"class":455},"        # чтобы не зависеть от текущего регистра\n",[431,14876,14877,14879,14882,14884],{"class":433,"line":4030},[431,14878,11471],{"class":654},[431,14880,14881],{"class":441}," current_char.lower() ",[431,14883,8409],{"class":654},[431,14885,14886],{"class":441}," char.lower():\n",[431,14888,14889,14891,14893],{"class":433,"line":4419},[431,14890,11835],{"class":441},[431,14892,12563],{"class":654},[431,14894,3916],{"class":437},[431,14896,14897,14899],{"class":433,"line":4436},[431,14898,6599],{"class":654},[431,14900,6812],{"class":441},[431,14902,14903],{"class":433,"line":4446},[431,14904,1662],{"emptyLinePlaceholder":393},[431,14906,14907],{"class":433,"line":4451},[431,14908,1662],{"emptyLinePlaceholder":393},[431,14910,14911,14914,14917,14919,14922,14924],{"class":433,"line":4086},[431,14912,14913],{"class":441},"chars_count(",[431,14915,14916],{"class":445},"'python!'",[431,14918,4846],{"class":441},[431,14920,14921],{"class":445},"'o'",[431,14923,526],{"class":441},[431,14925,13119],{"class":455},[431,14927,14928,14930,14933,14935,14937,14939],{"class":433,"line":4477},[431,14929,14913],{"class":441},[431,14931,14932],{"class":445},"'pYthon!'",[431,14934,4846],{"class":441},[431,14936,13917],{"class":445},[431,14938,526],{"class":441},[431,14940,13119],{"class":455},[431,14942,14943,14945,14947,14949,14951,14953],{"class":433,"line":4482},[431,14944,14913],{"class":441},[431,14946,14932],{"class":445},[431,14948,4846],{"class":441},[431,14950,6154],{"class":445},[431,14952,526],{"class":441},[431,14954,13119],{"class":455},[431,14956,14957,14959,14961,14963,14966,14968],{"class":433,"line":4488},[431,14958,14913],{"class":441},[431,14960,14916],{"class":445},[431,14962,4846],{"class":441},[431,14964,14965],{"class":445},"'a'",[431,14967,526],{"class":441},[431,14969,13922],{"class":455},[415,14971,14972],{},"Главное преимущество for в том, что он короче и проще, когда известно сколько итераций будет.\nЕщё он понятнее и легче читается, например со строками.\nВ Python он ещё и управляет итерациями сам, что делает его удобнее в некоторых случаях.",[415,14974,1849,14975,1853,14977,1857],{},[800,14976,1852],{},[800,14978,1856],{},[1859,14980],{},[1862,14982,14983],{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":14985},[14986],{"id":12493,"depth":452,"text":12494,"children":14987},[14988,14989,14994,14998,15002,15006],{"id":12500,"depth":584,"text":12501},{"id":12733,"depth":578,"text":14990,"children":14991},"Цикл while",[14992,14993],{"id":12910,"depth":584,"text":12911},{"id":12998,"depth":584,"text":12999},{"id":13039,"depth":578,"text":13040,"children":14995},[14996,14997],{"id":13046,"depth":584,"text":13047},{"id":13340,"depth":584,"text":13341},{"id":13531,"depth":578,"text":13532,"children":14999},[15000,15001],{"id":13538,"depth":584,"text":13539},{"id":13657,"depth":584,"text":13658},{"id":13874,"depth":578,"text":13875,"children":15003},[15004,15005],{"id":14030,"depth":584,"text":14031},{"id":14139,"depth":584,"text":14140},{"id":14326,"depth":578,"text":15007,"children":15008},"Цикл for",[15009,15011],{"id":14456,"depth":584,"text":15010},"Функция range",{"id":14645,"depth":584,"text":14646},"2025-02-17","Создание циклов. Условия внутри тела цикла. Обход строк","images\u002Fblog\u002Fpython\u002Fst9\u002Fimg.png",{},32,{"title":326,"description":15013},"YHZIPaRjrxqh6QpofVgGBGXu8OOTklvouSRmkglfW4o",{"id":15020,"title":194,"author":15021,"body":15023,"date":15353,"description":15354,"extension":1887,"image":15355,"meta":15356,"minRead":4451,"navigation":393,"num":4419,"path":195,"seo":15357,"stem":196,"__hash__":15358},"python\u002Fblog\u002Fpython\u002Fst10.md",{"name":402,"avatar":15022},{"src":404,"alt":405},{"type":407,"value":15024,"toc":15343},[15025,15028,15031,15035,15038,15041,15044,15061,15064,15067,15076,15079,15112,15115,15119,15126,15155,15162,15173,15176,15183,15187,15190,15264,15272,15276,15279,15282,15290,15294,15300,15317,15320,15328,15335,15340],[410,15026,194],{"id":15027},"отладка",[415,15029,15030],{},"Даже у самых опытных программистов код редко работает идеально с первого раза.\nНо чем опытнее программист, тем лучше он отлаживает код, то есть анализирует ошибки и устраняет их.\nНавык отладки сам по себе не появится: его необходимо развивать, причем начинать нужно как можно раньше.\nПо ходу обучения вы будете выполнять задания и практиковаться — все это поможет набраться опыта.\nСо временем анализ и устранение ошибок войдут в привычку, если уделять достаточно внимания практике.",[632,15032,15034],{"id":15033},"поиск-ошибок-в-коде","Поиск ошибок в коде",[415,15036,15037],{},"Можно отлаживать некорректно работающий код \"методом тыка\", но это долго и непродуктивно.\nБудет намного проще, если вы сначала поймете проблему, а уже потом начнете устранять ее.\nПонимание — это ключевой этап, без которого дальнейшие шаги невозможны.\nПеред отладкой кода надо понять, что в нем не так. Это можно сделать за два шага.",[415,15039,15040],{},"Шаг 1. Изучить traceback(\"трейсбек\") — список всех вызовов функций от запуска программы до места с ошибкой.\nTraceback помогает отследить, как прошло выполнение программы: какие функции получилось вызвать успешно, а с какими — возникли сложности.\nКаждая запись в \"трейсбеке\" указывает на файл и строчку, а затем на выполняемую функцию.",[415,15042,15043],{},"Представим, что вы написали код в файле db.py и решили запустить функцию main() в четвертой строчке.\nЗапись в \"трейсбеке\" будет выглядеть так:",[422,15045,15049],{"className":15046,"code":15047,"language":15048,"meta":426,"style":426},"language-shell shiki shiki-themes github-light","File \"db.py\", line 4, in \u003Cmodule>\n    main()\n","shell",[428,15050,15051,15056],{"__ignoreMap":426},[431,15052,15053],{"class":433,"line":434},[431,15054,15055],{},"File \"db.py\", line 4, in \u003Cmodule>\n",[431,15057,15058],{"class":433,"line":452},[431,15059,15060],{},"    main()\n",[415,15062,15063],{},"Как видите, здесь указаны не только файл и строчка, но еще и название модуля.\nПо нему можно с легкостью определить, где возникла проблема: в вашем коде или в какой-то библиотеке, которую вы не писали, но используете.",[415,15065,15066],{},"Шаг 2. Когда \"трейсбек\" дойдет до проблемного места, он выдаст сообщение об ошибке. Например, такое:",[422,15068,15070],{"className":15046,"code":15069,"language":15048,"meta":426,"style":426},"NameError: name 'create' is not defined\n",[428,15071,15072],{"__ignoreMap":426},[431,15073,15074],{"class":433,"line":434},[431,15075,15069],{},[415,15077,15078],{},"Если владеете английским, то быстрее поймете, о чем идет речь в сообщении: «Название create не определено».\nЭта ошибка чаще всего происходит из-за опечатки в названии — нужно проверить этот момент.\nБез знания английского тоже можно разобраться, если обратиться к словарю или онлайн-переводчику.\nТеперь посмотрим, как traceback и сообщение об ошибке выглядят вместе:",[422,15080,15082],{"className":15046,"code":15081,"language":15048,"meta":426,"style":426},"Traceback (most recent call last):\n  File \"db.py\", line 4, in \u003Cmodule>\n    main()\n  File \"db.py\", line 2, in main\n    create()\nNameError: name 'create' is not defined\n",[428,15083,15084,15089,15094,15098,15103,15108],{"__ignoreMap":426},[431,15085,15086],{"class":433,"line":434},[431,15087,15088],{},"Traceback (most recent call last):\n",[431,15090,15091],{"class":433,"line":452},[431,15092,15093],{},"  File \"db.py\", line 4, in \u003Cmodule>\n",[431,15095,15096],{"class":433,"line":578},[431,15097,15060],{},[431,15099,15100],{"class":433,"line":584},[431,15101,15102],{},"  File \"db.py\", line 2, in main\n",[431,15104,15105],{"class":433,"line":1244},[431,15106,15107],{},"    create()\n",[431,15109,15110],{"class":433,"line":1985},[431,15111,15069],{},[415,15113,15114],{},"В примере выше видно всю цепочку событий: программа успешно справилась с функцией main(), а потом перешла к функции create() и столкнулась с ошибкой в названии.\nКроме NameError, в Python есть еще множество разных ошибок, которые можно разделить на три группы.",[632,15116,15118],{"id":15117},"типы-ошибок","Типы ошибок",[415,15120,15121,15122,15125],{},"Самые простые и понятные ошибки — ",[1355,15123,15124],{},"синтаксические",".\nОни связаны исключительно с тем, что код неверно оформлен: например, использованы неправильные кавычки.\nВ выводе таких ошибок всегда присутствует фраза SyntaxError:. Чтобы отладить код в этом случае, нужно внимательно взглянуть на место с ошибкой.\nПосмотрим на примере. Здесь синтаксическая ошибка произошла потому, что использована кавычка ' вместо \":",[422,15127,15129],{"className":15046,"code":15128,"language":15048,"meta":426,"style":426},"Traceback (most recent call last):\n  File \"users.py\", line 2\n    print(\"Hello\" + \"world')\n                           ^\nSyntaxError: EOL while scanning string literal\n",[428,15130,15131,15135,15140,15145,15150],{"__ignoreMap":426},[431,15132,15133],{"class":433,"line":434},[431,15134,15088],{},[431,15136,15137],{"class":433,"line":452},[431,15138,15139],{},"  File \"users.py\", line 2\n",[431,15141,15142],{"class":433,"line":578},[431,15143,15144],{},"    print(\"Hello\" + \"world')\n",[431,15146,15147],{"class":433,"line":584},[431,15148,15149],{},"                           ^\n",[431,15151,15152],{"class":433,"line":1244},[431,15153,15154],{},"SyntaxError: EOL while scanning string literal\n",[415,15156,15157,15158,15161],{},"Вторая большая группа ошибок — это ",[1355,15159,15160],{},"ошибки программирования",". Например, к ним относятся:",[697,15163,15164,15167,15170],{},[700,15165,15166],{},"Вызов несуществующей функции;",[700,15168,15169],{},"Использование необъявленной переменной;",[700,15171,15172],{},"Передача неверных аргументов (например, аргументов неверного типа);",[415,15174,15175],{},"Эти ошибки исправить труднее, чем синтаксические. Обычно они возникают, если в другом более раннем вызове была неправильная логика.",[415,15177,15178,15179,15182],{},"Последний тип ошибок — ",[1355,15180,15181],{},"логические ошибки",".\nИсправить ситуацию бывает очень сложно, потому что программа в целом работает, но при некоторых значениях выдает неверный результат.\nВ большинстве случаев проблема кроется в неверной логике. Например, вместо сложения в программе выполняется вычитание.",[632,15184,15186],{"id":15185},"способы-отладки","Способы отладки",[415,15188,15189],{},"Есть множество способов отладки программ, но у всех одна общая идея — нужно проанализировать, как меняются значения переменных в процессе работы кода.\nРассмотрим на конкретном примере.\nНиже описана функция, которая считает сумму чисел от числа start до числа finish.\nЕсли start равно трём, а finish — пяти, то программа должна вычислить: 3 + 4 + 5.",[422,15191,15193],{"className":424,"code":15192,"language":396,"meta":426,"style":426},"def sum_of_series(start, finish):\n    result = 0\n    n = start\n    while n \u003C finish:\n        result = result + n\n        n = n + 1\n    return result\n",[428,15194,15195,15204,15212,15221,15232,15245,15258],{"__ignoreMap":426},[431,15196,15197,15199,15202],{"class":433,"line":434},[431,15198,6330],{"class":654},[431,15200,15201],{"class":6333}," sum_of_series",[431,15203,13152],{"class":441},[431,15205,15206,15208,15210],{"class":433,"line":452},[431,15207,6796],{"class":441},[431,15209,1189],{"class":654},[431,15211,3459],{"class":437},[431,15213,15214,15217,15219],{"class":433,"line":578},[431,15215,15216],{"class":441},"    n ",[431,15218,1189],{"class":654},[431,15220,13176],{"class":441},[431,15222,15223,15225,15227,15229],{"class":433,"line":584},[431,15224,12537],{"class":654},[431,15226,8150],{"class":441},[431,15228,8521],{"class":654},[431,15230,15231],{"class":441}," finish:\n",[431,15233,15234,15236,15238,15240,15242],{"class":433,"line":1244},[431,15235,13429],{"class":441},[431,15237,1189],{"class":654},[431,15239,13434],{"class":441},[431,15241,802],{"class":654},[431,15243,15244],{"class":441}," n\n",[431,15246,15247,15250,15252,15254,15256],{"class":433,"line":1985},[431,15248,15249],{"class":441},"        n ",[431,15251,1189],{"class":654},[431,15253,8150],{"class":441},[431,15255,802],{"class":654},[431,15257,3916],{"class":437},[431,15259,15260,15262],{"class":433,"line":2041},[431,15261,6599],{"class":654},[431,15263,6812],{"class":441},[415,15265,15266,15267],{},"В этом коде допущена ошибка.\nГлядя на код функции sum_of_series(), замечаем, что основных переменных там две: n и result.\nИз этого можно сделать такой вывод — нужно посмотреть, какие значения даются переменным на каждой итерации.\nПосле этого найти ошибку не составит труда.\nЕсть удобный инструмент для отслеживания значений переменных во время выполнения кода — это визуальные отладчики.\nОни встраиваются в популярные редакторы кода и позволяют выполнить программу по шагам и увидеть все изменения.\nЕсли интересно узнать больше об отладчиках: ",[1205,15268,15271],{"href":15269,"rel":15270},"https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002Fpdb.html",[1209],"Python debugger.",[458,15273,15275],{"id":15274},"тесты","Тесты",[415,15277,15278],{},"Код должен и часто проверяется с помощью автоматических тестов.\nОбычно они написаны на том же языке, на котором написан сам код.\nОбщий принцип работы такого вида тестирования довольно прост.\nТестируемая программа загружается в память и вызывается с разными параметрами, а тесты следят за тем, чтобы ее поведение соответствовало ожидаемому.\nКогда код не проходит тесты, то обычно говорят что \"тесты упали\". В этот момент начинается самое интересное.\nНеобходимо понять, где и почему возникла ошибка.\nИ вывод тестов в этом процессе играет ключевую роль, это главный помощник и проводник.\nНо необходим опыт, чтобы начать делать правильные выводы из того, что пишут тесты.\nВ первую очередь нужно классифицировать проблему.",[415,15280,15281],{},"Ошибки в тестах можно грубо разделить на две категории:",[697,15283,15284,15287],{},[700,15285,15286],{},"ошибки, которые выдает компилятор или интерпретатор: синтаксическая ошибка, ошибка типизации;",[700,15288,15289],{},"ошибочные утверждения.",[458,15291,15293],{"id":15292},"утверждения","Утверждения",[415,15295,15296,15299],{},[800,15297,15298],{},"Утверждение"," — это специальная функция, которая вызывает ваш код с определенными параметрами и проверяет, что он возвращает ожидаемый результат.\nНапример:",[422,15301,15303],{"className":424,"code":15302,"language":396,"meta":426,"style":426},"assert(isDigit(3))\n",[428,15304,15305],{"__ignoreMap":426},[431,15306,15307,15310,15313,15315],{"class":433,"line":434},[431,15308,15309],{"class":654},"assert",[431,15311,15312],{"class":441},"(isDigit(",[431,15314,971],{"class":437},[431,15316,6157],{"class":441},[415,15318,15319],{},"Самое важное: если \"тесты упали на утверждении\", это означает, что ваш код как минимум отработал, но его результат не соответствует ожидаемому.\nПричем часто бывает так, что часть утверждений проходит проверку, то есть код возвращает правильный результат, а часть — нет, обычно в пограничных случаях.\nВ конечном итоге падение теста на утверждении говорит о том, что в коде логическая ошибка.",[415,15321,15322,15323],{},"Ниже — пример вывода упавшего теста. То, насколько вывод подробный, зависит от вида утверждения и возможностей тестовой среды.\n",[15324,15325],"img",{"alt":15326,"src":15327},"Упавший тест","\u002Fimages\u002Fblog\u002Fpython\u002Fst10\u002Fimg1.png",[415,15329,15330,15331],{},"Вывод можно разделить на две части:\nПервая — описание того, что ожидалось от функции и что было получено.\nВ нашем примере это строка AssertionError: 3 == 1.\nЧитается она следующим образом: «ожидалось, что функция вернет 3, но она вернула 1».\nЭто уже хорошо, но еще хотелось бы увидеть, с какими параметрами была вызвана функция.\nИ в этом нам поможет вторая часть вывода.\nВторая часть называется backtrace, она содержит список функций, которые последовательно вызывались в коде.\nПорядок вывода, чаще всего, обратный: в начале то, что вызывалось последним.\nВ первую очередь нужно, начиная с конца, найти первое упоминание функции из файла, который похож на тестовый.\nОбычно его называние содержит слово test.\nВ примере выше это at Object.",[15332,15333,15334],"anonymous",{}," (test.js:4:8).\nВ скобках указана строчка, на которой находится вызов этого утверждения. В данном случае — строчка 4.\nВсё, что теперь остается, это зайти в соответствующий файл и посмотреть то, как вызывалась ваша функция.",[415,15336,15337],{},[1355,15338,15339],{},"Новички часто расстраиваются из-за ошибок, начинают считать себя невнимательными.\nНа самом деле, в ошибках нет ничего страшного: опытные разработчики допускают их не реже новичков.\nСложно научиться писать идеальный код, но можно развивать навыки отладки и \"насмотренность\" на ошибки.\nЕще новички думают, что опытный разработчик может взглянуть на код и сразу же понять, в чем ошибка.\nДа, с опытом это приходит, но все не так просто. По фрагменту кода сложно понять, что пошло не так.\nЕсли хотите спросить совет у опытного разработчика, лучше покажите не сам некорректно работающий код, а сообщение об ошибке.",[1862,15341,15342],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}",{"title":426,"searchDepth":452,"depth":1244,"links":15344},[15345],{"id":15027,"depth":452,"text":194,"children":15346},[15347,15348,15349],{"id":15033,"depth":578,"text":15034},{"id":15117,"depth":578,"text":15118},{"id":15185,"depth":578,"text":15186,"children":15350},[15351,15352],{"id":15274,"depth":584,"text":15275},{"id":15292,"depth":584,"text":15293},"2025-02-18","Поиск ошибок в коде. Типы ошибок. Способы отладки","images\u002Fblog\u002Fpython\u002Fst10\u002Fimg.png",{},{"title":194,"description":15354},"mxydsrJ83M_q18XS0SMO0XfGmLPbXc-zhZlPmOgcQHQ",{"id":15360,"title":198,"author":15361,"body":15363,"date":16564,"description":16565,"extension":1887,"image":16566,"meta":16567,"minRead":2874,"navigation":393,"num":4436,"path":199,"seo":16568,"stem":200,"__hash__":16569},"python\u002Fblog\u002Fpython\u002Fst11.md",{"name":402,"avatar":15362},{"src":404,"alt":405},{"type":407,"value":15364,"toc":16543},[15365,15368,15371,15374,15378,15399,15449,15458,15469,15472,15476,15491,15508,15511,15548,15551,15555,15567,15612,15615,15662,15673,15677,15680,15708,15711,15715,15722,15780,15788,15873,15876,15887,15891,15894,15898,15909,15924,15930,15950,15953,15980,15989,15993,15996,16019,16025,16044,16050,16089,16095,16099,16102,16110,16117,16152,16155,16199,16202,16210,16213,16217,16220,16224,16227,16268,16275,16297,16300,16304,16307,16310,16324,16328,16337,16353,16356,16379,16385,16432,16435,16446,16453,16457,16466,16503,16513,16525,16532,16538,16540],[410,15366,198],{"id":15367},"модули-и-пакеты",[415,15369,15370],{},"Для реальных приложений на рынке разработчики пишут сотни и тысячи строчек кода.\nЕсть даже проекты, в которых несколько миллионов строчек.\nПодобный масштабный проект невозможно сохранить в одном файле, команда запутается в своем же коде, не сможет поддерживать и обновлять его.\nПоэтому файл с кодом нужно разбивать на части.\nЭтот принцип применяется во многих языках программирования. В Python с этой целью используются модули.",[415,15372,15373],{},"В Python любой файл с кодом называется модулем — между этими терминами нет разницы.\nЧтобы всем Python-разработчикам было удобно читать готовый код, принято называть файлы в стиле snake_case: то есть с маленькой буквы и с разделением слов символом подчеркивания.\nЭто легко запомнить: snake_case переводится как «змеиный регистр» и поэтому идеально сочетается с языком Python.",[458,15375,15377],{"id":15376},"как-использовать-модули","Как использовать модули",[415,15379,15380,15381,15384,15385,15387,15388,15391,15392,15395,15396,3562],{},"Работать с кодом в тысячи строчек намного проще, если он разбит на несколько модулей.\nВ таком случае обычно работают с главным файлом, а отдельные функции помещают в разные модули.\nЗатем модули импортируют в ",[800,15382,15383],{},"main.py"," с помощью ключевого слова ",[428,15386,5379],{},".\nВ итоге команда разработчиков получает код, который легко читать и обслуживать.\nЧтобы попрактиковаться, попробуем создать свой модуль.\nДля этого мы создадим файл с названием ",[800,15389,15390],{},"greeting.py",".\nЗатем внутри этого файла определим функцию ",[428,15393,15394],{},"say_hi()"," и переменную ",[428,15397,15398],{},"name",[422,15400,15402],{"className":424,"code":15401,"language":396,"meta":426,"style":426},"# file: greeting.py\ndef say_hi(): # определяем функцию\n    print('Hi!')\n\nname = 'Alexander' # определяем переменную\n",[428,15403,15404,15409,15422,15433,15437],{"__ignoreMap":426},[431,15405,15406],{"class":433,"line":434},[431,15407,15408],{"class":455},"# file: greeting.py\n",[431,15410,15411,15413,15416,15419],{"class":433,"line":452},[431,15412,6330],{"class":654},[431,15414,15415],{"class":6333}," say_hi",[431,15417,15418],{"class":441},"(): ",[431,15420,15421],{"class":455},"# определяем функцию\n",[431,15423,15424,15426,15428,15431],{"class":433,"line":578},[431,15425,6357],{"class":437},[431,15427,442],{"class":441},[431,15429,15430],{"class":445},"'Hi!'",[431,15432,449],{"class":441},[431,15434,15435],{"class":433,"line":584},[431,15436,1662],{"emptyLinePlaceholder":393},[431,15438,15439,15441,15443,15446],{"class":433,"line":1244},[431,15440,3287],{"class":441},[431,15442,1189],{"class":654},[431,15444,15445],{"class":445}," 'Alexander'",[431,15447,15448],{"class":455}," # определяем переменную\n",[415,15450,15451,15452,15454,15455,15457],{},"Модуль-приветствие готов: он умеет печатать строку Hi! и обрабатывать переменную ",[428,15453,15398],{},".\nНо от него нет никакой пользы, пока он не встроен в работу всей остальной программы.\nЧтобы воспользоваться нашим модулем, нужно импортировать его в главный модуль ",[800,15456,15383],{},".\nДля этого в Python есть три способа:",[697,15459,15460,15463,15466],{},[700,15461,15462],{},"Импорт модуля целиком;",[700,15464,15465],{},"Импорт отдельных определений из модуля;",[700,15467,15468],{},"Импорт всего содержимого модуля сразу;",[415,15470,15471],{},"Сначала рассмотрим только первый и второй способы.",[458,15473,15475],{"id":15474},"импорт-модуля-целиком","Импорт модуля целиком",[415,15477,15478,15479,15481,15482,15485,15486,15488,15489,3562],{},"Это самый простой способ: используем ключевое слово ",[428,15480,5379],{}," вместе с названием файла без расширения ",[800,15483,15484],{},".py",".\nПерейдем в главный файл ",[800,15487,15383],{}," и импортируем туда наш модуль ",[800,15490,15390],{},[422,15492,15494],{"className":424,"code":15493,"language":396,"meta":426,"style":426},"# file: main.py\nimport greeting\n",[428,15495,15496,15501],{"__ignoreMap":426},[431,15497,15498],{"class":433,"line":434},[431,15499,15500],{"class":455},"# file: main.py\n",[431,15502,15503,15505],{"class":433,"line":452},[431,15504,5379],{"class":654},[431,15506,15507],{"class":441}," greeting\n",[415,15509,15510],{},"Импорт прошел успешно — у нас появился доступ к модулю-приветствию прямо из главного файла.\nТеперь к содержимому модуля можно обращаться «через точку».\nТак можно вызвать функцию модуля или отдельную переменную:",[422,15512,15514],{"className":424,"code":15513,"language":396,"meta":426,"style":426},"# вызываем функцию модуля\ngreeting.say_hi()  # => Hi!\n\n# выводим на экран отдельную переменную\nprint(greeting.name)  # => Alexander\n",[428,15515,15516,15521,15529,15533,15538],{"__ignoreMap":426},[431,15517,15518],{"class":433,"line":434},[431,15519,15520],{"class":455},"# вызываем функцию модуля\n",[431,15522,15523,15526],{"class":433,"line":452},[431,15524,15525],{"class":441},"greeting.say_hi()  ",[431,15527,15528],{"class":455},"# => Hi!\n",[431,15530,15531],{"class":433,"line":578},[431,15532,1662],{"emptyLinePlaceholder":393},[431,15534,15535],{"class":433,"line":584},[431,15536,15537],{"class":455},"# выводим на экран отдельную переменную\n",[431,15539,15540,15542,15545],{"class":433,"line":1244},[431,15541,438],{"class":437},[431,15543,15544],{"class":441},"(greeting.name)  ",[431,15546,15547],{"class":455},"# => Alexander\n",[415,15549,15550],{},"Это самый распространенный способ, потому что такой код легко читать.\nЛюбой разработчик с первого взгляда может определить, что используемая переменная или вызываемая функция — это часть какого-то конкретного модуля.",[458,15552,15554],{"id":15553},"импорт-отдельных-определений","Импорт отдельных определений",[415,15556,15557,15558,15560,15561,15563,15564,15566],{},"Иногда первый способ не подходит — например, из длинного и сложного модуля вам нужна всего пара функций или переменных.\nТогда поможет второй способ импорта: нужно написать ключевое слово ",[428,15559,5373],{}," с названием модуля без расширения ",[800,15562,15484],{},".\nЗатем в той же строчке указываем ключевое слово ",[428,15565,5379],{}," с названиями определений, которые хотим использовать.\nТак это выглядит в коде:",[422,15568,15570],{"className":424,"code":15569,"language":396,"meta":426,"style":426},"# file: main.py\nfrom greeting import say_hi, name # импортируем отдельные компоненты модуля\n\nprint(name)  # используем импортированную переменную\nsay_hi()     # вызываем импортированную функцию\n",[428,15571,15572,15576,15591,15595,15604],{"__ignoreMap":426},[431,15573,15574],{"class":433,"line":434},[431,15575,15500],{"class":455},[431,15577,15578,15580,15583,15585,15588],{"class":433,"line":452},[431,15579,5373],{"class":654},[431,15581,15582],{"class":441}," greeting ",[431,15584,5379],{"class":654},[431,15586,15587],{"class":441}," say_hi, name ",[431,15589,15590],{"class":455},"# импортируем отдельные компоненты модуля\n",[431,15592,15593],{"class":433,"line":578},[431,15594,1662],{"emptyLinePlaceholder":393},[431,15596,15597,15599,15601],{"class":433,"line":584},[431,15598,438],{"class":437},[431,15600,5538],{"class":441},[431,15602,15603],{"class":455},"# используем импортированную переменную\n",[431,15605,15606,15609],{"class":433,"line":1244},[431,15607,15608],{"class":441},"say_hi()     ",[431,15610,15611],{"class":455},"# вызываем импортированную функцию\n",[415,15613,15614],{},"Также при импорте можно указать новое имя для импортируемого компонента с помощью ключевого слова as:",[422,15616,15618],{"className":424,"code":15617,"language":396,"meta":426,"style":426},"# file: main.py\nfrom greeting import say_hi as hello, name as first_name\n\nprint(first_name)\nhello()\n",[428,15619,15620,15624,15646,15650,15657],{"__ignoreMap":426},[431,15621,15622],{"class":433,"line":434},[431,15623,15500],{"class":455},[431,15625,15626,15628,15630,15632,15635,15638,15641,15643],{"class":433,"line":452},[431,15627,5373],{"class":654},[431,15629,15582],{"class":441},[431,15631,5379],{"class":654},[431,15633,15634],{"class":441}," say_hi ",[431,15636,15637],{"class":654},"as",[431,15639,15640],{"class":441}," hello, name ",[431,15642,15637],{"class":654},[431,15644,15645],{"class":441}," first_name\n",[431,15647,15648],{"class":433,"line":578},[431,15649,1662],{"emptyLinePlaceholder":393},[431,15651,15652,15654],{"class":433,"line":584},[431,15653,438],{"class":437},[431,15655,15656],{"class":441},"(first_name)\n",[431,15658,15659],{"class":433,"line":1244},[431,15660,15661],{"class":441},"hello()\n",[415,15663,15664,15665,15668,15669,15672],{},"Во время импорта всего модуля можно обращаться к нему «через точку». Вот как выглядит такая запись: module.name.\nДля такой формы записи существует и более официальный термин — ",[1355,15666,15667],{},"квалифицированное имя",".\nСоответственно, импорт модуля целиком официально называется ",[1355,15670,15671],{},"квалифицированным импортом",".\nСтоит отметить, что в Python все строчки с import принято располагать в самом начале кода модуля.\nТакой набор строчек часто называют блоком импортов, хотя синтаксически этот блок никак не выделен — это обычные строчки одна за другой.\nЭта группировка повышает читаемость кода: так разработчикам проще искать ошибки в коде и исправлять их.",[458,15674,15676],{"id":15675},"импорт-всего-содержимого-модуля","Импорт всего содержимого модуля",[415,15678,15679],{},"Рассмотрим третий вариант — импорт всего содержимого модуля. Так он выглядит в коде:",[422,15681,15683],{"className":424,"code":15682,"language":396,"meta":426,"style":426},"from some_module import *\nfrom another_module import *\n",[428,15684,15685,15697],{"__ignoreMap":426},[431,15686,15687,15689,15692,15694],{"class":433,"line":434},[431,15688,5373],{"class":654},[431,15690,15691],{"class":441}," some_module ",[431,15693,5379],{"class":654},[431,15695,15696],{"class":654}," *\n",[431,15698,15699,15701,15704,15706],{"class":433,"line":452},[431,15700,5373],{"class":654},[431,15702,15703],{"class":441}," another_module ",[431,15705,5379],{"class":654},[431,15707,15696],{"class":654},[415,15709,15710],{},"Здесь из модулей some_module и another_module неявно импортируются все определения.\nТакой способ импорта дает доступ к десяткам переменных, констант и функций, причем можно не указывать названия содержимого из всего модуля.\nЭта особенность отличает импорт содержимого от импорта модуля целиком — и она же может усложнять чтение кода.\nПосмотрим на примере. Представим программиста, который читает чужой код с импортом содержимого.\nВ какой-то момент он встречает название незнакомой переменной и хочет узнать, откуда она взялась.\nНедостаточно просто внимательно посмотреть на блок импортов или сделать поиск по коду — названия всех импортированных определений скрываются за *.\nИменно поэтому в большинстве руководств по написанию кода на Python повторяется один и тот же совет: «Как можно реже пользуйтесь импортом всего содержимого».\nТем не менее в реальном коде такие импорты встречаются, поэтому было важно упомянуть этот вариант.",[458,15712,15714],{"id":15713},"сочетание-способов-импорта","Сочетание способов импорта",[415,15716,15717,15718,15721],{},"Чтобы углубить знания, рассмотрим еще один способ — сочетание импорта целиком и отдельными определениями в рамках одного и того же модуля.\nРассмотрим пример. В модуле ",[428,15719,15720],{},"computation.py"," определим функцию и переменные:",[422,15723,15725],{"className":424,"code":15724,"language":396,"meta":426,"style":426},"# file: computation.py\nPI = 3.1415926\nE = 2.7182818\n\n\ndef pi_times(x):\n    return x * PI\n",[428,15726,15727,15732,15741,15751,15755,15759,15769],{"__ignoreMap":426},[431,15728,15729],{"class":433,"line":434},[431,15730,15731],{"class":455},"# file: computation.py\n",[431,15733,15734,15736,15738],{"class":433,"line":452},[431,15735,2143],{"class":437},[431,15737,2146],{"class":654},[431,15739,15740],{"class":437}," 3.1415926\n",[431,15742,15743,15746,15748],{"class":433,"line":578},[431,15744,15745],{"class":441},"E ",[431,15747,1189],{"class":654},[431,15749,15750],{"class":437}," 2.7182818\n",[431,15752,15753],{"class":433,"line":584},[431,15754,1662],{"emptyLinePlaceholder":393},[431,15756,15757],{"class":433,"line":1244},[431,15758,1662],{"emptyLinePlaceholder":393},[431,15760,15761,15763,15766],{"class":433,"line":1985},[431,15762,6330],{"class":654},[431,15764,15765],{"class":6333}," pi_times",[431,15767,15768],{"class":441},"(x):\n",[431,15770,15771,15773,15775,15777],{"class":433,"line":2041},[431,15772,6599],{"class":654},[431,15774,7388],{"class":441},[431,15776,1357],{"class":654},[431,15778,15779],{"class":437}," PI\n",[415,15781,15782,15783,15785,15786,3562],{},"А в модуле ",[428,15784,15383],{}," воспользуемся двумя способами импорта из модуля ",[428,15787,15720],{},[422,15789,15791],{"className":424,"code":15790,"language":396,"meta":426,"style":426},"# file: main.py\nimport computation\nfrom computation import PI, E\nfrom computation import pi_times\n\n\nprint(PI)\nprint(computation.E)\nprint(pi_times(2))\nprint(computation.pi_times(E))\n",[428,15792,15793,15797,15804,15819,15830,15834,15838,15848,15855,15866],{"__ignoreMap":426},[431,15794,15795],{"class":433,"line":434},[431,15796,15500],{"class":455},[431,15798,15799,15801],{"class":433,"line":452},[431,15800,5379],{"class":654},[431,15802,15803],{"class":441}," computation\n",[431,15805,15806,15808,15811,15813,15816],{"class":433,"line":578},[431,15807,5373],{"class":654},[431,15809,15810],{"class":441}," computation ",[431,15812,5379],{"class":654},[431,15814,15815],{"class":437}," PI",[431,15817,15818],{"class":441},", E\n",[431,15820,15821,15823,15825,15827],{"class":433,"line":584},[431,15822,5373],{"class":654},[431,15824,15810],{"class":441},[431,15826,5379],{"class":654},[431,15828,15829],{"class":441}," pi_times\n",[431,15831,15832],{"class":433,"line":1244},[431,15833,1662],{"emptyLinePlaceholder":393},[431,15835,15836],{"class":433,"line":1985},[431,15837,1662],{"emptyLinePlaceholder":393},[431,15839,15840,15842,15844,15846],{"class":433,"line":2041},[431,15841,438],{"class":437},[431,15843,442],{"class":441},[431,15845,2143],{"class":437},[431,15847,449],{"class":441},[431,15849,15850,15852],{"class":433,"line":4018},[431,15851,438],{"class":437},[431,15853,15854],{"class":441},"(computation.E)\n",[431,15856,15857,15859,15862,15864],{"class":433,"line":4030},[431,15858,438],{"class":437},[431,15860,15861],{"class":441},"(pi_times(",[431,15863,651],{"class":437},[431,15865,6157],{"class":441},[431,15867,15868,15870],{"class":433,"line":4419},[431,15869,438],{"class":437},[431,15871,15872],{"class":441},"(computation.pi_times(E))\n",[415,15874,15875],{},"Из примеров выше видно, что можно:",[697,15877,15878,15881,15884],{},[700,15879,15880],{},"Использовать оба способа импорта одновременно;",[700,15882,15883],{},"Импортировать отдельные определения в несколько заходов;",[700,15885,15886],{},"Получать доступ «через точку» к определениям, которые уже импортированы по имени;",[632,15888,15890],{"id":15889},"пакеты","Пакеты",[415,15892,15893],{},"Обычно код в больших проектах делят на модули — отдельные файлы, в которых хранится код на Python.\nНо иногда и этого разделения недостаточно.\nЧасто модули хочется сгруппировать «по смыслу» или сформировать отдельную группу модулей, чтобы использовать их в других проектах.\nВ таких случаях помогают пакеты — группы модулей.\nВ особенно больших проектах используются еще и подпакеты внутри пакетов, но на этой теме мы пока не будем останавливаться.\nНиже разберемся, как создавать пакеты и добавлять в них модули.\nТакже посмотрим, какими способами можно импортировать пакеты в проект.",[458,15895,15897],{"id":15896},"создание-пакета","Создание пакета",[415,15899,15900,15901,15904,15905,15908],{},"С точки зрения структуры ",[800,15902,15903],{},"пакет"," — это каталог (директория) с файлами модулей, имеющий имя в формате snake_case и содержащий специальный модуль с именем «",[800,15906,15907],{},"__init__.py","».\nИменно наличие этого специального файла подсказывает интерпретатору Python, что каталог следует воспринимать как пакет.\nРассмотрим пример самого простого пакета. Создадим пакет из каталога package и модуля __init__.py внутри этого каталога:",[422,15910,15912],{"className":1436,"code":15911,"language":1438,"meta":426,"style":426},"package\u002F\n└── __init__.py\n",[428,15913,15914,15919],{"__ignoreMap":426},[431,15915,15916],{"class":433,"line":434},[431,15917,15918],{},"package\u002F\n",[431,15920,15921],{"class":433,"line":452},[431,15922,15923],{},"└── __init__.py\n",[415,15925,15926,15927,15929],{},"В файл ",[428,15928,15907],{}," добавим следующий код:",[422,15931,15933],{"className":424,"code":15932,"language":396,"meta":426,"style":426},"# file __init__.py\nNAME = 'super_package'\n",[428,15934,15935,15940],{"__ignoreMap":426},[431,15936,15937],{"class":433,"line":434},[431,15938,15939],{"class":455},"# file __init__.py\n",[431,15941,15942,15945,15947],{"class":433,"line":452},[431,15943,15944],{"class":437},"NAME",[431,15946,2146],{"class":654},[431,15948,15949],{"class":445}," 'super_package'\n",[415,15951,15952],{},"Теперь у нас есть небольшой, но уже полноценный пакет. Его можно импортировать так же, как модуль:",[422,15954,15956],{"className":424,"code":15955,"language":396,"meta":426,"style":426},"import package\n\nprint(package.NAME)\n",[428,15957,15958,15965,15969],{"__ignoreMap":426},[431,15959,15960,15962],{"class":433,"line":434},[431,15961,5379],{"class":654},[431,15963,15964],{"class":441}," package\n",[431,15966,15967],{"class":433,"line":452},[431,15968,1662],{"emptyLinePlaceholder":393},[431,15970,15971,15973,15976,15978],{"class":433,"line":578},[431,15972,438],{"class":437},[431,15974,15975],{"class":441},"(package.",[431,15977,15944],{"class":437},[431,15979,449],{"class":441},[415,15981,15982,15983,15985,15986,15988],{},"Обратите внимание, что отдельно импортировать файл ",[428,15984,15907],{}," не нужно.\nПри первом обращении к пакету Python самостоятельно импортирует модуль ",[428,15987,15907],{},".\nЭто происходит автоматически, потому что каталог без init-файла не будет считаться пакетом.",[458,15990,15992],{"id":15991},"добавление-модуля-в-пакет","Добавление модуля в пакет",[415,15994,15995],{},"С простым пакетом все ясно — его можно использовать как модуль. Теперь перейдем к группировке.\nДобавим в пакет еще два модуля:",[422,15997,15999],{"className":1436,"code":15998,"language":1438,"meta":426,"style":426},"package\u002F\n├── constants.py\n├── functions.py\n└── __init__.py\n",[428,16000,16001,16005,16010,16015],{"__ignoreMap":426},[431,16002,16003],{"class":433,"line":434},[431,16004,15918],{},[431,16006,16007],{"class":433,"line":452},[431,16008,16009],{},"├── constants.py\n",[431,16011,16012],{"class":433,"line":578},[431,16013,16014],{},"├── functions.py\n",[431,16016,16017],{"class":433,"line":584},[431,16018,15923],{},[415,16020,16021,16022,3562],{},"Чтобы было понятнее, рассмотрим содержимое модуля ",[428,16023,16024],{},"constants.py",[422,16026,16028],{"className":424,"code":16027,"language":396,"meta":426,"style":426},"# file constants.py\nPERSON = 'Alex'\n",[428,16029,16030,16035],{"__ignoreMap":426},[431,16031,16032],{"class":433,"line":434},[431,16033,16034],{"class":455},"# file constants.py\n",[431,16036,16037,16040,16042],{"class":433,"line":452},[431,16038,16039],{"class":437},"PERSON",[431,16041,2146],{"class":654},[431,16043,5905],{"class":445},[415,16045,16046,16047,3562],{},"И содержимое модуля ",[428,16048,16049],{},"functions.py",[422,16051,16053],{"className":424,"code":16052,"language":396,"meta":426,"style":426},"# file functions.py\ndef greet(who):\n    print('Hello, ' + who + '!')\n",[428,16054,16055,16060,16070],{"__ignoreMap":426},[431,16056,16057],{"class":433,"line":434},[431,16058,16059],{"class":455},"# file functions.py\n",[431,16061,16062,16064,16067],{"class":433,"line":452},[431,16063,6330],{"class":654},[431,16065,16066],{"class":6333}," greet",[431,16068,16069],{"class":441},"(who):\n",[431,16071,16072,16074,16076,16078,16080,16083,16085,16087],{"class":433,"line":578},[431,16073,6357],{"class":437},[431,16075,442],{"class":441},[431,16077,5910],{"class":445},[431,16079,655],{"class":654},[431,16081,16082],{"class":441}," who ",[431,16084,802],{"class":654},[431,16086,5920],{"class":445},[431,16088,449],{"class":441},[415,16090,16091,16092,16094],{},"Теперь в пакете есть не только ",[428,16093,15907],{},", но и еще два модуля — теперь их можно импортировать.",[458,16096,16098],{"id":16097},"как-импортировать-пакеты","Как импортировать пакеты",[415,16100,16101],{},"Про модули упоминались два распространенных варианта импорта:",[697,16103,16104,16107],{},[700,16105,16106],{},"Квалифицированный импорт (также его называют «импорт модуля целиком»);",[700,16108,16109],{},"Импорт отдельных определений.",[415,16111,16112,16113,16116],{},"Применим оба способа импорта — но теперь уже не к модулям, а к пакетам.\n",[1355,16114,16115],{},"Квалифицированный импорт"," помогает писать понятный код.\nПрочитав строчку вызова функции, другой разработчик сразу поймет, откуда пришли сама функция и ее аргумент.\nВ этом примере квалифицированный импорт выглядит так:",[422,16118,16120],{"className":424,"code":16119,"language":396,"meta":426,"style":426},"import package.functions\nimport package.constants\n\npackage.functions.greet(package.constants.PERSON)  # => Hello, Alex!\n",[428,16121,16122,16129,16136,16140],{"__ignoreMap":426},[431,16123,16124,16126],{"class":433,"line":434},[431,16125,5379],{"class":654},[431,16127,16128],{"class":441}," package.functions\n",[431,16130,16131,16133],{"class":433,"line":452},[431,16132,5379],{"class":654},[431,16134,16135],{"class":441}," package.constants\n",[431,16137,16138],{"class":433,"line":578},[431,16139,1662],{"emptyLinePlaceholder":393},[431,16141,16142,16145,16147,16149],{"class":433,"line":584},[431,16143,16144],{"class":441},"package.functions.greet(package.constants.",[431,16146,16039],{"class":437},[431,16148,526],{"class":441},[431,16150,16151],{"class":455},"# => Hello, Alex!\n",[415,16153,16154],{},"Импорт отдельных определений удобнее в работе, потому что вам не придется каждый раз прописывать имя пакета и модуля.\nС другой стороны, другим разработчикам будет сложнее читать код.\nЧтобы узнать, откуда пришли функция и константа, им придется смотреть в блок импортов.\nПопробуем импортировать отдельные определения, то есть саму функцию и аргумент:",[422,16156,16158],{"className":424,"code":16157,"language":396,"meta":426,"style":426},"from package.functions import greet\nfrom package.constants import PERSON\n\ngreet(PERSON)  # => Hello, Alex!\n",[428,16159,16160,16172,16184,16188],{"__ignoreMap":426},[431,16161,16162,16164,16167,16169],{"class":433,"line":434},[431,16163,5373],{"class":654},[431,16165,16166],{"class":441}," package.functions ",[431,16168,5379],{"class":654},[431,16170,16171],{"class":441}," greet\n",[431,16173,16174,16176,16179,16181],{"class":433,"line":452},[431,16175,5373],{"class":654},[431,16177,16178],{"class":441}," package.constants ",[431,16180,5379],{"class":654},[431,16182,16183],{"class":437}," PERSON\n",[431,16185,16186],{"class":433,"line":578},[431,16187,1662],{"emptyLinePlaceholder":393},[431,16189,16190,16193,16195,16197],{"class":433,"line":584},[431,16191,16192],{"class":441},"greet(",[431,16194,16039],{"class":437},[431,16196,526],{"class":441},[431,16198,16151],{"class":455},[415,16200,16201],{},"Кроме того, импорты в Python бывают двух видов:",[697,16203,16204,16207],{},[700,16205,16206],{},"Абсолютные;",[700,16208,16209],{},"Относительные.",[415,16211,16212],{},"Для понимания пакетов критически важно обсудить подробности этих двух видов импортов.",[12129,16214,16216],{"id":16215},"абсолютный-импорт","Абсолютный импорт",[415,16218,16219],{},"В абсолютном импорте нужно прописывать полный путь до модуля, включающий все пакеты и подпакеты.\nПолные пути гарантируют простоту чтения и однозначность — так всем будет понятно, что и откуда импортируется.\nЧтобы вам было удобнее читать код, во всех примерах выше использовался абсолютный импорт.",[12129,16221,16223],{"id":16222},"относительный-импорт","Относительный импорт",[415,16225,16226],{},"Относительные импорты выглядят так:",[422,16228,16230],{"className":424,"code":16229,"language":396,"meta":426,"style":426},"from . import module\nfrom .module import function\nfrom .subpackage.module import CONSTANT\n",[428,16231,16232,16244,16256],{"__ignoreMap":426},[431,16233,16234,16236,16239,16241],{"class":433,"line":434},[431,16235,5373],{"class":654},[431,16237,16238],{"class":441}," . ",[431,16240,5379],{"class":654},[431,16242,16243],{"class":441}," module\n",[431,16245,16246,16248,16251,16253],{"class":433,"line":452},[431,16247,5373],{"class":654},[431,16249,16250],{"class":441}," .module ",[431,16252,5379],{"class":654},[431,16254,16255],{"class":441}," function\n",[431,16257,16258,16260,16263,16265],{"class":433,"line":578},[431,16259,5373],{"class":654},[431,16261,16262],{"class":441}," .subpackage.module ",[431,16264,5379],{"class":654},[431,16266,16267],{"class":437}," CONSTANT\n",[415,16269,16270],{},[1355,16271,16272],{},[800,16273,16274],{},"В относительном импорте используется точка, которая означает импорт модуля из текущей директории.",[415,16276,16277,16278,16280,16281,16284,16285,3228,16287,16289,16290,16292,16293,16296],{},"Например, мы работаем с файлом ",[428,16279,15383],{}," и хотим импортировать ",[428,16282,16283],{},".module",".\nПри этом мы знаем, что ",[428,16286,15383],{},[428,16288,16283],{}," хранятся в одной и той же директории.\nТогда можно не прописывать абсолютный путь к ",[428,16291,16283],{},", а воспользоваться ",[428,16294,16295],{},". import",".\nПо этой точке Python автоматически определит, что и откуда мы хотим импортировать.",[415,16298,16299],{},"Относительный импорт помогает писать быстрее, но слишком сильно запутывает код, что негативно сказывается на читаемости.\nИменно поэтому в сообществе Python-разработчиков есть распространенный совет для новичков: старайтесь пользоваться абсолютным импортом, даже в самых простых и очевидных случаях.",[632,16301,16303],{"id":16302},"модуль-random","Модуль random",[415,16305,16306],{},"Python знаменит тем, что в нем доступно большое количество стандартных библиотек — так называют модули и пакеты, в которых уже реализованы тысячи разных функций.\nРазработчику полезно разбираться в этих стандартных библиотеках, ведь это знание позволяет экономить время и силы.\nПредлагаю для начала познакомимся с одной из стандартных библиотек — модулем random.",[415,16308,16309],{},"При разработке программ иногда возникает потребность сгенерировать случайное число.\nДля этого в Python можно использовать модуль random. Он предоставляет множество функций, но пока остановимся на двух:",[697,16311,16312,16318],{},[700,16313,16314,16317],{},[428,16315,16316],{},"randint"," — сгенерировать целое число в заданном диапазоне;",[700,16319,16320,16323],{},[428,16321,16322],{},"choice"," — выбрать случайный элемент из заданного набора.",[458,16325,16327],{"id":16326},"генерация-случайных-чисел","Генерация случайных чисел",[415,16329,16330,16331,16333,16334,3562],{},"Чтобы сгенерировать случайное число, нужно импортировать функцию ",[428,16332,16316],{}," из модуля ",[428,16335,16336],{},"random",[422,16338,16340],{"className":424,"code":16339,"language":396,"meta":426,"style":426},"from random import randint\n",[428,16341,16342],{"__ignoreMap":426},[431,16343,16344,16346,16348,16350],{"class":433,"line":434},[431,16345,5373],{"class":654},[431,16347,5376],{"class":441},[431,16349,5379],{"class":654},[431,16351,16352],{"class":441}," randint\n",[415,16354,16355],{},"Для примера попробуем сгенерировать число от 1 до 100:",[422,16357,16359],{"className":424,"code":16358,"language":396,"meta":426,"style":426},"random_number = randint(1, 100)\n",[428,16360,16361],{"__ignoreMap":426},[431,16362,16363,16366,16368,16371,16373,16375,16377],{"class":433,"line":434},[431,16364,16365],{"class":441},"random_number ",[431,16367,1189],{"class":654},[431,16369,16370],{"class":441}," randint(",[431,16372,1192],{"class":437},[431,16374,4846],{"class":441},[431,16376,2249],{"class":437},[431,16378,449],{"class":441},[415,16380,16381,16382,16384],{},"Обратите внимание, что обе границы диапазона включены — значит, ",[428,16383,16316],{}," может выдать любое значение в диапазоне, в том числе 1 и 100.\nПерейдем к более сложному примеру:",[422,16386,16388],{"className":424,"code":16387,"language":396,"meta":426,"style":426},"string = 'abcde'\nrandom_index = randint(0, len(string) - 1)\nchar = string[random_index]\n",[428,16389,16390,16399,16422],{"__ignoreMap":426},[431,16391,16392,16394,16396],{"class":433,"line":434},[431,16393,14072],{"class":441},[431,16395,1189],{"class":654},[431,16397,16398],{"class":445}," 'abcde'\n",[431,16400,16401,16404,16406,16408,16410,16412,16414,16416,16418,16420],{"class":433,"line":452},[431,16402,16403],{"class":441},"random_index ",[431,16405,1189],{"class":654},[431,16407,16370],{"class":441},[431,16409,3302],{"class":437},[431,16411,4846],{"class":441},[431,16413,5205],{"class":437},[431,16415,13698],{"class":441},[431,16417,853],{"class":654},[431,16419,1032],{"class":437},[431,16421,449],{"class":441},[431,16423,16424,16427,16429],{"class":433,"line":578},[431,16425,16426],{"class":441},"char ",[431,16428,1189],{"class":654},[431,16430,16431],{"class":441}," string[random_index]\n",[415,16433,16434],{},"Здесь программа должна выбрать случайный символ из строки string. При этом:",[697,16436,16437,16440,16443],{},[700,16438,16439],{},"Строка в переменной string имеет длину 5;",[700,16441,16442],{},"Индекс последнего элемента в строке равен 4;",[700,16444,16445],{},"Символы строки индексируются с нуля.",[415,16447,16448,16449,16452],{},"Если мы попробуем сгенерировать число через ",[428,16450,16451],{},"randint(0, 5)",", то в какой-то момент получим значение 5.\nТогда программа выдаст ошибку IndexError: она не сможет выдать пятый символ из четырех.\nКак это предотвратить? Нужно не просто задать верхнюю границу диапазона, а вычислить ее — то есть вычесть единицу из длины строки.\nИменно так и сделано в примере кода выше.",[458,16454,16456],{"id":16455},"выбор-случайного-элемента","Выбор случайного элемента",[415,16458,16459,16460,16462,16463,16465],{},"Выше мы рассмотрели пример, в котором выбирается случайный символ строки.\nЭта задача возникает достаточно часто, поэтому в модуле ",[428,16461,16336],{}," существует функция ",[428,16464,16322],{},".\nЕсли использовать эту функцию, выбор случайного символа из строки будет выглядеть так:",[422,16467,16469],{"className":424,"code":16468,"language":396,"meta":426,"style":426},"from random import choice\n\nstring = 'abcde'\nchar = choice(string)\n",[428,16470,16471,16482,16486,16494],{"__ignoreMap":426},[431,16472,16473,16475,16477,16479],{"class":433,"line":434},[431,16474,5373],{"class":654},[431,16476,5376],{"class":441},[431,16478,5379],{"class":654},[431,16480,16481],{"class":441}," choice\n",[431,16483,16484],{"class":433,"line":452},[431,16485,1662],{"emptyLinePlaceholder":393},[431,16487,16488,16490,16492],{"class":433,"line":578},[431,16489,14072],{"class":441},[431,16491,1189],{"class":654},[431,16493,16398],{"class":445},[431,16495,16496,16498,16500],{"class":433,"line":584},[431,16497,16426],{"class":441},[431,16499,1189],{"class":654},[431,16501,16502],{"class":441}," choice(string)\n",[415,16504,16505,16506,16508,16509,16512],{},"Используя ",[428,16507,16322],{},", не нужно думать о границах диапазона — функция сама определяет, как правильно выбирать элементы.\nПри этом важно, чтобы строка для выбора не была пустой.\nИначе мы получим ошибку ",[428,16510,16511],{},"IndexError: Cannot choose from an empty sequence"," т.е. «Нельзя выбрать из пустой строки».",[415,16514,16515,16516,16519,16520],{},"В основе модуля random лежит генератор псевдослучайных чисел — на самом деле, число выбирается не случайно, а на основе сложных математических вычислений.\nИз-за этого random не принято использовать в сферах, где нужна повышенная безопасность.\nВ криптографии, шифровании и других подобных сферах используют модуль ",[428,16517,16518],{},"secrets",", в основе которого менее предсказуемый механизм случайной генерации.\nПодробнее о модуле random почитайте по ссылке: ",[1205,16521,16524],{"href":16522,"rel":16523},"https:\u002F\u002Fdocs.python.org\u002F3.11\u002Flibrary\u002Frandom.html",[1209],"Документация по модулю random.",[415,16526,16527],{},[1205,16528,16531],{"href":16529,"rel":16530},"https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002F%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80_%D0%BF%D1%81%D0%B5%D0%B2%D0%B4%D0%BE%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D1%87%D0%B8%D1%81%D0%B5%D0%BB",[1209],"Статья про генерацию случайных чисел.",[415,16533,1849,16534,1853,16536,1857],{},[800,16535,1852],{},[800,16537,1856],{},[1859,16539],{},[1862,16541,16542],{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":16544},[16545],{"id":15367,"depth":452,"text":198,"children":16546},[16547,16548,16549,16550,16551,16552,16560],{"id":15376,"depth":584,"text":15377},{"id":15474,"depth":584,"text":15475},{"id":15553,"depth":584,"text":15554},{"id":15675,"depth":584,"text":15676},{"id":15713,"depth":584,"text":15714},{"id":15889,"depth":578,"text":15890,"children":16553},[16554,16555,16556],{"id":15896,"depth":584,"text":15897},{"id":15991,"depth":584,"text":15992},{"id":16097,"depth":584,"text":16098,"children":16557},[16558,16559],{"id":16215,"depth":1244,"text":16216},{"id":16222,"depth":1244,"text":16223},{"id":16302,"depth":578,"text":16303,"children":16561},[16562,16563],{"id":16326,"depth":584,"text":16327},{"id":16455,"depth":584,"text":16456},"2025-02-22","Работа с модулями. Объединение отдельных модулей в пакет. Пример использования модуля random","images\u002Fblog\u002Fpython\u002Fst11\u002Fimg.png",{},{"title":198,"description":16565},"Yl9TNx-37HKu8864AdZDscbnE_EmuYyMgrXPExJm-Is",{"id":16571,"title":202,"author":16572,"body":16574,"date":17347,"description":17348,"extension":1887,"image":17349,"meta":17350,"minRead":2041,"navigation":393,"num":4446,"path":203,"seo":17351,"stem":204,"__hash__":17352},"python\u002Fblog\u002Fpython\u002Fst12.md",{"name":402,"avatar":16573},{"src":404,"alt":405},{"type":407,"value":16575,"toc":17335},[16576,16579,16582,16586,16592,16687,16690,16712,16715,16736,16739,16758,16762,16769,16821,16825,16828,16899,16903,16906,16949,16952,17015,17019,17022,17067,17070,17093,17096,17122,17128,17132,17135,17181,17184,17230,17234,17237,17324,17330,17332],[410,16577,202],{"id":16578},"кортежи",[415,16580,16581],{},"До этого момента мы встречались со строками, числами, булевыми значениями.\nВсе это — простые типы данных, то есть они не включают в себя данные других типов.\nНо часто в программировании приходится работать с несколькими типами данных одновременно.\nИменно поэтому во многих языках программирования есть составные типы — они могут включать в себя данные других типов.\nСоставные типы позволяют описывать сущности произвольной сложности, поэтому приносят много пользы.\nВ этой статье познакомимся с кортежем — одним из составных типов данных в Python.",[632,16583,16585],{"id":16584},"что-такое-кортеж","Что такое кортеж",[415,16587,16588,16591],{},[800,16589,16590],{},"Кортеж (tuple)"," — это несколько значений, записанных через запятую. Вот несколько примеров:",[422,16593,16595],{"className":424,"code":16594,"language":396,"meta":426,"style":426},"rgb_colour = (255, 127, 64)\nname_and_age = ('Alex', 42)\nthree_booleans = (True, False, True)\ntwo_pairs_of_numbers = ((1, 2), (3, 4))\n",[428,16596,16597,16621,16639,16660],{"__ignoreMap":426},[431,16598,16599,16602,16604,16606,16609,16611,16614,16616,16619],{"class":433,"line":434},[431,16600,16601],{"class":441},"rgb_colour ",[431,16603,1189],{"class":654},[431,16605,976],{"class":441},[431,16607,16608],{"class":437},"255",[431,16610,4846],{"class":441},[431,16612,16613],{"class":437},"127",[431,16615,4846],{"class":441},[431,16617,16618],{"class":437},"64",[431,16620,449],{"class":441},[431,16622,16623,16626,16628,16630,16633,16635,16637],{"class":433,"line":452},[431,16624,16625],{"class":441},"name_and_age ",[431,16627,1189],{"class":654},[431,16629,976],{"class":441},[431,16631,16632],{"class":445},"'Alex'",[431,16634,4846],{"class":441},[431,16636,9731],{"class":437},[431,16638,449],{"class":441},[431,16640,16641,16644,16646,16648,16650,16652,16654,16656,16658],{"class":433,"line":578},[431,16642,16643],{"class":441},"three_booleans ",[431,16645,1189],{"class":654},[431,16647,976],{"class":441},[431,16649,4463],{"class":437},[431,16651,4846],{"class":441},[431,16653,4431],{"class":437},[431,16655,4846],{"class":441},[431,16657,4463],{"class":437},[431,16659,449],{"class":441},[431,16661,16662,16665,16667,16670,16672,16674,16676,16679,16681,16683,16685],{"class":433,"line":584},[431,16663,16664],{"class":441},"two_pairs_of_numbers ",[431,16666,1189],{"class":654},[431,16668,16669],{"class":441}," ((",[431,16671,1192],{"class":437},[431,16673,4846],{"class":441},[431,16675,651],{"class":437},[431,16677,16678],{"class":441},"), (",[431,16680,971],{"class":437},[431,16682,4846],{"class":441},[431,16684,762],{"class":437},[431,16686,6157],{"class":441},[415,16688,16689],{},"При этом кортеж может состоять всего из одного элемента:",[422,16691,16693],{"className":424,"code":16692,"language":396,"meta":426,"style":426},"my_tuple = (42,)  # Ставим запятую, чтобы указать на кортеж\n",[428,16694,16695],{"__ignoreMap":426},[431,16696,16697,16700,16702,16704,16706,16709],{"class":433,"line":434},[431,16698,16699],{"class":441},"my_tuple ",[431,16701,1189],{"class":654},[431,16703,976],{"class":441},[431,16705,9731],{"class":437},[431,16707,16708],{"class":441},",)  ",[431,16710,16711],{"class":455},"# Ставим запятую, чтобы указать на кортеж\n",[415,16713,16714],{},"Обратите внимание на запятую — ее нужно ставить даже после единственного элемента кортежа.\nА теперь посмотрим на пример без запятой.\nВ этом случае Python подумает, что мы хотим вычислить значение арифметического выражения со скобками:",[422,16716,16718],{"className":424,"code":16717,"language":396,"meta":426,"style":426},"not_a_tuple = (42)  # Запятой нет, поэтому Python не считает это кортежем\n",[428,16719,16720],{"__ignoreMap":426},[431,16721,16722,16725,16727,16729,16731,16733],{"class":433,"line":434},[431,16723,16724],{"class":441},"not_a_tuple ",[431,16726,1189],{"class":654},[431,16728,976],{"class":441},[431,16730,9731],{"class":437},[431,16732,526],{"class":441},[431,16734,16735],{"class":455},"# Запятой нет, поэтому Python не считает это кортежем\n",[415,16737,16738],{},"Такая запись кортежа тоже допускается, скобки указывать не обязательно:",[422,16740,16742],{"className":424,"code":16741,"language":396,"meta":426,"style":426},"also_tuple = 1, 2\n",[428,16743,16744],{"__ignoreMap":426},[431,16745,16746,16749,16751,16753,16755],{"class":433,"line":434},[431,16747,16748],{"class":441},"also_tuple ",[431,16750,1189],{"class":654},[431,16752,1032],{"class":437},[431,16754,4846],{"class":441},[431,16756,16757],{"class":437},"2\n",[632,16759,16761],{"id":16760},"как-изменить-кортеж","Как изменить кортеж",[415,16763,16764,16765,16768],{},"Одна из особенностей кортежей в том, что это неизменяемый тип данных — то есть ",[800,16766,16767],{},"изменить кортеж после создания нельзя",".\nЧтобы добавить новое значение, нужно создать новый кортеж.\nПри попытке изменить кортеж мы получим такую ошибку:",[422,16770,16772],{"className":424,"code":16771,"language":396,"meta":426,"style":426},"name_and_age = ('Alex', 42)\nname_and_age[0] = 'Ben'\n# Traceback (most recent call last)\n# TypeError: 'tuple' object does not support item assignment\nname_and_age # ('Alex', 42)\n",[428,16773,16774,16790,16804,16809,16814],{"__ignoreMap":426},[431,16775,16776,16778,16780,16782,16784,16786,16788],{"class":433,"line":434},[431,16777,16625],{"class":441},[431,16779,1189],{"class":654},[431,16781,976],{"class":441},[431,16783,16632],{"class":445},[431,16785,4846],{"class":441},[431,16787,9731],{"class":437},[431,16789,449],{"class":441},[431,16791,16792,16795,16797,16799,16801],{"class":433,"line":452},[431,16793,16794],{"class":441},"name_and_age[",[431,16796,3302],{"class":437},[431,16798,4049],{"class":441},[431,16800,1189],{"class":654},[431,16802,16803],{"class":445}," 'Ben'\n",[431,16805,16806],{"class":433,"line":578},[431,16807,16808],{"class":455},"# Traceback (most recent call last)\n",[431,16810,16811],{"class":433,"line":584},[431,16812,16813],{"class":455},"# TypeError: 'tuple' object does not support item assignment\n",[431,16815,16816,16818],{"class":433,"line":1244},[431,16817,16625],{"class":441},[431,16819,16820],{"class":455},"# ('Alex', 42)\n",[632,16822,16824],{"id":16823},"как-работать-с-кортежами","Как работать с кортежами",[415,16826,16827],{},"Кортежи полезны, когда нужно вернуть сразу несколько значений.\nВозьмем для примера функцию, которая возвращает два значения одновременно: результат деления нацело и остаток от деления.\nВ коде это выглядит так:",[422,16829,16831],{"className":424,"code":16830,"language":396,"meta":426,"style":426},"def div_mod(a, b):\n    quotient = a \u002F\u002F b\n    modulo = a % b\n    return (quotient, modulo)\n\ndiv_mod(13, 4)  # (3, 1)\n",[428,16832,16833,16843,16858,16871,16878,16882],{"__ignoreMap":426},[431,16834,16835,16837,16840],{"class":433,"line":434},[431,16836,6330],{"class":654},[431,16838,16839],{"class":6333}," div_mod",[431,16841,16842],{"class":441},"(a, b):\n",[431,16844,16845,16848,16850,16852,16855],{"class":433,"line":452},[431,16846,16847],{"class":441},"    quotient ",[431,16849,1189],{"class":654},[431,16851,11260],{"class":441},[431,16853,16854],{"class":654},"\u002F\u002F",[431,16856,16857],{"class":441}," b\n",[431,16859,16860,16863,16865,16867,16869],{"class":433,"line":578},[431,16861,16862],{"class":441},"    modulo ",[431,16864,1189],{"class":654},[431,16866,11260],{"class":441},[431,16868,8667],{"class":654},[431,16870,16857],{"class":441},[431,16872,16873,16875],{"class":433,"line":584},[431,16874,6599],{"class":654},[431,16876,16877],{"class":441}," (quotient, modulo)\n",[431,16879,16880],{"class":433,"line":1244},[431,16881,1662],{"emptyLinePlaceholder":393},[431,16883,16884,16887,16890,16892,16894,16896],{"class":433,"line":1985},[431,16885,16886],{"class":441},"div_mod(",[431,16888,16889],{"class":437},"13",[431,16891,4846],{"class":441},[431,16893,762],{"class":437},[431,16895,526],{"class":441},[431,16897,16898],{"class":455},"# (3, 1)\n",[458,16900,16902],{"id":16901},"как-извлекать-значения-из-кортежа","Как извлекать значения из кортежа",[415,16904,16905],{},"Выше мы научились создавать кортежи, а теперь попробуем извлекать значения из них.\nДля этого достаточно обратиться к элементу кортежа по индексу:",[422,16907,16909],{"className":424,"code":16908,"language":396,"meta":426,"style":426},"name_and_age = ('Alex', 42)\nname_and_age[0]  # 'Alex'\nname_and_age[1]  # 42\n",[428,16910,16911,16927,16938],{"__ignoreMap":426},[431,16912,16913,16915,16917,16919,16921,16923,16925],{"class":433,"line":434},[431,16914,16625],{"class":441},[431,16916,1189],{"class":654},[431,16918,976],{"class":441},[431,16920,16632],{"class":445},[431,16922,4846],{"class":441},[431,16924,9731],{"class":437},[431,16926,449],{"class":441},[431,16928,16929,16931,16933,16935],{"class":433,"line":452},[431,16930,16794],{"class":441},[431,16932,3302],{"class":437},[431,16934,3612],{"class":441},[431,16936,16937],{"class":455},"# 'Alex'\n",[431,16939,16940,16942,16944,16946],{"class":433,"line":578},[431,16941,16794],{"class":441},[431,16943,1192],{"class":437},[431,16945,3612],{"class":441},[431,16947,16948],{"class":455},"# 42\n",[415,16950,16951],{},"Также у кортежа есть длина, которую можно получить с помощью функции len():",[422,16953,16955],{"className":424,"code":16954,"language":396,"meta":426,"style":426},"tuple = (42,)  # (42,)\nlen(tuple)     # 1\npair = (1, 2)  # (1, 2)\nlen(pair)      # 2\n",[428,16956,16957,16973,16986,17006],{"__ignoreMap":426},[431,16958,16959,16962,16964,16966,16968,16970],{"class":433,"line":434},[431,16960,16961],{"class":437},"tuple",[431,16963,2146],{"class":654},[431,16965,976],{"class":441},[431,16967,9731],{"class":437},[431,16969,16708],{"class":441},[431,16971,16972],{"class":455},"# (42,)\n",[431,16974,16975,16977,16979,16981,16984],{"class":433,"line":452},[431,16976,5205],{"class":437},[431,16978,442],{"class":441},[431,16980,16961],{"class":437},[431,16982,16983],{"class":441},")     ",[431,16985,13119],{"class":455},[431,16987,16988,16991,16993,16995,16997,16999,17001,17003],{"class":433,"line":578},[431,16989,16990],{"class":441},"pair ",[431,16992,1189],{"class":654},[431,16994,976],{"class":441},[431,16996,1192],{"class":437},[431,16998,4846],{"class":441},[431,17000,651],{"class":437},[431,17002,526],{"class":441},[431,17004,17005],{"class":455},"# (1, 2)\n",[431,17007,17008,17010,17013],{"class":433,"line":584},[431,17009,5205],{"class":437},[431,17011,17012],{"class":441},"(pair)      ",[431,17014,5652],{"class":455},[458,17016,17018],{"id":17017},"как-разделить-значения-из-кортежа","Как разделить значения из кортежа",[415,17020,17021],{},"Часто кортежи содержат значения разных типов. Сложно запомнить, каким индексом обозначается каждое значение.\nЧтобы упростить работу, можно разобрать кортеж:",[422,17023,17025],{"className":424,"code":17024,"language":396,"meta":426,"style":426},"name_and_age = ('Alex', 42)\n(name, age) = name_and_age\nname  # 'Alex'\nage   # 42\n",[428,17026,17027,17043,17053,17060],{"__ignoreMap":426},[431,17028,17029,17031,17033,17035,17037,17039,17041],{"class":433,"line":434},[431,17030,16625],{"class":441},[431,17032,1189],{"class":654},[431,17034,976],{"class":441},[431,17036,16632],{"class":445},[431,17038,4846],{"class":441},[431,17040,9731],{"class":437},[431,17042,449],{"class":441},[431,17044,17045,17048,17050],{"class":433,"line":452},[431,17046,17047],{"class":441},"(name, age) ",[431,17049,1189],{"class":654},[431,17051,17052],{"class":441}," name_and_age\n",[431,17054,17055,17058],{"class":433,"line":578},[431,17056,17057],{"class":441},"name  ",[431,17059,16937],{"class":455},[431,17061,17062,17065],{"class":433,"line":584},[431,17063,17064],{"class":441},"age   ",[431,17066,16948],{"class":455},[415,17068,17069],{},"Также этот процесс может называться распаковкой.\nТаким же способом можно получать и сразу разбирать значения, которые возвращает функция:",[422,17071,17073],{"className":424,"code":17072,"language":396,"meta":426,"style":426},"(quotient, modulo) = div_mod(13, 4)\n",[428,17074,17075],{"__ignoreMap":426},[431,17076,17077,17080,17082,17085,17087,17089,17091],{"class":433,"line":434},[431,17078,17079],{"class":441},"(quotient, modulo) ",[431,17081,1189],{"class":654},[431,17083,17084],{"class":441}," div_mod(",[431,17086,16889],{"class":437},[431,17088,4846],{"class":441},[431,17090,762],{"class":437},[431,17092,449],{"class":441},[415,17094,17095],{},"Соответственно, кортеж из одного элемента разбирается так:",[422,17097,17099],{"className":424,"code":17098,"language":396,"meta":426,"style":426},"(a,) = (42,)\na  # 42\n",[428,17100,17101,17115],{"__ignoreMap":426},[431,17102,17103,17106,17108,17110,17112],{"class":433,"line":434},[431,17104,17105],{"class":441},"(a,) ",[431,17107,1189],{"class":654},[431,17109,976],{"class":441},[431,17111,9731],{"class":437},[431,17113,17114],{"class":441},",)\n",[431,17116,17117,17120],{"class":433,"line":452},[431,17118,17119],{"class":441},"a  ",[431,17121,16948],{"class":455},[415,17123,17124,17125,17127],{},"Если после имени переменной не поставить запятую, то синтаксической ошибки не будет, но в переменную ",[428,17126,1205],{}," кортеж запишется целиком — ничего не распакуется.\nЭто логическая ошибка — мы получим не тот результат, который ожидали.",[632,17129,17131],{"id":17130},"кортежи-и-множественное-присваивание","Кортежи и множественное присваивание",[415,17133,17134],{},"Кортежи легко собирать и разбирать, поэтому в Python удобно делать множественное присваивание:",[422,17136,17138],{"className":424,"code":17137,"language":396,"meta":426,"style":426},"(a, b, c) = (1, 2, 3)\na  # 1\nb  # 2\nc  # 3\n",[428,17139,17140,17161,17167,17174],{"__ignoreMap":426},[431,17141,17142,17145,17147,17149,17151,17153,17155,17157,17159],{"class":433,"line":434},[431,17143,17144],{"class":441},"(a, b, c) ",[431,17146,1189],{"class":654},[431,17148,976],{"class":441},[431,17150,1192],{"class":437},[431,17152,4846],{"class":441},[431,17154,651],{"class":437},[431,17156,4846],{"class":441},[431,17158,971],{"class":437},[431,17160,449],{"class":441},[431,17162,17163,17165],{"class":433,"line":452},[431,17164,17119],{"class":441},[431,17166,13119],{"class":455},[431,17168,17169,17172],{"class":433,"line":578},[431,17170,17171],{"class":441},"b  ",[431,17173,5652],{"class":455},[431,17175,17176,17179],{"class":433,"line":584},[431,17177,17178],{"class":441},"c  ",[431,17180,5340],{"class":455},[415,17182,17183],{},"Используя множественное присваивание, можно обменять значения между двумя переменными. Так это выглядит:",[422,17185,17187],{"className":424,"code":17186,"language":396,"meta":426,"style":426},"a = 100\nb = 'foo'\n(a, b) = (b, a)\na  # 'foo'\nb  # 100\n",[428,17188,17189,17198,17207,17217,17224],{"__ignoreMap":426},[431,17190,17191,17193,17195],{"class":433,"line":434},[431,17192,3193],{"class":441},[431,17194,1189],{"class":654},[431,17196,17197],{"class":437}," 100\n",[431,17199,17200,17202,17204],{"class":433,"line":452},[431,17201,3203],{"class":441},[431,17203,1189],{"class":654},[431,17205,17206],{"class":445}," 'foo'\n",[431,17208,17209,17212,17214],{"class":433,"line":578},[431,17210,17211],{"class":441},"(a, b) ",[431,17213,1189],{"class":654},[431,17215,17216],{"class":441}," (b, a)\n",[431,17218,17219,17221],{"class":433,"line":584},[431,17220,17119],{"class":441},[431,17222,17223],{"class":455},"# 'foo'\n",[431,17225,17226,17228],{"class":433,"line":1244},[431,17227,17171],{"class":441},[431,17229,13134],{"class":455},[632,17231,17233],{"id":17232},"кортежи-как-аргументы-функций","Кортежи как аргументы функций",[415,17235,17236],{},"Также кортежи можно передавать в качестве аргументов в функцию и разбирать уже внутри нее:",[422,17238,17240],{"className":424,"code":17239,"language":396,"meta":426,"style":426},"def print_person_info(person):\n    name, age = person # разбираем переданный кортеж\n    print(f'{name} is {age} years old')\n\nperson_tuple = ('Alex', 42)\nprint_person_info(person_tuple)  # => Alex is 42 years old\n",[428,17241,17242,17252,17265,17295,17299,17316],{"__ignoreMap":426},[431,17243,17244,17246,17249],{"class":433,"line":434},[431,17245,6330],{"class":654},[431,17247,17248],{"class":6333}," print_person_info",[431,17250,17251],{"class":441},"(person):\n",[431,17253,17254,17257,17259,17262],{"class":433,"line":452},[431,17255,17256],{"class":441},"    name, age ",[431,17258,1189],{"class":654},[431,17260,17261],{"class":441}," person ",[431,17263,17264],{"class":455},"# разбираем переданный кортеж\n",[431,17266,17267,17269,17271,17273,17275,17277,17279,17281,17284,17286,17288,17290,17293],{"class":433,"line":578},[431,17268,6357],{"class":437},[431,17270,442],{"class":441},[431,17272,2990],{"class":654},[431,17274,2993],{"class":445},[431,17276,2996],{"class":437},[431,17278,15398],{"class":441},[431,17280,3002],{"class":437},[431,17282,17283],{"class":445}," is ",[431,17285,2996],{"class":437},[431,17287,8180],{"class":441},[431,17289,3002],{"class":437},[431,17291,17292],{"class":445}," years old'",[431,17294,449],{"class":441},[431,17296,17297],{"class":433,"line":584},[431,17298,1662],{"emptyLinePlaceholder":393},[431,17300,17301,17304,17306,17308,17310,17312,17314],{"class":433,"line":1244},[431,17302,17303],{"class":441},"person_tuple ",[431,17305,1189],{"class":654},[431,17307,976],{"class":441},[431,17309,16632],{"class":445},[431,17311,4846],{"class":441},[431,17313,9731],{"class":437},[431,17315,449],{"class":441},[431,17317,17318,17321],{"class":433,"line":1985},[431,17319,17320],{"class":441},"print_person_info(person_tuple)  ",[431,17322,17323],{"class":455},"# => Alex is 42 years old\n",[415,17325,1849,17326,1853,17328,1857],{},[800,17327,1852],{},[800,17329,1856],{},[1859,17331],{},[1862,17333,17334],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":426,"searchDepth":452,"depth":1244,"links":17336},[17337],{"id":16578,"depth":452,"text":202,"children":17338},[17339,17340,17341,17345,17346],{"id":16584,"depth":578,"text":16585},{"id":16760,"depth":578,"text":16761},{"id":16823,"depth":578,"text":16824,"children":17342},[17343,17344],{"id":16901,"depth":584,"text":16902},{"id":17017,"depth":584,"text":17018},{"id":17130,"depth":578,"text":17131},{"id":17232,"depth":578,"text":17233},"2025-03-02","Работа с кортежами. Извлечение значений и разделения кортежей","images\u002Fblog\u002Fpython\u002Fst12\u002Fimg.png",{},{"title":202,"description":17348},"r8N06M2r4YacOq9tkx19wIooVxTfohUgWtINbVwm4xo",{"id":17354,"title":206,"author":17355,"body":17357,"date":18562,"description":18563,"extension":1887,"image":18564,"meta":18565,"minRead":4451,"navigation":393,"num":4451,"path":207,"seo":18566,"stem":208,"__hash__":18567},"python\u002Fblog\u002Fpython\u002Fst13.md",{"name":402,"avatar":17356},{"src":404,"alt":405},{"type":407,"value":17358,"toc":18548},[17359,17362,17365,17379,17382,17417,17420,17423,17426,17429,17443,17447,17450,17454,17510,17517,17521,17524,17597,17603,17642,17645,17685,17688,17742,17745,17791,17794,17835,17839,17842,17876,17879,17883,17886,17938,17942,17949,18025,18031,18083,18089,18152,18155,18201,18207,18211,18217,18267,18273,18319,18323,18326,18367,18370,18453,18456,18537,18543,18545],[410,17360,206],{"id":17361},"знакомство-со-списками",[415,17363,17364],{},"Программирование становится по-настоящему интересным, когда появляется возможность работать с наборами элементов.\nВот лишь некоторые примеры того, где они встречаются:",[697,17366,17367,17370,17373,17376],{},[700,17368,17369],{},"Подсчет общей суммы в заказе на основании каждой из позиций",[700,17371,17372],{},"Обработка набора DOM-узлов (HTML, фронтенд-разработка)",[700,17374,17375],{},"Постраничный вывод данных на сайте",[700,17377,17378],{},"Вывод списка друзей, сообщений, фильмов и тому подобное",[415,17380,17381],{},"Любые списки, которые окружают нас в реальном или виртуальном мире, являются коллекциями элементов с точки зрения программирования.\nВ Python для их хранения используется список – структура данных, позволяющая работать с набором как с единым целым:",[422,17383,17385],{"className":424,"code":17384,"language":396,"meta":426,"style":426},"# Определение списка покупок\nshops = ['мыло', 'порошок', 'зубная паста']\n",[428,17386,17387,17392],{"__ignoreMap":426},[431,17388,17389],{"class":433,"line":434},[431,17390,17391],{"class":455},"# Определение списка покупок\n",[431,17393,17394,17397,17399,17402,17405,17407,17410,17412,17415],{"class":433,"line":452},[431,17395,17396],{"class":441},"shops ",[431,17398,1189],{"class":654},[431,17400,17401],{"class":441}," [",[431,17403,17404],{"class":445},"'мыло'",[431,17406,4846],{"class":441},[431,17408,17409],{"class":445},"'порошок'",[431,17411,4846],{"class":441},[431,17413,17414],{"class":445},"'зубная паста'",[431,17416,3568],{"class":441},[415,17418,17419],{},"В отличие от примитивных типов данных, списки в Python могут изменяться.\nПричем, как по содержимому, так и по размеру самого списка.\nЭто сильно влияет на работу с ними и добавляет с одной стороны больше возможностей, а с другой – ответственности.",[415,17421,17422],{},"Используя списки, одну и ту же задачу можно решить множеством разных способов.\nТолько некоторые из них будут хорошими, остальные же — неэффективными, сложными в отладке и анализе.",[415,17424,17425],{},"Именно поэтому спискам посвящено несколько статей и множество часов работы с ними.",[415,17427,17428],{},"Далее рассматриваются несколько ситуаций, которые традиционно решаются с помощью списков.\nОсновные темы:",[697,17430,17431,17434,17437,17440],{},[700,17432,17433],{},"Манипуляции со списками",[700,17435,17436],{},"Обработка списков в циклах",[700,17438,17439],{},"Работа с вложенными списками и вложенными циклами",[700,17441,17442],{},"Сортировка списков",[632,17444,17446],{"id":17445},"синтаксис","Синтаксис",[415,17448,17449],{},"Списки в Python представляют любые упорядоченные наборы, коллекции элементов, ученики в группе или друзья в вашей социальной сети.\nЗадача списка — представить такие коллекции в виде единой структуры, которая позволяет работать с ними как с единым целым.",[458,17451,17453],{"id":17452},"определение-списка","Определение списка",[422,17455,17457],{"className":424,"code":17456,"language":396,"meta":426,"style":426},"# Создание пустого списка\nitems = []  # Или так items = list()\n\n# Создание списка с тремя элементами\nanimals = ['cats', 'dogs', 'birds']\n",[428,17458,17459,17464,17477,17481,17486],{"__ignoreMap":426},[431,17460,17461],{"class":433,"line":434},[431,17462,17463],{"class":455},"# Создание пустого списка\n",[431,17465,17466,17469,17471,17474],{"class":433,"line":452},[431,17467,17468],{"class":441},"items ",[431,17470,1189],{"class":654},[431,17472,17473],{"class":441}," []  ",[431,17475,17476],{"class":455},"# Или так items = list()\n",[431,17478,17479],{"class":433,"line":578},[431,17480,1662],{"emptyLinePlaceholder":393},[431,17482,17483],{"class":433,"line":584},[431,17484,17485],{"class":455},"# Создание списка с тремя элементами\n",[431,17487,17488,17491,17493,17495,17498,17500,17503,17505,17508],{"class":433,"line":1244},[431,17489,17490],{"class":441},"animals ",[431,17492,1189],{"class":654},[431,17494,17401],{"class":441},[431,17496,17497],{"class":445},"'cats'",[431,17499,4846],{"class":441},[431,17501,17502],{"class":445},"'dogs'",[431,17504,4846],{"class":441},[431,17506,17507],{"class":445},"'birds'",[431,17509,3568],{"class":441},[415,17511,17512,17513,17516],{},"В примере происходит определение списка ",[428,17514,17515],{},"['cats', 'dogs', 'birds']",", который затем присваивается переменной animals.\nОбратите внимание на именование переменных, содержащих списки. Они во множественном числе.\nЭто подчеркивает природу переменной и делает код проще для анализа.",[458,17518,17520],{"id":17519},"получение-данных","Получение данных",[415,17522,17523],{},"Элементы в списке упорядочены слева направо. Каждый элемент имеет порядковый номер, называемый индексом.\nИндексация списка начинается с нуля.\nТо есть первый элемент списка доступен по индексу 0, второй — по индексу 1 и так далее.\nДля извлечения элемента из списка по индексу используется особый синтаксис:",[422,17525,17527],{"className":424,"code":17526,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\nanimals[0] # 'cats'\nanimals[1] # 'dogs'\n\n# Последний индекс в списке всегда меньше размера списка на единицу.\n# В этом списке три элемента, но последний индекс равен двум\nanimals[2] # 'birds'\n",[428,17528,17529,17549,17561,17572,17576,17581,17586],{"__ignoreMap":426},[431,17530,17531,17533,17535,17537,17539,17541,17543,17545,17547],{"class":433,"line":434},[431,17532,17490],{"class":441},[431,17534,1189],{"class":654},[431,17536,17401],{"class":441},[431,17538,17497],{"class":445},[431,17540,4846],{"class":441},[431,17542,17502],{"class":445},[431,17544,4846],{"class":441},[431,17546,17507],{"class":445},[431,17548,3568],{"class":441},[431,17550,17551,17554,17556,17558],{"class":433,"line":452},[431,17552,17553],{"class":441},"animals[",[431,17555,3302],{"class":437},[431,17557,4049],{"class":441},[431,17559,17560],{"class":455},"# 'cats'\n",[431,17562,17563,17565,17567,17569],{"class":433,"line":578},[431,17564,17553],{"class":441},[431,17566,1192],{"class":437},[431,17568,4049],{"class":441},[431,17570,17571],{"class":455},"# 'dogs'\n",[431,17573,17574],{"class":433,"line":584},[431,17575,1662],{"emptyLinePlaceholder":393},[431,17577,17578],{"class":433,"line":1244},[431,17579,17580],{"class":455},"# Последний индекс в списке всегда меньше размера списка на единицу.\n",[431,17582,17583],{"class":433,"line":1985},[431,17584,17585],{"class":455},"# В этом списке три элемента, но последний индекс равен двум\n",[431,17587,17588,17590,17592,17594],{"class":433,"line":2041},[431,17589,17553],{"class":441},[431,17591,651],{"class":437},[431,17593,4049],{"class":441},[431,17595,17596],{"class":455},"# 'birds'\n",[415,17598,17599,17600,2699],{},"Узнать размер списка можно, с помощью функции ",[428,17601,17602],{},"len()",[422,17604,17606],{"className":424,"code":17605,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\n# У списков много других методов\nlen(animals) # 3   \n",[428,17607,17608,17628,17633],{"__ignoreMap":426},[431,17609,17610,17612,17614,17616,17618,17620,17622,17624,17626],{"class":433,"line":434},[431,17611,17490],{"class":441},[431,17613,1189],{"class":654},[431,17615,17401],{"class":441},[431,17617,17497],{"class":445},[431,17619,4846],{"class":441},[431,17621,17502],{"class":445},[431,17623,4846],{"class":441},[431,17625,17507],{"class":445},[431,17627,3568],{"class":441},[431,17629,17630],{"class":433,"line":452},[431,17631,17632],{"class":455},"# У списков много других методов\n",[431,17634,17635,17637,17640],{"class":433,"line":578},[431,17636,5205],{"class":437},[431,17638,17639],{"class":441},"(animals) ",[431,17641,5340],{"class":455},[415,17643,17644],{},"В реальных задачах индекс часто вычисляется динамически, поэтому обращение к конкретному элементу происходит с использованием переменных:",[422,17646,17648],{"className":424,"code":17647,"language":396,"meta":426,"style":426},"i = 1\nanimals = ['cats', 'dogs', 'birds']\nanimals[i] # 'dogs'\n",[428,17649,17650,17658,17678],{"__ignoreMap":426},[431,17651,17652,17654,17656],{"class":433,"line":434},[431,17653,3454],{"class":441},[431,17655,1189],{"class":654},[431,17657,3916],{"class":437},[431,17659,17660,17662,17664,17666,17668,17670,17672,17674,17676],{"class":433,"line":452},[431,17661,17490],{"class":441},[431,17663,1189],{"class":654},[431,17665,17401],{"class":441},[431,17667,17497],{"class":445},[431,17669,4846],{"class":441},[431,17671,17502],{"class":445},[431,17673,4846],{"class":441},[431,17675,17507],{"class":445},[431,17677,3568],{"class":441},[431,17679,17680,17683],{"class":433,"line":578},[431,17681,17682],{"class":441},"animals[i] ",[431,17684,17571],{"class":455},[415,17686,17687],{},"И даже так:",[422,17689,17691],{"className":424,"code":17690,"language":396,"meta":426,"style":426},"i = 1\nj = 1\nanimals = ['cats', 'dogs', 'birds']\nanimals[i + j] # 'birds'\n",[428,17692,17693,17701,17710,17730],{"__ignoreMap":426},[431,17694,17695,17697,17699],{"class":433,"line":434},[431,17696,3454],{"class":441},[431,17698,1189],{"class":654},[431,17700,3916],{"class":437},[431,17702,17703,17706,17708],{"class":433,"line":452},[431,17704,17705],{"class":441},"j ",[431,17707,1189],{"class":654},[431,17709,3916],{"class":437},[431,17711,17712,17714,17716,17718,17720,17722,17724,17726,17728],{"class":433,"line":578},[431,17713,17490],{"class":441},[431,17715,1189],{"class":654},[431,17717,17401],{"class":441},[431,17719,17497],{"class":445},[431,17721,4846],{"class":441},[431,17723,17502],{"class":445},[431,17725,4846],{"class":441},[431,17727,17507],{"class":445},[431,17729,3568],{"class":441},[431,17731,17732,17735,17737,17740],{"class":433,"line":584},[431,17733,17734],{"class":441},"animals[i ",[431,17736,802],{"class":654},[431,17738,17739],{"class":441}," j] ",[431,17741,17596],{"class":455},[415,17743,17744],{},"Такой вызов возможен по одной простой причине — внутри скобок ожидается выражение.\nА там, где ожидается выражение, можно подставлять все, что вычисляется. В том числе вызовы функций:",[422,17746,17748],{"className":424,"code":17747,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\nanimals[len(['a', 'b'])] # 'birds'\n",[428,17749,17750,17770],{"__ignoreMap":426},[431,17751,17752,17754,17756,17758,17760,17762,17764,17766,17768],{"class":433,"line":434},[431,17753,17490],{"class":441},[431,17755,1189],{"class":654},[431,17757,17401],{"class":441},[431,17759,17497],{"class":445},[431,17761,4846],{"class":441},[431,17763,17502],{"class":445},[431,17765,4846],{"class":441},[431,17767,17507],{"class":445},[431,17769,3568],{"class":441},[431,17771,17772,17774,17776,17779,17781,17783,17786,17789],{"class":433,"line":452},[431,17773,17553],{"class":441},[431,17775,5205],{"class":437},[431,17777,17778],{"class":441},"([",[431,17780,14965],{"class":445},[431,17782,4846],{"class":441},[431,17784,17785],{"class":445},"'b'",[431,17787,17788],{"class":441},"])] ",[431,17790,17596],{"class":455},[415,17792,17793],{},"В Python индексы можно указывать не только положительные, но и отрицательные.\nВ таком случае отсчет происходит с конца списка.\nДовольно часто в задачах с использованием списков нужно взять последний элемент.\nВ Python для этого достаточно лишь указать индекс элемента -1:",[422,17795,17797],{"className":424,"code":17796,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\nprint(animals[-1])  # birds\n",[428,17798,17799,17819],{"__ignoreMap":426},[431,17800,17801,17803,17805,17807,17809,17811,17813,17815,17817],{"class":433,"line":434},[431,17802,17490],{"class":441},[431,17804,1189],{"class":654},[431,17806,17401],{"class":441},[431,17808,17497],{"class":445},[431,17810,4846],{"class":441},[431,17812,17502],{"class":445},[431,17814,4846],{"class":441},[431,17816,17507],{"class":445},[431,17818,3568],{"class":441},[431,17820,17821,17823,17826,17828,17830,17832],{"class":433,"line":452},[431,17822,438],{"class":437},[431,17824,17825],{"class":441},"(animals[",[431,17827,853],{"class":654},[431,17829,1192],{"class":437},[431,17831,3305],{"class":441},[431,17833,17834],{"class":455},"# birds\n",[632,17836,17838],{"id":17837},"модификация","Модификация",[415,17840,17841],{},"Примитивные типы данных невозможно изменять.\nЛюбые функции и методы над ними возвращают новые значения, но не могут ничего сделать со старым.",[422,17843,17845],{"className":424,"code":17844,"language":396,"meta":426,"style":426},"name = 'Python'\nname.upper() # 'PYTHON'\n# Значение name не поменялось\nprint(name) # 'Python'\n",[428,17846,17847,17855,17862,17867],{"__ignoreMap":426},[431,17848,17849,17851,17853],{"class":433,"line":434},[431,17850,3287],{"class":441},[431,17852,1189],{"class":654},[431,17854,3648],{"class":445},[431,17856,17857,17860],{"class":433,"line":452},[431,17858,17859],{"class":441},"name.upper() ",[431,17861,5613],{"class":455},[431,17863,17864],{"class":433,"line":578},[431,17865,17866],{"class":455},"# Значение name не поменялось\n",[431,17868,17869,17871,17873],{"class":433,"line":584},[431,17870,438],{"class":437},[431,17872,5167],{"class":441},[431,17874,17875],{"class":455},"# 'Python'\n",[415,17877,17878],{},"Со списками это правило не работает. Списки могут меняться: увеличиваться, уменьшаться, изменять значения по индексам.\nНиже разберем основные операции.",[458,17880,17882],{"id":17881},"изменение-элементов-списка","Изменение элементов списка",[415,17884,17885],{},"Синтаксис изменения элемента списка практически такой же, как и при обращении к элементу списка.\nРазница лишь в наличии присваивания:",[422,17887,17889],{"className":424,"code":17888,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\n# Меняется первый элемент списка\nanimals[0] = 'horses'\nprint(animals) # => [ 'horses', 'dogs', 'birds' ]\n",[428,17890,17891,17911,17916,17929],{"__ignoreMap":426},[431,17892,17893,17895,17897,17899,17901,17903,17905,17907,17909],{"class":433,"line":434},[431,17894,17490],{"class":441},[431,17896,1189],{"class":654},[431,17898,17401],{"class":441},[431,17900,17497],{"class":445},[431,17902,4846],{"class":441},[431,17904,17502],{"class":445},[431,17906,4846],{"class":441},[431,17908,17507],{"class":445},[431,17910,3568],{"class":441},[431,17912,17913],{"class":433,"line":452},[431,17914,17915],{"class":455},"# Меняется первый элемент списка\n",[431,17917,17918,17920,17922,17924,17926],{"class":433,"line":578},[431,17919,17553],{"class":441},[431,17921,3302],{"class":437},[431,17923,4049],{"class":441},[431,17925,1189],{"class":654},[431,17927,17928],{"class":445}," 'horses'\n",[431,17930,17931,17933,17935],{"class":433,"line":584},[431,17932,438],{"class":437},[431,17934,17639],{"class":441},[431,17936,17937],{"class":455},"# => [ 'horses', 'dogs', 'birds' ]\n",[458,17939,17941],{"id":17940},"добавление-элемента-в-список","Добавление элемента в список",[415,17943,17944,17945,17948],{},"Метод ",[428,17946,17947],{},"append()"," добавляет элемент в конец списка:",[422,17950,17952],{"className":424,"code":17951,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\nanimals.append('horses')\n\n# Список animals изменен — стал больше\nprint(animals) # => [ 'cats', 'dogs', 'birds', 'horses' ]\n\n# Строка 'horses' была добавлена в конец списка (индекс = 3)\nprint(animals[3]) # => 'horses'\n",[428,17953,17954,17974,17984,17988,17993,18002,18006,18011],{"__ignoreMap":426},[431,17955,17956,17958,17960,17962,17964,17966,17968,17970,17972],{"class":433,"line":434},[431,17957,17490],{"class":441},[431,17959,1189],{"class":654},[431,17961,17401],{"class":441},[431,17963,17497],{"class":445},[431,17965,4846],{"class":441},[431,17967,17502],{"class":445},[431,17969,4846],{"class":441},[431,17971,17507],{"class":445},[431,17973,3568],{"class":441},[431,17975,17976,17979,17982],{"class":433,"line":452},[431,17977,17978],{"class":441},"animals.append(",[431,17980,17981],{"class":445},"'horses'",[431,17983,449],{"class":441},[431,17985,17986],{"class":433,"line":578},[431,17987,1662],{"emptyLinePlaceholder":393},[431,17989,17990],{"class":433,"line":584},[431,17991,17992],{"class":455},"# Список animals изменен — стал больше\n",[431,17994,17995,17997,17999],{"class":433,"line":1244},[431,17996,438],{"class":437},[431,17998,17639],{"class":441},[431,18000,18001],{"class":455},"# => [ 'cats', 'dogs', 'birds', 'horses' ]\n",[431,18003,18004],{"class":433,"line":1985},[431,18005,1662],{"emptyLinePlaceholder":393},[431,18007,18008],{"class":433,"line":2041},[431,18009,18010],{"class":455},"# Строка 'horses' была добавлена в конец списка (индекс = 3)\n",[431,18012,18013,18015,18017,18019,18022],{"class":433,"line":4018},[431,18014,438],{"class":437},[431,18016,17825],{"class":441},[431,18018,971],{"class":437},[431,18020,18021],{"class":441},"]) ",[431,18023,18024],{"class":455},"# => 'horses'\n",[415,18026,17944,18027,18030],{},[428,18028,18029],{},"insert()"," добавляет элемент перед указанным по индексу элементом списка:",[422,18032,18034],{"className":424,"code":18033,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\n# Добавит элемент перед 2 индексом, то есть между 'dogs' и 'birds'\nanimals.insert(2, 'horses')\nprint(animals) # => ['cats', 'dogs', 'horses', 'birds']\n",[428,18035,18036,18056,18061,18074],{"__ignoreMap":426},[431,18037,18038,18040,18042,18044,18046,18048,18050,18052,18054],{"class":433,"line":434},[431,18039,17490],{"class":441},[431,18041,1189],{"class":654},[431,18043,17401],{"class":441},[431,18045,17497],{"class":445},[431,18047,4846],{"class":441},[431,18049,17502],{"class":445},[431,18051,4846],{"class":441},[431,18053,17507],{"class":445},[431,18055,3568],{"class":441},[431,18057,18058],{"class":433,"line":452},[431,18059,18060],{"class":455},"# Добавит элемент перед 2 индексом, то есть между 'dogs' и 'birds'\n",[431,18062,18063,18066,18068,18070,18072],{"class":433,"line":578},[431,18064,18065],{"class":441},"animals.insert(",[431,18067,651],{"class":437},[431,18069,4846],{"class":441},[431,18071,17981],{"class":445},[431,18073,449],{"class":441},[431,18075,18076,18078,18080],{"class":433,"line":584},[431,18077,438],{"class":437},[431,18079,17639],{"class":441},[431,18081,18082],{"class":455},"# => ['cats', 'dogs', 'horses', 'birds']\n",[415,18084,17944,18085,18088],{},[428,18086,18087],{},"extend()"," расширяет список всеми элементами из переданного списка:",[422,18090,18092],{"className":424,"code":18091,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs']\nbirds = ['heron', 'sparrow', 'swift']\n\nanimals.extend(birds)\nprint(animals) # => ['cats', 'dogs', 'heron', 'sparrow', 'swift']\n",[428,18093,18094,18110,18134,18138,18143],{"__ignoreMap":426},[431,18095,18096,18098,18100,18102,18104,18106,18108],{"class":433,"line":434},[431,18097,17490],{"class":441},[431,18099,1189],{"class":654},[431,18101,17401],{"class":441},[431,18103,17497],{"class":445},[431,18105,4846],{"class":441},[431,18107,17502],{"class":445},[431,18109,3568],{"class":441},[431,18111,18112,18115,18117,18119,18122,18124,18127,18129,18132],{"class":433,"line":452},[431,18113,18114],{"class":441},"birds ",[431,18116,1189],{"class":654},[431,18118,17401],{"class":441},[431,18120,18121],{"class":445},"'heron'",[431,18123,4846],{"class":441},[431,18125,18126],{"class":445},"'sparrow'",[431,18128,4846],{"class":441},[431,18130,18131],{"class":445},"'swift'",[431,18133,3568],{"class":441},[431,18135,18136],{"class":433,"line":578},[431,18137,1662],{"emptyLinePlaceholder":393},[431,18139,18140],{"class":433,"line":584},[431,18141,18142],{"class":441},"animals.extend(birds)\n",[431,18144,18145,18147,18149],{"class":433,"line":1244},[431,18146,438],{"class":437},[431,18148,17639],{"class":441},[431,18150,18151],{"class":455},"# => ['cats', 'dogs', 'heron', 'sparrow', 'swift']\n",[415,18153,18154],{},"Новички часто совершают такую ошибку:",[422,18156,18158],{"className":424,"code":18157,"language":396,"meta":426,"style":426},"l = [1]\nl = l.append(2)\nprint(l)  # None\n# A где список?\n",[428,18159,18160,18173,18186,18196],{"__ignoreMap":426},[431,18161,18162,18165,18167,18169,18171],{"class":433,"line":434},[431,18163,18164],{"class":441},"l ",[431,18166,1189],{"class":654},[431,18168,17401],{"class":441},[431,18170,1192],{"class":437},[431,18172,3568],{"class":441},[431,18174,18175,18177,18179,18182,18184],{"class":433,"line":452},[431,18176,18164],{"class":441},[431,18178,1189],{"class":654},[431,18180,18181],{"class":441}," l.append(",[431,18183,651],{"class":437},[431,18185,449],{"class":441},[431,18187,18188,18190,18193],{"class":433,"line":578},[431,18189,438],{"class":437},[431,18191,18192],{"class":441},"(l)  ",[431,18194,18195],{"class":455},"# None\n",[431,18197,18198],{"class":433,"line":584},[431,18199,18200],{"class":455},"# A где список?\n",[415,18202,18203,18204,18206],{},"Нужно помнить, что определенные методы изменяют сам список, но возвращают ",[428,18205,7922],{},". Это избавит от потенциальных ошибок и удивления.",[458,18208,18210],{"id":18209},"удаление-элемента-из-списка","Удаление элемента из списка",[415,18212,18213,18214,2699],{},"Удалить элемент из списка можно с помощью оператора ",[428,18215,18216],{},"del",[422,18218,18220],{"className":424,"code":18219,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\n# удаляем элемент под индексом 1\ndel animals[1]\nprint(animals) # => ['cats', 'birds']\n",[428,18221,18222,18242,18247,18258],{"__ignoreMap":426},[431,18223,18224,18226,18228,18230,18232,18234,18236,18238,18240],{"class":433,"line":434},[431,18225,17490],{"class":441},[431,18227,1189],{"class":654},[431,18229,17401],{"class":441},[431,18231,17497],{"class":445},[431,18233,4846],{"class":441},[431,18235,17502],{"class":445},[431,18237,4846],{"class":441},[431,18239,17507],{"class":445},[431,18241,3568],{"class":441},[431,18243,18244],{"class":433,"line":452},[431,18245,18246],{"class":455},"# удаляем элемент под индексом 1\n",[431,18248,18249,18251,18254,18256],{"class":433,"line":578},[431,18250,18216],{"class":654},[431,18252,18253],{"class":441}," animals[",[431,18255,1192],{"class":437},[431,18257,3568],{"class":441},[431,18259,18260,18262,18264],{"class":433,"line":584},[431,18261,438],{"class":437},[431,18263,17639],{"class":441},[431,18265,18266],{"class":455},"# => ['cats', 'birds']\n",[415,18268,18269,18270,2699],{},"Удалить элемент из списка можно также с помощью метода ",[428,18271,18272],{},"remove()",[422,18274,18276],{"className":424,"code":18275,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\n# удаляем элемент под индексом 1\nanimals.remove('dogs')\nprint(animals) # => ['cats', 'birds']\n",[428,18277,18278,18298,18302,18311],{"__ignoreMap":426},[431,18279,18280,18282,18284,18286,18288,18290,18292,18294,18296],{"class":433,"line":434},[431,18281,17490],{"class":441},[431,18283,1189],{"class":654},[431,18285,17401],{"class":441},[431,18287,17497],{"class":445},[431,18289,4846],{"class":441},[431,18291,17502],{"class":445},[431,18293,4846],{"class":441},[431,18295,17507],{"class":445},[431,18297,3568],{"class":441},[431,18299,18300],{"class":433,"line":452},[431,18301,18246],{"class":455},[431,18303,18304,18307,18309],{"class":433,"line":578},[431,18305,18306],{"class":441},"animals.remove(",[431,18308,17502],{"class":445},[431,18310,449],{"class":441},[431,18312,18313,18315,18317],{"class":433,"line":584},[431,18314,438],{"class":437},[431,18316,17639],{"class":441},[431,18318,18266],{"class":455},[458,18320,18322],{"id":18321},"проверка-существования-значения","Проверка существования значения",[415,18324,18325],{},"При работе со списками часто допускается ситуация, называемая \"выход за границу списка\".\nОна возникает при обращении к несуществующему индексу:",[422,18327,18329],{"className":424,"code":18328,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\n# Элемента с индексом 5 не существует\nanimals[5] # IndexError: list index out of range\n",[428,18330,18331,18351,18356],{"__ignoreMap":426},[431,18332,18333,18335,18337,18339,18341,18343,18345,18347,18349],{"class":433,"line":434},[431,18334,17490],{"class":441},[431,18336,1189],{"class":654},[431,18338,17401],{"class":441},[431,18340,17497],{"class":445},[431,18342,4846],{"class":441},[431,18344,17502],{"class":445},[431,18346,4846],{"class":441},[431,18348,17507],{"class":445},[431,18350,3568],{"class":441},[431,18352,18353],{"class":433,"line":452},[431,18354,18355],{"class":455},"# Элемента с индексом 5 не существует\n",[431,18357,18358,18360,18362,18364],{"class":433,"line":578},[431,18359,17553],{"class":441},[431,18361,856],{"class":437},[431,18363,4049],{"class":441},[431,18365,18366],{"class":455},"# IndexError: list index out of range\n",[415,18368,18369],{},"В разных языках программирования поведение в случае выхода за границу реализовано совершенно по-разному.\nИногда возникает ошибка, иногда нет, а иногда подобный выход возвращает случайные данные из соседнего блока памяти, как в Си, что может привести к катастрофе.",[422,18371,18373],{"className":424,"code":18372,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\n\n# Выход за границы списка\nanimals[5] # IndexError: list index out of range\nanimals[4] # IndexError: list index out of range\nanimals[3] # IndexError: list index out of range\n\n# Ура, мы попали в границы списка :)\nanimals[2] # 'birds'\n",[428,18374,18375,18395,18399,18404,18414,18424,18434,18438,18443],{"__ignoreMap":426},[431,18376,18377,18379,18381,18383,18385,18387,18389,18391,18393],{"class":433,"line":434},[431,18378,17490],{"class":441},[431,18380,1189],{"class":654},[431,18382,17401],{"class":441},[431,18384,17497],{"class":445},[431,18386,4846],{"class":441},[431,18388,17502],{"class":445},[431,18390,4846],{"class":441},[431,18392,17507],{"class":445},[431,18394,3568],{"class":441},[431,18396,18397],{"class":433,"line":452},[431,18398,1662],{"emptyLinePlaceholder":393},[431,18400,18401],{"class":433,"line":578},[431,18402,18403],{"class":455},"# Выход за границы списка\n",[431,18405,18406,18408,18410,18412],{"class":433,"line":584},[431,18407,17553],{"class":441},[431,18409,856],{"class":437},[431,18411,4049],{"class":441},[431,18413,18366],{"class":455},[431,18415,18416,18418,18420,18422],{"class":433,"line":1244},[431,18417,17553],{"class":441},[431,18419,762],{"class":437},[431,18421,4049],{"class":441},[431,18423,18366],{"class":455},[431,18425,18426,18428,18430,18432],{"class":433,"line":1985},[431,18427,17553],{"class":441},[431,18429,971],{"class":437},[431,18431,4049],{"class":441},[431,18433,18366],{"class":455},[431,18435,18436],{"class":433,"line":2041},[431,18437,1662],{"emptyLinePlaceholder":393},[431,18439,18440],{"class":433,"line":4018},[431,18441,18442],{"class":455},"# Ура, мы попали в границы списка :)\n",[431,18444,18445,18447,18449,18451],{"class":433,"line":4030},[431,18446,17553],{"class":441},[431,18448,651],{"class":437},[431,18450,4049],{"class":441},[431,18452,17596],{"class":455},[415,18454,18455],{},"В подавляющем большинстве ситуаций выход за границу списка является нежелательным поведением.\nОн происходит из-за логических ошибок в программе.\nПри этом программа может работать и даже иногда выдавать правильный результат.\nСамый простой способ проверить выход за границу — это убедиться в том, что индекс меньше длины списка.\nЭто можно сделать с помощью функции len():",[422,18457,18459],{"className":424,"code":18458,"language":396,"meta":426,"style":426},"animals = ['cats', 'dogs', 'birds']\nindex = 1\n# Важно что \u003C, а не \u003C=.\n# потому что такого индекса нет len(animals) = 3\nif index \u003C len(animals):\n  animal = animals[index] # все отлично!\n  print(animal) # => dogs\n",[428,18460,18461,18481,18490,18495,18500,18513,18526],{"__ignoreMap":426},[431,18462,18463,18465,18467,18469,18471,18473,18475,18477,18479],{"class":433,"line":434},[431,18464,17490],{"class":441},[431,18466,1189],{"class":654},[431,18468,17401],{"class":441},[431,18470,17497],{"class":445},[431,18472,4846],{"class":441},[431,18474,17502],{"class":445},[431,18476,4846],{"class":441},[431,18478,17507],{"class":445},[431,18480,3568],{"class":441},[431,18482,18483,18486,18488],{"class":433,"line":452},[431,18484,18485],{"class":441},"index ",[431,18487,1189],{"class":654},[431,18489,3916],{"class":437},[431,18491,18492],{"class":433,"line":578},[431,18493,18494],{"class":455},"# Важно что \u003C, а не \u003C=.\n",[431,18496,18497],{"class":433,"line":584},[431,18498,18499],{"class":455},"# потому что такого индекса нет len(animals) = 3\n",[431,18501,18502,18504,18506,18508,18510],{"class":433,"line":1244},[431,18503,10399],{"class":654},[431,18505,13722],{"class":441},[431,18507,8521],{"class":654},[431,18509,4804],{"class":437},[431,18511,18512],{"class":441},"(animals):\n",[431,18514,18515,18518,18520,18523],{"class":433,"line":1985},[431,18516,18517],{"class":441},"  animal ",[431,18519,1189],{"class":654},[431,18521,18522],{"class":441}," animals[index] ",[431,18524,18525],{"class":455},"# все отлично!\n",[431,18527,18528,18531,18534],{"class":433,"line":2041},[431,18529,18530],{"class":437},"  print",[431,18532,18533],{"class":441},"(animal) ",[431,18535,18536],{"class":455},"# => dogs\n",[415,18538,1849,18539,1853,18541,1857],{},[800,18540,1852],{},[800,18542,1856],{},[1859,18544],{},[1862,18546,18547],{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}",{"title":426,"searchDepth":452,"depth":1244,"links":18549},[18550],{"id":17361,"depth":452,"text":206,"children":18551},[18552,18556],{"id":17445,"depth":578,"text":17446,"children":18553},[18554,18555],{"id":17452,"depth":584,"text":17453},{"id":17519,"depth":584,"text":17520},{"id":17837,"depth":578,"text":17838,"children":18557},[18558,18559,18560,18561],{"id":17881,"depth":584,"text":17882},{"id":17940,"depth":584,"text":17941},{"id":18209,"depth":584,"text":18210},{"id":18321,"depth":584,"text":18322},"2025-03-16","Синтаксис. Модификация. Проверка существования значения","images\u002Fblog\u002Fpython\u002Fst13\u002Fimg.png",{},{"title":206,"description":18563},"P_NJW7PSm-_IrGxOyY2P91CiccK1BBkX0iIF9B8C3jc",{"id":18569,"title":210,"author":18570,"body":18572,"date":21136,"description":21137,"extension":1887,"image":21138,"meta":21139,"minRead":1890,"navigation":393,"num":4086,"path":211,"seo":21140,"stem":212,"__hash__":21141},"python\u002Fblog\u002Fpython\u002Fst14.md",{"name":402,"avatar":18571},{"src":404,"alt":405},{"type":407,"value":18573,"toc":21117},[18574,18577,18581,18588,18654,18664,18751,18758,18765,18820,18824,18827,18879,18882,18885,18895,18897,18949,18951,18955,18958,19051,19057,19151,19154,19248,19254,19325,19329,19332,19450,19460,19464,19467,19565,19568,19634,19637,19728,19732,19735,19799,19802,19805,19830,19833,19890,19896,19900,19905,19946,19949,20021,20024,20028,20031,20100,20103,20188,20191,20269,20272,20333,20337,20340,20436,20439,20443,20446,20644,20647,20651,20654,20769,20772,20775,20815,20822,20826,20836,20965,20975,21103,21106,21112,21114],[410,18575,210],{"id":18576},"списки-и-циклы",[632,18578,18580],{"id":18579},"цикл-for-и-списки","Цикл for и списки",[415,18582,18583,18584,18587],{},"Обход коллекции настолько распространенная задача, что многие языки программирования решают это введением специального вида цикла.\nВ Python можно воспользоваться циклом ",[428,18585,18586],{},"for ... in"," для обхода списка.",[422,18589,18591],{"className":424,"code":18590,"language":396,"meta":426,"style":426},"user_names = ['petya', 'vasya', 'evgeny']\n# name на каждой итерации свой собственный (локальный)\nfor name in user_names:\n    print(name)\n# => \"petya\"\n# => \"vasya\"\n# => \"evgeny\"\n",[428,18592,18593,18617,18622,18633,18639,18644,18649],{"__ignoreMap":426},[431,18594,18595,18598,18600,18602,18605,18607,18610,18612,18615],{"class":433,"line":434},[431,18596,18597],{"class":441},"user_names ",[431,18599,1189],{"class":654},[431,18601,17401],{"class":441},[431,18603,18604],{"class":445},"'petya'",[431,18606,4846],{"class":441},[431,18608,18609],{"class":445},"'vasya'",[431,18611,4846],{"class":441},[431,18613,18614],{"class":445},"'evgeny'",[431,18616,3568],{"class":441},[431,18618,18619],{"class":433,"line":452},[431,18620,18621],{"class":455},"# name на каждой итерации свой собственный (локальный)\n",[431,18623,18624,18626,18628,18630],{"class":433,"line":578},[431,18625,14329],{"class":654},[431,18627,9800],{"class":441},[431,18629,14421],{"class":654},[431,18631,18632],{"class":441}," user_names:\n",[431,18634,18635,18637],{"class":433,"line":584},[431,18636,6357],{"class":437},[431,18638,4282],{"class":441},[431,18640,18641],{"class":433,"line":1244},[431,18642,18643],{"class":455},"# => \"petya\"\n",[431,18645,18646],{"class":433,"line":1985},[431,18647,18648],{"class":455},"# => \"vasya\"\n",[431,18650,18651],{"class":433,"line":2041},[431,18652,18653],{"class":455},"# => \"evgeny\"\n",[415,18655,18656,18657,18659,18660,18663],{},"Цикл знает, как перебирать элементы, и знает о том, когда они закончатся.\nВ цикле создается переменная ",[800,18658,15398],{},". На каждой итерации она принимает следующее значение элемента списка ",[800,18661,18662],{},"user_names",".\nЭтот цикл отлично подходит для задач агрегации:",[422,18665,18667],{"className":424,"code":18666,"language":396,"meta":426,"style":426},"def calc_sum(coll):\n    sum = 0\n    for value in coll:\n        sum += value\n    return sum\n\nprint(calc_sum([3, 2, -5, 38, 0]))  # => 38\n",[428,18668,18669,18679,18687,18698,18707,18713,18717],{"__ignoreMap":426},[431,18670,18671,18673,18676],{"class":433,"line":434},[431,18672,6330],{"class":654},[431,18674,18675],{"class":6333}," calc_sum",[431,18677,18678],{"class":441},"(coll):\n",[431,18680,18681,18683,18685],{"class":433,"line":452},[431,18682,13181],{"class":437},[431,18684,2146],{"class":654},[431,18686,3459],{"class":437},[431,18688,18689,18691,18693,18695],{"class":433,"line":578},[431,18690,14745],{"class":654},[431,18692,10381],{"class":441},[431,18694,14421],{"class":654},[431,18696,18697],{"class":441}," coll:\n",[431,18699,18700,18702,18704],{"class":433,"line":584},[431,18701,13207],{"class":437},[431,18703,14372],{"class":654},[431,18705,18706],{"class":441}," value\n",[431,18708,18709,18711],{"class":433,"line":1244},[431,18710,6599],{"class":654},[431,18712,13247],{"class":437},[431,18714,18715],{"class":433,"line":1985},[431,18716,1662],{"emptyLinePlaceholder":393},[431,18718,18719,18721,18724,18726,18728,18730,18732,18734,18736,18738,18741,18743,18745,18748],{"class":433,"line":2041},[431,18720,438],{"class":437},[431,18722,18723],{"class":441},"(calc_sum([",[431,18725,971],{"class":437},[431,18727,4846],{"class":441},[431,18729,651],{"class":437},[431,18731,4846],{"class":441},[431,18733,853],{"class":654},[431,18735,856],{"class":437},[431,18737,4846],{"class":441},[431,18739,18740],{"class":437},"38",[431,18742,4846],{"class":441},[431,18744,3302],{"class":437},[431,18746,18747],{"class":441},"]))  ",[431,18749,18750],{"class":455},"# => 38\n",[415,18752,18753,18755,18756],{},[428,18754,18586],{}," — это больше, чем просто цикл для списков.\nОн используется для обхода всех коллекций в Python. Так ранее мы проходили уже пример коллекции в виде кортежей.\nОбходить их тоже можно с помощью ",[428,18757,18586],{},[415,18759,18760,18761,18764],{},"Для полного понимания принципов его работы нужно разбираться в темах: объекты, итераторы, магические методы.\nЕсли по-простому, то разные данные в Python могут притворяться коллекциями элементов.\nСамый простой пример — это строка: ",[428,18762,18763],{},"for...in"," перебирает строку посимвольно.",[422,18766,18768],{"className":424,"code":18767,"language":396,"meta":426,"style":426},"greeting = 'Hello'\nfor symbol in greeting:\n    print(symbol)\n# => \"H\"\n# => \"e\"\n# => \"l\"\n# => \"l\"\n# => \"o\"\n",[428,18769,18770,18779,18790,18796,18801,18806,18811,18815],{"__ignoreMap":426},[431,18771,18772,18774,18776],{"class":433,"line":434},[431,18773,1959],{"class":441},[431,18775,1189],{"class":654},[431,18777,18778],{"class":445}," 'Hello'\n",[431,18780,18781,18783,18785,18787],{"class":433,"line":452},[431,18782,14329],{"class":654},[431,18784,14670],{"class":441},[431,18786,14421],{"class":654},[431,18788,18789],{"class":441}," greeting:\n",[431,18791,18792,18794],{"class":433,"line":578},[431,18793,6357],{"class":437},[431,18795,14682],{"class":441},[431,18797,18798],{"class":433,"line":584},[431,18799,18800],{"class":455},"# => \"H\"\n",[431,18802,18803],{"class":433,"line":1244},[431,18804,18805],{"class":455},"# => \"e\"\n",[431,18807,18808],{"class":433,"line":1985},[431,18809,18810],{"class":455},"# => \"l\"\n",[431,18812,18813],{"class":433,"line":2041},[431,18814,18810],{"class":455},[431,18816,18817],{"class":433,"line":4018},[431,18818,18819],{"class":455},"# => \"o\"\n",[632,18821,18823],{"id":18822},"циклы-с-индексами","Циклы с индексами",[415,18825,18826],{},"Цикл for можно использовать не только для обхода списка, но и для повторения действий.\nДля этого используют функцию range().\nФункция range() в Python используется для генерации последовательностей чисел.\nОна часто применяется в циклах for для задания диапазона чисел, которые нужно перебрать.",[422,18828,18830],{"className":424,"code":18829,"language":396,"meta":426,"style":426},"for i in range(1, 6):\n  print(i)\n# => 1\n# => 2\n# => 3\n# => 4\n# => 5\n",[428,18831,18832,18852,18858,18862,18866,18870,18875],{"__ignoreMap":426},[431,18833,18834,18836,18838,18840,18842,18844,18846,18848,18850],{"class":433,"line":434},[431,18835,14329],{"class":654},[431,18837,12664],{"class":441},[431,18839,14421],{"class":654},[431,18841,14424],{"class":437},[431,18843,442],{"class":441},[431,18845,1192],{"class":437},[431,18847,4846],{"class":441},[431,18849,742],{"class":437},[431,18851,7381],{"class":441},[431,18853,18854,18856],{"class":433,"line":452},[431,18855,18530],{"class":437},[431,18857,12677],{"class":441},[431,18859,18860],{"class":433,"line":578},[431,18861,791],{"class":455},[431,18863,18864],{"class":433,"line":584},[431,18865,3518],{"class":455},[431,18867,18868],{"class":433,"line":1244},[431,18869,4513],{"class":455},[431,18871,18872],{"class":433,"line":1985},[431,18873,18874],{"class":455},"# => 4\n",[431,18876,18877],{"class":433,"line":2041},[431,18878,3531],{"class":455},[415,18880,18881],{},"Функция range в Python является встроенной функцией, которая создает последовательность чисел внутри определенного диапазона.\nЕе можно использовать в цикле for для контроля количества итераций.",[415,18883,18884],{},"У range() есть несколько вариантов использования:",[697,18886,18887,18890,18893],{},[700,18888,18889],{},"range(stop) создает последовательность от 0 до stop - 1",[700,18891,18892],{},"range(start, stop) создает последовательность от start до stop - 1",[700,18894,14476],{},[415,18896,14529],{},[422,18898,18899],{"className":424,"code":14532,"language":396,"meta":426,"style":426},[428,18900,18901,18927,18933,18937,18941,18945],{"__ignoreMap":426},[431,18902,18903,18905,18907,18909,18911,18913,18915,18917,18919,18921,18923,18925],{"class":433,"line":434},[431,18904,14329],{"class":654},[431,18906,12664],{"class":441},[431,18908,14421],{"class":654},[431,18910,14424],{"class":437},[431,18912,442],{"class":441},[431,18914,971],{"class":437},[431,18916,4846],{"class":441},[431,18918,3302],{"class":437},[431,18920,4846],{"class":441},[431,18922,853],{"class":654},[431,18924,1192],{"class":437},[431,18926,7381],{"class":441},[431,18928,18929,18931],{"class":433,"line":452},[431,18930,6357],{"class":437},[431,18932,12677],{"class":441},[431,18934,18935],{"class":433,"line":578},[431,18936,1662],{"emptyLinePlaceholder":393},[431,18938,18939],{"class":433,"line":584},[431,18940,4513],{"class":455},[431,18942,18943],{"class":433,"line":1244},[431,18944,3518],{"class":455},[431,18946,18947],{"class":433,"line":1985},[431,18948,791],{"class":455},[415,18950,14585],{},[458,18952,18954],{"id":18953},"обход-списка-с-использованием-индекса","Обход списка с использованием индекса",[415,18956,18957],{},"Можно использовать range() для получения индексов элементов списка, что может быть полезно, если нужно работать с индексами:",[422,18959,18961],{"className":424,"code":18960,"language":396,"meta":426,"style":426},"user_names = ['petya', 'vasya', 'evgeny']\nend = len(user_names)\n\n# range(begin, end) создает последовательность чисел от begin до end\n# значение end не включается в последовательность\nfor i in range(0, end):\n  print(user_names[i])\n\n# => petya\n# => vasya\n# => evgeny\n",[428,18962,18963,18983,18994,18998,19003,19008,19025,19032,19036,19041,19046],{"__ignoreMap":426},[431,18964,18965,18967,18969,18971,18973,18975,18977,18979,18981],{"class":433,"line":434},[431,18966,18597],{"class":441},[431,18968,1189],{"class":654},[431,18970,17401],{"class":441},[431,18972,18604],{"class":445},[431,18974,4846],{"class":441},[431,18976,18609],{"class":445},[431,18978,4846],{"class":441},[431,18980,18614],{"class":445},[431,18982,3568],{"class":441},[431,18984,18985,18987,18989,18991],{"class":433,"line":452},[431,18986,3921],{"class":441},[431,18988,1189],{"class":654},[431,18990,4804],{"class":437},[431,18992,18993],{"class":441},"(user_names)\n",[431,18995,18996],{"class":433,"line":578},[431,18997,1662],{"emptyLinePlaceholder":393},[431,18999,19000],{"class":433,"line":584},[431,19001,19002],{"class":455},"# range(begin, end) создает последовательность чисел от begin до end\n",[431,19004,19005],{"class":433,"line":1244},[431,19006,19007],{"class":455},"# значение end не включается в последовательность\n",[431,19009,19010,19012,19014,19016,19018,19020,19022],{"class":433,"line":1985},[431,19011,14329],{"class":654},[431,19013,12664],{"class":441},[431,19015,14421],{"class":654},[431,19017,14424],{"class":437},[431,19019,442],{"class":441},[431,19021,3302],{"class":437},[431,19023,19024],{"class":441},", end):\n",[431,19026,19027,19029],{"class":433,"line":2041},[431,19028,18530],{"class":437},[431,19030,19031],{"class":441},"(user_names[i])\n",[431,19033,19034],{"class":433,"line":4018},[431,19035,1662],{"emptyLinePlaceholder":393},[431,19037,19038],{"class":433,"line":4030},[431,19039,19040],{"class":455},"# => petya\n",[431,19042,19043],{"class":433,"line":4419},[431,19044,19045],{"class":455},"# => vasya\n",[431,19047,19048],{"class":433,"line":4436},[431,19049,19050],{"class":455},"# => evgeny\n",[415,19052,19053,19054,2699],{},"В данном коде создаем список из трех элементов — имен.\nДалее в цикле обходим список и выводим на экран все имена так, что каждое имя оказывается на новой строке (print() автоматически делает перевод строки).\nРассмотрим этот этап подробнее. При обходе списка циклом for счетчик, как правило, играет роль индекса в списке.\nОн инициализируется нулем и увеличивается до len(user_names) - 1, что соответствует индексу последнего элемента.\nА что, если нам нужно вывести значения в обратном порядке? Для этого есть два способа.\nОдин — идти в прямом порядке, то есть от нулевого индекса до последнего,\nи каждый раз вычислять нужный индекс по такой формуле: ",[1355,19055,19056],{},"размер списка - 1 - текущее значение счетчика",[422,19058,19060],{"className":424,"code":19059,"language":396,"meta":426,"style":426},"user_names = ['petya', 'vasya', 'evgeny']\nend = len(user_names)\nfor i in range(0, end):\n  index = (len(user_names) - 1) - i\n  print(user_names[index])\n# => evgeny\n# => vasya\n# => petya\n",[428,19061,19062,19082,19092,19108,19132,19139,19143,19147],{"__ignoreMap":426},[431,19063,19064,19066,19068,19070,19072,19074,19076,19078,19080],{"class":433,"line":434},[431,19065,18597],{"class":441},[431,19067,1189],{"class":654},[431,19069,17401],{"class":441},[431,19071,18604],{"class":445},[431,19073,4846],{"class":441},[431,19075,18609],{"class":445},[431,19077,4846],{"class":441},[431,19079,18614],{"class":445},[431,19081,3568],{"class":441},[431,19083,19084,19086,19088,19090],{"class":433,"line":452},[431,19085,3921],{"class":441},[431,19087,1189],{"class":654},[431,19089,4804],{"class":437},[431,19091,18993],{"class":441},[431,19093,19094,19096,19098,19100,19102,19104,19106],{"class":433,"line":578},[431,19095,14329],{"class":654},[431,19097,12664],{"class":441},[431,19099,14421],{"class":654},[431,19101,14424],{"class":437},[431,19103,442],{"class":441},[431,19105,3302],{"class":437},[431,19107,19024],{"class":441},[431,19109,19110,19113,19115,19117,19119,19122,19124,19126,19128,19130],{"class":433,"line":584},[431,19111,19112],{"class":441},"  index ",[431,19114,1189],{"class":654},[431,19116,976],{"class":441},[431,19118,5205],{"class":437},[431,19120,19121],{"class":441},"(user_names) ",[431,19123,853],{"class":654},[431,19125,1032],{"class":437},[431,19127,1014],{"class":441},[431,19129,853],{"class":654},[431,19131,14375],{"class":441},[431,19133,19134,19136],{"class":433,"line":1244},[431,19135,18530],{"class":437},[431,19137,19138],{"class":441},"(user_names[index])\n",[431,19140,19141],{"class":433,"line":1985},[431,19142,19050],{"class":455},[431,19144,19145],{"class":433,"line":2041},[431,19146,19045],{"class":455},[431,19148,19149],{"class":433,"line":4018},[431,19150,19040],{"class":455},[415,19152,19153],{},"Другой способ подразумевает обход в обратном порядке, от верхней границы до нижней,\nто есть от последнего индекса списка к первому (нулю, так как индексирование начинается с нуля).\nВ такой ситуации код меняется на следующий:",[422,19155,19157],{"className":424,"code":19156,"language":396,"meta":426,"style":426},"user_names = ['petya', 'vasya', 'evgeny']\nend = len(user_names)\n# Здесь в range передается третий параметр - шаг\n# и так же как со срезами, если передается отрицательный шаг, то обход будет в обратную сторону\nfor i in range(end - 1, -1, -1):\n  print(user_names[i])\n# => evgeny\n# => vasya\n# => petya\n",[428,19158,19159,19179,19189,19194,19199,19230,19236,19240,19244],{"__ignoreMap":426},[431,19160,19161,19163,19165,19167,19169,19171,19173,19175,19177],{"class":433,"line":434},[431,19162,18597],{"class":441},[431,19164,1189],{"class":654},[431,19166,17401],{"class":441},[431,19168,18604],{"class":445},[431,19170,4846],{"class":441},[431,19172,18609],{"class":445},[431,19174,4846],{"class":441},[431,19176,18614],{"class":445},[431,19178,3568],{"class":441},[431,19180,19181,19183,19185,19187],{"class":433,"line":452},[431,19182,3921],{"class":441},[431,19184,1189],{"class":654},[431,19186,4804],{"class":437},[431,19188,18993],{"class":441},[431,19190,19191],{"class":433,"line":578},[431,19192,19193],{"class":455},"# Здесь в range передается третий параметр - шаг\n",[431,19195,19196],{"class":433,"line":584},[431,19197,19198],{"class":455},"# и так же как со срезами, если передается отрицательный шаг, то обход будет в обратную сторону\n",[431,19200,19201,19203,19205,19207,19209,19212,19214,19216,19218,19220,19222,19224,19226,19228],{"class":433,"line":1244},[431,19202,14329],{"class":654},[431,19204,12664],{"class":441},[431,19206,14421],{"class":654},[431,19208,14424],{"class":437},[431,19210,19211],{"class":441},"(end ",[431,19213,853],{"class":654},[431,19215,1032],{"class":437},[431,19217,4846],{"class":441},[431,19219,853],{"class":654},[431,19221,1192],{"class":437},[431,19223,4846],{"class":441},[431,19225,853],{"class":654},[431,19227,1192],{"class":437},[431,19229,7381],{"class":441},[431,19231,19232,19234],{"class":433,"line":1985},[431,19233,18530],{"class":437},[431,19235,19031],{"class":441},[431,19237,19238],{"class":433,"line":2041},[431,19239,19050],{"class":455},[431,19241,19242],{"class":433,"line":4018},[431,19243,19045],{"class":455},[431,19245,19246],{"class":433,"line":4030},[431,19247,19040],{"class":455},[415,19249,19250,19251],{},"Код выше можно сделать проще с помощью функции ",[800,19252,19253],{},"reversed()",[422,19255,19257],{"className":424,"code":19256,"language":396,"meta":426,"style":426},"user_names = ['petya', 'vasya', 'evgeny']\nend = len(user_names)\nfor i in reversed(range(end)):\n  print(user_names[i])\n# => evgeny\n# => vasya\n# => petya\n",[428,19258,19259,19279,19289,19307,19313,19317,19321],{"__ignoreMap":426},[431,19260,19261,19263,19265,19267,19269,19271,19273,19275,19277],{"class":433,"line":434},[431,19262,18597],{"class":441},[431,19264,1189],{"class":654},[431,19266,17401],{"class":441},[431,19268,18604],{"class":445},[431,19270,4846],{"class":441},[431,19272,18609],{"class":445},[431,19274,4846],{"class":441},[431,19276,18614],{"class":445},[431,19278,3568],{"class":441},[431,19280,19281,19283,19285,19287],{"class":433,"line":452},[431,19282,3921],{"class":441},[431,19284,1189],{"class":654},[431,19286,4804],{"class":437},[431,19288,18993],{"class":441},[431,19290,19291,19293,19295,19297,19300,19302,19304],{"class":433,"line":578},[431,19292,14329],{"class":654},[431,19294,12664],{"class":441},[431,19296,14421],{"class":654},[431,19298,19299],{"class":437}," reversed",[431,19301,442],{"class":441},[431,19303,14459],{"class":437},[431,19305,19306],{"class":441},"(end)):\n",[431,19308,19309,19311],{"class":433,"line":584},[431,19310,18530],{"class":437},[431,19312,19031],{"class":441},[431,19314,19315],{"class":433,"line":1244},[431,19316,19050],{"class":455},[431,19318,19319],{"class":433,"line":1985},[431,19320,19045],{"class":455},[431,19322,19323],{"class":433,"line":2041},[431,19324,19040],{"class":455},[458,19326,19328],{"id":19327},"изменение-списка-во-время-обхода","Изменение списка во время обхода",[415,19330,19331],{},"Во время обхода списка его можно не только читать, но и модифицировать.\nПредположим, что перед нами стоит задача нормализации списка электронных адресов — например, приведение их к нижнему регистру.\nТогда код будет выглядеть так:",[422,19333,19335],{"className":424,"code":19334,"language":396,"meta":426,"style":426},"emails = ['VASYA@gmAil.com', 'iGoR@yandex.RU', 'netiD@hot.CoM']\nprint(emails)\n# => ['VASYA@gmAil.com', 'iGoR@yandex.RU', 'netiD@hot.CoM']\nfor i in range(0, len(emails)):\n  # lower() - стандартный метод строк Python\n  # преобразующий строку в нижний регистр\n  email = emails[i]\n  normalized_email = email.lower()\n  # Заменяем значение\n  emails[i] = normalized_email\nprint(emails)\n# => ['vasya@gmail.com', 'igor@yandex.ru', 'netid@hot.com']\n",[428,19336,19337,19361,19368,19373,19394,19399,19404,19414,19424,19429,19439,19445],{"__ignoreMap":426},[431,19338,19339,19342,19344,19346,19349,19351,19354,19356,19359],{"class":433,"line":434},[431,19340,19341],{"class":441},"emails ",[431,19343,1189],{"class":654},[431,19345,17401],{"class":441},[431,19347,19348],{"class":445},"'VASYA@gmAil.com'",[431,19350,4846],{"class":441},[431,19352,19353],{"class":445},"'iGoR@yandex.RU'",[431,19355,4846],{"class":441},[431,19357,19358],{"class":445},"'netiD@hot.CoM'",[431,19360,3568],{"class":441},[431,19362,19363,19365],{"class":433,"line":452},[431,19364,438],{"class":437},[431,19366,19367],{"class":441},"(emails)\n",[431,19369,19370],{"class":433,"line":578},[431,19371,19372],{"class":455},"# => ['VASYA@gmAil.com', 'iGoR@yandex.RU', 'netiD@hot.CoM']\n",[431,19374,19375,19377,19379,19381,19383,19385,19387,19389,19391],{"class":433,"line":584},[431,19376,14329],{"class":654},[431,19378,12664],{"class":441},[431,19380,14421],{"class":654},[431,19382,14424],{"class":437},[431,19384,442],{"class":441},[431,19386,3302],{"class":437},[431,19388,4846],{"class":441},[431,19390,5205],{"class":437},[431,19392,19393],{"class":441},"(emails)):\n",[431,19395,19396],{"class":433,"line":1244},[431,19397,19398],{"class":455},"  # lower() - стандартный метод строк Python\n",[431,19400,19401],{"class":433,"line":1985},[431,19402,19403],{"class":455},"  # преобразующий строку в нижний регистр\n",[431,19405,19406,19409,19411],{"class":433,"line":2041},[431,19407,19408],{"class":441},"  email ",[431,19410,1189],{"class":654},[431,19412,19413],{"class":441}," emails[i]\n",[431,19415,19416,19419,19421],{"class":433,"line":4018},[431,19417,19418],{"class":441},"  normalized_email ",[431,19420,1189],{"class":654},[431,19422,19423],{"class":441}," email.lower()\n",[431,19425,19426],{"class":433,"line":4030},[431,19427,19428],{"class":455},"  # Заменяем значение\n",[431,19430,19431,19434,19436],{"class":433,"line":4419},[431,19432,19433],{"class":441},"  emails[i] ",[431,19435,1189],{"class":654},[431,19437,19438],{"class":441}," normalized_email\n",[431,19440,19441,19443],{"class":433,"line":4436},[431,19442,438],{"class":437},[431,19444,19367],{"class":441},[431,19446,19447],{"class":433,"line":4446},[431,19448,19449],{"class":455},"# => ['vasya@gmail.com', 'igor@yandex.ru', 'netid@hot.com']\n",[415,19451,19452,19453,19456,19457,2699],{},"Ключевая строчка: ",[428,19454,19455],{},"emails[i] = normalized_email",". В ней происходит перезапись элемента под индексом ",[428,19458,19459],{},"i",[458,19461,19463],{"id":19462},"цикл-while-со-списком","Цикл while со списком",[415,19465,19466],{},"Цикл for можно заменить на while. Тогда нам необходимо будет вручную изменять счетчик:",[422,19468,19470],{"className":424,"code":19469,"language":396,"meta":426,"style":426},"user_names = ['petya', 'vasya', 'evgeny']\ni = 0\n# Определяем цикл. В переменной name на каждом шаге цикла будет храниться следующий элемент списка\n# Условие выполняется пока i \u003C 3\nwhile i \u003C len(user_names):\n  name = user_names[i]\n  print(name)\n  # увеличиваем счетчик\n  i += 1\n# => petya\n# => vasya\n# => evgeny\n",[428,19471,19472,19492,19500,19505,19510,19523,19533,19539,19544,19553,19557,19561],{"__ignoreMap":426},[431,19473,19474,19476,19478,19480,19482,19484,19486,19488,19490],{"class":433,"line":434},[431,19475,18597],{"class":441},[431,19477,1189],{"class":654},[431,19479,17401],{"class":441},[431,19481,18604],{"class":445},[431,19483,4846],{"class":441},[431,19485,18609],{"class":445},[431,19487,4846],{"class":441},[431,19489,18614],{"class":445},[431,19491,3568],{"class":441},[431,19493,19494,19496,19498],{"class":433,"line":452},[431,19495,3454],{"class":441},[431,19497,1189],{"class":654},[431,19499,3459],{"class":437},[431,19501,19502],{"class":433,"line":578},[431,19503,19504],{"class":455},"# Определяем цикл. В переменной name на каждом шаге цикла будет храниться следующий элемент списка\n",[431,19506,19507],{"class":433,"line":584},[431,19508,19509],{"class":455},"# Условие выполняется пока i \u003C 3\n",[431,19511,19512,19514,19516,19518,19520],{"class":433,"line":1244},[431,19513,12737],{"class":654},[431,19515,12664],{"class":441},[431,19517,8521],{"class":654},[431,19519,4804],{"class":437},[431,19521,19522],{"class":441},"(user_names):\n",[431,19524,19525,19528,19530],{"class":433,"line":1985},[431,19526,19527],{"class":441},"  name ",[431,19529,1189],{"class":654},[431,19531,19532],{"class":441}," user_names[i]\n",[431,19534,19535,19537],{"class":433,"line":2041},[431,19536,18530],{"class":437},[431,19538,4282],{"class":441},[431,19540,19541],{"class":433,"line":4018},[431,19542,19543],{"class":455},"  # увеличиваем счетчик\n",[431,19545,19546,19549,19551],{"class":433,"line":4030},[431,19547,19548],{"class":441},"  i ",[431,19550,12563],{"class":654},[431,19552,3916],{"class":437},[431,19554,19555],{"class":433,"line":4419},[431,19556,19040],{"class":455},[431,19558,19559],{"class":433,"line":4436},[431,19560,19045],{"class":455},[431,19562,19563],{"class":433,"line":4446},[431,19564,19050],{"class":455},[415,19566,19567],{},"Цикл while можно использовать для работы со списками, но он имеет несколько потенциальных минусов по сравнению с циклом for,\nкогда речь идёт о переборе элементов списка. В цикле while нужно явно контролировать условие завершения.\nЕсли вы забыли обновить счётчик или неправильно задали условие выхода, цикл может стать бесконечным. Например:",[422,19569,19571],{"className":424,"code":19570,"language":396,"meta":426,"style":426},"numbers = [10, 20, 30, 40]\ni = 0\n# Этот цикл будет бесконечным\nwhile i \u003C len(numbers):\n  print(numbers[i])\n",[428,19572,19573,19601,19609,19614,19627],{"__ignoreMap":426},[431,19574,19575,19578,19580,19582,19584,19586,19589,19591,19594,19596,19599],{"class":433,"line":434},[431,19576,19577],{"class":441},"numbers ",[431,19579,1189],{"class":654},[431,19581,17401],{"class":441},[431,19583,3565],{"class":437},[431,19585,4846],{"class":441},[431,19587,19588],{"class":437},"20",[431,19590,4846],{"class":441},[431,19592,19593],{"class":437},"30",[431,19595,4846],{"class":441},[431,19597,19598],{"class":437},"40",[431,19600,3568],{"class":441},[431,19602,19603,19605,19607],{"class":433,"line":452},[431,19604,3454],{"class":441},[431,19606,1189],{"class":654},[431,19608,3459],{"class":437},[431,19610,19611],{"class":433,"line":578},[431,19612,19613],{"class":455},"# Этот цикл будет бесконечным\n",[431,19615,19616,19618,19620,19622,19624],{"class":433,"line":584},[431,19617,12737],{"class":654},[431,19619,12664],{"class":441},[431,19621,8521],{"class":654},[431,19623,4804],{"class":437},[431,19625,19626],{"class":441},"(numbers):\n",[431,19628,19629,19631],{"class":433,"line":1244},[431,19630,18530],{"class":437},[431,19632,19633],{"class":441},"(numbers[i])\n",[415,19635,19636],{},"Или если укажете неверное условие, то выйдите за пределы списка:",[422,19638,19640],{"className":424,"code":19639,"language":396,"meta":426,"style":426},"numbers = [10, 20, 30, 40]\ni = 0\n# Этот цикл выйдет за границы списка\nwhile i \u003C= len(numbers):\n  print(numbers[i])\n  i += 1\n# => 10\n# => 20\n# => 30\n# => 40\n# IndexError: list index out of range\n",[428,19641,19642,19666,19674,19679,19691,19697,19705,19709,19714,19719,19724],{"__ignoreMap":426},[431,19643,19644,19646,19648,19650,19652,19654,19656,19658,19660,19662,19664],{"class":433,"line":434},[431,19645,19577],{"class":441},[431,19647,1189],{"class":654},[431,19649,17401],{"class":441},[431,19651,3565],{"class":437},[431,19653,4846],{"class":441},[431,19655,19588],{"class":437},[431,19657,4846],{"class":441},[431,19659,19593],{"class":437},[431,19661,4846],{"class":441},[431,19663,19598],{"class":437},[431,19665,3568],{"class":441},[431,19667,19668,19670,19672],{"class":433,"line":452},[431,19669,3454],{"class":441},[431,19671,1189],{"class":654},[431,19673,3459],{"class":437},[431,19675,19676],{"class":433,"line":578},[431,19677,19678],{"class":455},"# Этот цикл выйдет за границы списка\n",[431,19680,19681,19683,19685,19687,19689],{"class":433,"line":584},[431,19682,12737],{"class":654},[431,19684,12664],{"class":441},[431,19686,12667],{"class":654},[431,19688,4804],{"class":437},[431,19690,19626],{"class":441},[431,19692,19693,19695],{"class":433,"line":1244},[431,19694,18530],{"class":437},[431,19696,19633],{"class":441},[431,19698,19699,19701,19703],{"class":433,"line":1985},[431,19700,19548],{"class":441},[431,19702,12563],{"class":654},[431,19704,3916],{"class":437},[431,19706,19707],{"class":433,"line":2041},[431,19708,4412],{"class":455},[431,19710,19711],{"class":433,"line":4018},[431,19712,19713],{"class":455},"# => 20\n",[431,19715,19716],{"class":433,"line":4030},[431,19717,19718],{"class":455},"# => 30\n",[431,19720,19721],{"class":433,"line":4419},[431,19722,19723],{"class":455},"# => 40\n",[431,19725,19726],{"class":433,"line":4436},[431,19727,18366],{"class":455},[632,19729,19731],{"id":19730},"ссылочные-данные","Ссылочные данные",[415,19733,19734],{},"В Python в отличие от других языков, нет разделения на примитивные типы и ссылочные. Все всегда передается по ссылке.\nС точки зрения прикладного программиста, разница проявляется при изменении данных, их передаче и возврате из функций.\nНужно держать в уме, что списки как коллекции хранят в себе не сами значения, а ссылки на них.\nПри этом списки сами тоже передаются по ссылкам.\nЧтобы убедиться в этом, создадим несколько переменных, содержащих один список, и посмотрим, как они меняются:",[422,19736,19738],{"className":424,"code":19737,"language":396,"meta":426,"style":426},"items = [1, 2]\nitems2 = items\nitems2[0] = \"python\"\nprint(items2) #=> [\"python\", 2]\nprint(items) #=> [\"python\", 2]\n",[428,19739,19740,19756,19766,19780,19790],{"__ignoreMap":426},[431,19741,19742,19744,19746,19748,19750,19752,19754],{"class":433,"line":434},[431,19743,17468],{"class":441},[431,19745,1189],{"class":654},[431,19747,17401],{"class":441},[431,19749,1192],{"class":437},[431,19751,4846],{"class":441},[431,19753,651],{"class":437},[431,19755,3568],{"class":441},[431,19757,19758,19761,19763],{"class":433,"line":452},[431,19759,19760],{"class":441},"items2 ",[431,19762,1189],{"class":654},[431,19764,19765],{"class":441}," items\n",[431,19767,19768,19771,19773,19775,19777],{"class":433,"line":578},[431,19769,19770],{"class":441},"items2[",[431,19772,3302],{"class":437},[431,19774,4049],{"class":441},[431,19776,1189],{"class":654},[431,19778,19779],{"class":445}," \"python\"\n",[431,19781,19782,19784,19787],{"class":433,"line":584},[431,19783,438],{"class":437},[431,19785,19786],{"class":441},"(items2) ",[431,19788,19789],{"class":455},"#=> [\"python\", 2]\n",[431,19791,19792,19794,19797],{"class":433,"line":1244},[431,19793,438],{"class":437},[431,19795,19796],{"class":441},"(items) ",[431,19798,19789],{"class":455},[415,19800,19801],{},"В примере выше создаем новую переменную items2 и записываем в нее ссылку на переменную items.\nТеперь две переменные ссылаются на один и тот же список.\nА значит изменив список в любой из переменных, он поменяется и для другой.",[415,19803,19804],{},"Ссылка это уникальный идентификатор объекта, условный адрес в виртуальной памяти интерпретатора, по которому хранится значение переменной.\nПолучить этот адрес можно функцией id():",[422,19806,19808],{"className":424,"code":19807,"language":396,"meta":426,"style":426},"a = 42\nid(a) # 140708400662728\n",[428,19809,19810,19819],{"__ignoreMap":426},[431,19811,19812,19814,19816],{"class":433,"line":434},[431,19813,3193],{"class":441},[431,19815,1189],{"class":654},[431,19817,19818],{"class":437}," 42\n",[431,19820,19821,19824,19827],{"class":433,"line":452},[431,19822,19823],{"class":437},"id",[431,19825,19826],{"class":441},"(a) ",[431,19828,19829],{"class":455},"# 140708400662728\n",[415,19831,19832],{},"Идентификатор — это обычное число. Но у каждого объекта свой уникальный идентификатор.\nПоэтому идентификаторы удобно использовать,\nчтобы отслеживать передачи ссылок на объект между разными участками кода — идентификатор объекта будет одним и тем же,\nпо какой бы ссылке к объекту ни обращались:",[422,19834,19836],{"className":424,"code":19835,"language":396,"meta":426,"style":426},"a = \"Hello, Python!\"\nb = a\nid(a)  # 1871043874544\nid(b)  # 1871043874544\nprint(a is b)  # => True\n",[428,19837,19838,19847,19856,19866,19875],{"__ignoreMap":426},[431,19839,19840,19842,19844],{"class":433,"line":434},[431,19841,3193],{"class":441},[431,19843,1189],{"class":654},[431,19845,19846],{"class":445}," \"Hello, Python!\"\n",[431,19848,19849,19851,19853],{"class":433,"line":452},[431,19850,3203],{"class":441},[431,19852,1189],{"class":654},[431,19854,19855],{"class":441}," a\n",[431,19857,19858,19860,19863],{"class":433,"line":578},[431,19859,19823],{"class":437},[431,19861,19862],{"class":441},"(a)  ",[431,19864,19865],{"class":455},"# 1871043874544\n",[431,19867,19868,19870,19873],{"class":433,"line":584},[431,19869,19823],{"class":437},[431,19871,19872],{"class":441},"(b)  ",[431,19874,19865],{"class":455},[431,19876,19877,19879,19882,19885,19888],{"class":433,"line":1244},[431,19878,438],{"class":437},[431,19880,19881],{"class":441},"(a ",[431,19883,19884],{"class":654},"is",[431,19886,19887],{"class":441}," b)  ",[431,19889,8470],{"class":455},[415,19891,19892,19893],{},"Когда мы создаем переменную и записываем в нее значение, то мы даем имя ссылке.\nДалее, мы присваиваем одну переменную другой, и даем еще одно, новое имя для этой же ссылки.\nПоэтому id(a) и id(b) возвращают одинаковый результат.\nОператор is проверяет равенство идентификаторов своих операндов.\nВ этом примере обе переменные ссылаются на один объект, поэтому проверка a is b дает True.\nПроверкой is в Python пользуются, когда мы имеем дело с так называемыми объектами-одиночками.\nСамые известные одиночки в Python, это True, False и None.\nПоэтому проверка на равенство None обычно пишется так: ",[428,19894,19895],{},"if foo is None:",[458,19897,19899],{"id":19898},"сравнение-списков","Сравнение списков",[415,19901,8664,19902,19904],{},[428,19903,8409],{}," сравнивает списки, и любые другие объекты, по значению.\nТо есть два списка будут равны, если имеют одинаковые значения:",[422,19906,19908],{"className":424,"code":19907,"language":396,"meta":426,"style":426},"[1, 2, 3] == [1, 2, 3] # True\n",[428,19909,19910],{"__ignoreMap":426},[431,19911,19912,19915,19917,19919,19921,19923,19925,19927,19929,19931,19933,19935,19937,19939,19941,19943],{"class":433,"line":434},[431,19913,19914],{"class":441},"[",[431,19916,1192],{"class":437},[431,19918,4846],{"class":441},[431,19920,651],{"class":437},[431,19922,4846],{"class":441},[431,19924,971],{"class":437},[431,19926,4049],{"class":441},[431,19928,8409],{"class":654},[431,19930,17401],{"class":441},[431,19932,1192],{"class":437},[431,19934,4846],{"class":441},[431,19936,651],{"class":437},[431,19938,4846],{"class":441},[431,19940,971],{"class":437},[431,19942,4049],{"class":441},[431,19944,19945],{"class":455},"# True\n",[415,19947,19948],{},"Списки также можно сравнивать и по ссылке:",[422,19950,19952],{"className":424,"code":19951,"language":396,"meta":426,"style":426},"items = [1, 2, 3]\nitems2 = [1, 2, 3]\nprint(items2 == items) # True\nprint(items2 is items) # False\n",[428,19953,19954,19974,19994,20008],{"__ignoreMap":426},[431,19955,19956,19958,19960,19962,19964,19966,19968,19970,19972],{"class":433,"line":434},[431,19957,17468],{"class":441},[431,19959,1189],{"class":654},[431,19961,17401],{"class":441},[431,19963,1192],{"class":437},[431,19965,4846],{"class":441},[431,19967,651],{"class":437},[431,19969,4846],{"class":441},[431,19971,971],{"class":437},[431,19973,3568],{"class":441},[431,19975,19976,19978,19980,19982,19984,19986,19988,19990,19992],{"class":433,"line":452},[431,19977,19760],{"class":441},[431,19979,1189],{"class":654},[431,19981,17401],{"class":441},[431,19983,1192],{"class":437},[431,19985,4846],{"class":441},[431,19987,651],{"class":437},[431,19989,4846],{"class":441},[431,19991,971],{"class":437},[431,19993,3568],{"class":441},[431,19995,19996,19998,20001,20003,20006],{"class":433,"line":578},[431,19997,438],{"class":437},[431,19999,20000],{"class":441},"(items2 ",[431,20002,8409],{"class":654},[431,20004,20005],{"class":441}," items) ",[431,20007,19945],{"class":455},[431,20009,20010,20012,20014,20016,20018],{"class":433,"line":584},[431,20011,438],{"class":437},[431,20013,20000],{"class":441},[431,20015,19884],{"class":654},[431,20017,20005],{"class":441},[431,20019,20020],{"class":455},"# False\n",[415,20022,20023],{},"В этом примере, хоть списки и содержат одинаковые значения, но каждый список ссылается на свой адрес в виртуальной памяти.",[458,20025,20027],{"id":20026},"проектирование-функций-работающих-со-списками","Проектирование функций работающих со списками",[415,20029,20030],{},"Если передать список в какую-то функцию, которая его изменяет, то список тоже изменится.\nВедь в функцию передается именно ссылка на список. Посмотрите на пример:",[422,20032,20034],{"className":424,"code":20033,"language":396,"meta":426,"style":426},"def append_wow(some_list):\n  some_list.append('wow')\n\nitems = ['one']\nappend_wow(items)\nprint(items) # => ['one', 'wow']\nappend_wow(items)\nprint(items) # => ['one', 'wow', 'wow']\n",[428,20035,20036,20046,20056,20060,20073,20078,20087,20091],{"__ignoreMap":426},[431,20037,20038,20040,20043],{"class":433,"line":434},[431,20039,6330],{"class":654},[431,20041,20042],{"class":6333}," append_wow",[431,20044,20045],{"class":441},"(some_list):\n",[431,20047,20048,20051,20054],{"class":433,"line":452},[431,20049,20050],{"class":441},"  some_list.append(",[431,20052,20053],{"class":445},"'wow'",[431,20055,449],{"class":441},[431,20057,20058],{"class":433,"line":578},[431,20059,1662],{"emptyLinePlaceholder":393},[431,20061,20062,20064,20066,20068,20071],{"class":433,"line":584},[431,20063,17468],{"class":441},[431,20065,1189],{"class":654},[431,20067,17401],{"class":441},[431,20069,20070],{"class":445},"'one'",[431,20072,3568],{"class":441},[431,20074,20075],{"class":433,"line":1244},[431,20076,20077],{"class":441},"append_wow(items)\n",[431,20079,20080,20082,20084],{"class":433,"line":1985},[431,20081,438],{"class":437},[431,20083,19796],{"class":441},[431,20085,20086],{"class":455},"# => ['one', 'wow']\n",[431,20088,20089],{"class":433,"line":2041},[431,20090,20077],{"class":441},[431,20092,20093,20095,20097],{"class":433,"line":4018},[431,20094,438],{"class":437},[431,20096,19796],{"class":441},[431,20098,20099],{"class":455},"# => ['one', 'wow', 'wow']\n",[415,20101,20102],{},"Проектируя функции, работающие со списками, есть два пути: менять исходный список или формировать внутри новый и возвращать его наружу.\nКакой лучше? В подавляющем большинстве случаев стоит предпочитать второй. Это безопасно.\nФункции, возвращающие новые значения, удобнее в работе, а поведение программы становится в целом более предсказуемым,\nтак как отсутствуют неконтролируемые изменения данных.\nИзменение списка может повлечь за собой неожиданные эффекты.\nПредставьте себе функцию last(), которая извлекает последний элемент из списка.\nОна могла бы быть написана так:",[422,20104,20106],{"className":424,"code":20105,"language":396,"meta":426,"style":426},"def last(items):\n  # Метод .pop() извлекает последний элемент из списка\n  # Он изменяет список, удаляя оттуда этот элемент\n  return items.pop()\n\nitems = [1, 2, 3]\nlast_item = last(items)\nprint(last_item) # 3\nprint(items) # [1, 2]\n",[428,20107,20108,20118,20123,20128,20136,20140,20160,20170,20179],{"__ignoreMap":426},[431,20109,20110,20112,20115],{"class":433,"line":434},[431,20111,6330],{"class":654},[431,20113,20114],{"class":6333}," last",[431,20116,20117],{"class":441},"(items):\n",[431,20119,20120],{"class":433,"line":452},[431,20121,20122],{"class":455},"  # Метод .pop() извлекает последний элемент из списка\n",[431,20124,20125],{"class":433,"line":578},[431,20126,20127],{"class":455},"  # Он изменяет список, удаляя оттуда этот элемент\n",[431,20129,20130,20133],{"class":433,"line":584},[431,20131,20132],{"class":654},"  return",[431,20134,20135],{"class":441}," items.pop()\n",[431,20137,20138],{"class":433,"line":1244},[431,20139,1662],{"emptyLinePlaceholder":393},[431,20141,20142,20144,20146,20148,20150,20152,20154,20156,20158],{"class":433,"line":1985},[431,20143,17468],{"class":441},[431,20145,1189],{"class":654},[431,20147,17401],{"class":441},[431,20149,1192],{"class":437},[431,20151,4846],{"class":441},[431,20153,651],{"class":437},[431,20155,4846],{"class":441},[431,20157,971],{"class":437},[431,20159,3568],{"class":441},[431,20161,20162,20165,20167],{"class":433,"line":2041},[431,20163,20164],{"class":441},"last_item ",[431,20166,1189],{"class":654},[431,20168,20169],{"class":441}," last(items)\n",[431,20171,20172,20174,20177],{"class":433,"line":4018},[431,20173,438],{"class":437},[431,20175,20176],{"class":441},"(last_item) ",[431,20178,5340],{"class":455},[431,20180,20181,20183,20185],{"class":433,"line":4030},[431,20182,438],{"class":437},[431,20184,19796],{"class":441},[431,20186,20187],{"class":455},"# [1, 2]\n",[415,20189,20190],{},"Где-то в коде вы просто хотели посмотреть последний элемент.\nА в дополнение к этому, функция для извлечения этого элемента взяла и удалила его оттуда.\nЭто поведение очень неожиданно для подобной функции.\nОно противоречит большому количеству принципов построения хорошего кода (например \"Command–query separation\").\nПравильная реализация данной функции выглядит так:",[422,20192,20194],{"className":424,"code":20193,"language":396,"meta":426,"style":426},"# Список не изменяется\n# Индекс -1 означает первый элемент с конца\ndef last(items):\n  return items[-1]\n\nitems = [1, 2, 3]\nprint(last(items)) # => 3\nprint(items) # => [1, 2, 3]\n",[428,20195,20196,20201,20206,20214,20227,20231,20251,20260],{"__ignoreMap":426},[431,20197,20198],{"class":433,"line":434},[431,20199,20200],{"class":455},"# Список не изменяется\n",[431,20202,20203],{"class":433,"line":452},[431,20204,20205],{"class":455},"# Индекс -1 означает первый элемент с конца\n",[431,20207,20208,20210,20212],{"class":433,"line":578},[431,20209,6330],{"class":654},[431,20211,20114],{"class":6333},[431,20213,20117],{"class":441},[431,20215,20216,20218,20221,20223,20225],{"class":433,"line":584},[431,20217,20132],{"class":654},[431,20219,20220],{"class":441}," items[",[431,20222,853],{"class":654},[431,20224,1192],{"class":437},[431,20226,3568],{"class":441},[431,20228,20229],{"class":433,"line":1244},[431,20230,1662],{"emptyLinePlaceholder":393},[431,20232,20233,20235,20237,20239,20241,20243,20245,20247,20249],{"class":433,"line":1985},[431,20234,17468],{"class":441},[431,20236,1189],{"class":654},[431,20238,17401],{"class":441},[431,20240,1192],{"class":437},[431,20242,4846],{"class":441},[431,20244,651],{"class":437},[431,20246,4846],{"class":441},[431,20248,971],{"class":437},[431,20250,3568],{"class":441},[431,20252,20253,20255,20258],{"class":433,"line":2041},[431,20254,438],{"class":437},[431,20256,20257],{"class":441},"(last(items)) ",[431,20259,4513],{"class":455},[431,20261,20262,20264,20266],{"class":433,"line":4018},[431,20263,438],{"class":437},[431,20265,19796],{"class":441},[431,20267,20268],{"class":455},"# => [1, 2, 3]\n",[415,20270,20271],{},"В каких же случаях стоит менять сам список? Есть ровно одна причина, по которой так делают – производительность.\nИменно поэтому некоторые встроенные методы списков меняют их, например reverse() или sort():",[422,20273,20275],{"className":424,"code":20274,"language":396,"meta":426,"style":426},"items = [3, 2, 1, 5, 4]\nitems.sort()\nprint(items) # => [1, 2, 3, 4, 5]\nitems.reverse()\nprint(items) # => [5, 4, 3, 2, 1]\n",[428,20276,20277,20305,20310,20319,20324],{"__ignoreMap":426},[431,20278,20279,20281,20283,20285,20287,20289,20291,20293,20295,20297,20299,20301,20303],{"class":433,"line":434},[431,20280,17468],{"class":441},[431,20282,1189],{"class":654},[431,20284,17401],{"class":441},[431,20286,971],{"class":437},[431,20288,4846],{"class":441},[431,20290,651],{"class":437},[431,20292,4846],{"class":441},[431,20294,1192],{"class":437},[431,20296,4846],{"class":441},[431,20298,856],{"class":437},[431,20300,4846],{"class":441},[431,20302,762],{"class":437},[431,20304,3568],{"class":441},[431,20306,20307],{"class":433,"line":452},[431,20308,20309],{"class":441},"items.sort()\n",[431,20311,20312,20314,20316],{"class":433,"line":578},[431,20313,438],{"class":437},[431,20315,19796],{"class":441},[431,20317,20318],{"class":455},"# => [1, 2, 3, 4, 5]\n",[431,20320,20321],{"class":433,"line":584},[431,20322,20323],{"class":441},"items.reverse()\n",[431,20325,20326,20328,20330],{"class":433,"line":1244},[431,20327,438],{"class":437},[431,20329,19796],{"class":441},[431,20331,20332],{"class":455},"# => [5, 4, 3, 2, 1]\n",[458,20334,20336],{"id":20335},"копирование-списков","Копирование списков",[415,20338,20339],{},"В Python нет встроенных методов или функций, которые изменяют список, но возвращают новый, не трогая старый.\nЧтобы изменить список, не затрагивая изначальный, его нужно скопировать.",[422,20341,20343],{"className":424,"code":20342,"language":396,"meta":426,"style":426},"def append(items, item):\n  # Или items_copy = items[:]\n  items_copy = items.copy()\n  items_copy.append(item)\n  return items_copy\n\nitems = [1, 2, 3]\nitems2 = append(items, 4)\nprint(items) # => [1, 2, 3]\nprint(items2) # => [1, 2, 3, 4]\n",[428,20344,20345,20355,20360,20370,20375,20382,20386,20406,20419,20427],{"__ignoreMap":426},[431,20346,20347,20349,20352],{"class":433,"line":434},[431,20348,6330],{"class":654},[431,20350,20351],{"class":6333}," append",[431,20353,20354],{"class":441},"(items, item):\n",[431,20356,20357],{"class":433,"line":452},[431,20358,20359],{"class":455},"  # Или items_copy = items[:]\n",[431,20361,20362,20365,20367],{"class":433,"line":578},[431,20363,20364],{"class":441},"  items_copy ",[431,20366,1189],{"class":654},[431,20368,20369],{"class":441}," items.copy()\n",[431,20371,20372],{"class":433,"line":584},[431,20373,20374],{"class":441},"  items_copy.append(item)\n",[431,20376,20377,20379],{"class":433,"line":1244},[431,20378,20132],{"class":654},[431,20380,20381],{"class":441}," items_copy\n",[431,20383,20384],{"class":433,"line":1985},[431,20385,1662],{"emptyLinePlaceholder":393},[431,20387,20388,20390,20392,20394,20396,20398,20400,20402,20404],{"class":433,"line":2041},[431,20389,17468],{"class":441},[431,20391,1189],{"class":654},[431,20393,17401],{"class":441},[431,20395,1192],{"class":437},[431,20397,4846],{"class":441},[431,20399,651],{"class":437},[431,20401,4846],{"class":441},[431,20403,971],{"class":437},[431,20405,3568],{"class":441},[431,20407,20408,20410,20412,20415,20417],{"class":433,"line":4018},[431,20409,19760],{"class":441},[431,20411,1189],{"class":654},[431,20413,20414],{"class":441}," append(items, ",[431,20416,762],{"class":437},[431,20418,449],{"class":441},[431,20420,20421,20423,20425],{"class":433,"line":4030},[431,20422,438],{"class":437},[431,20424,19796],{"class":441},[431,20426,20268],{"class":455},[431,20428,20429,20431,20433],{"class":433,"line":4419},[431,20430,438],{"class":437},[431,20432,19786],{"class":441},[431,20434,20435],{"class":455},"# => [1, 2, 3, 4]\n",[415,20437,20438],{},"Несмотря на то, что подход, меняющий списки напрямую, сложнее в отладке, его используют в некоторых языках для увеличения эффективности работы программы.\nЕсли список достаточно большой, то полное копирование окажется дорогой операцией.\nВ реальной веб-разработчике это почти никогда не является проблемой, но знать об этом полезно.",[632,20440,20442],{"id":20441},"агрегация","Агрегация",[415,20444,20445],{},"Распространенный вариант использования циклов со списками — агрегация.\nАгрегацией называются любые вычисления, которые строятся на основе всего набора данных: например, поиск максимального значения, среднего, суммы и так далее.\nПроцесс агрегации не требует от программиста знания нового синтаксиса, но влияет на алгоритм решения задач.\nПоэтому имеет смысл рассмотреть его отдельно. Начнем с поиска максимального значения:",[422,20447,20449],{"className":424,"code":20448,"language":396,"meta":426,"style":426},"def calc_max(lst):\n  # Если коллекция пустая, то у нее не может быть максимального значения\n  # В подобных ситуациях принято возвращать None\n  # Это классический пример использования идиомы guard expression\n  if lst == []:\n    return None\n  # Сравнение элементов начинаем с первого элемента\n  max = lst[0]\n  # Обход начинаем со второго элемента\n  for i in range(1, len(lst)):\n    current = lst[i]\n    # Если текущий элемент больше максимального,\n    # то он становится максимальным\n    if current > max:\n      max = current\n  # Не забываем вернуть максимальное число\n  return max\n\nprint(calc_max([])) # => None\nprint(calc_max([3, 2, -10, 35, 0])) #=> 35\n",[428,20450,20451,20461,20466,20471,20476,20489,20495,20500,20514,20519,20541,20551,20556,20561,20575,20585,20590,20597,20601,20610],{"__ignoreMap":426},[431,20452,20453,20455,20458],{"class":433,"line":434},[431,20454,6330],{"class":654},[431,20456,20457],{"class":6333}," calc_max",[431,20459,20460],{"class":441},"(lst):\n",[431,20462,20463],{"class":433,"line":452},[431,20464,20465],{"class":455},"  # Если коллекция пустая, то у нее не может быть максимального значения\n",[431,20467,20468],{"class":433,"line":578},[431,20469,20470],{"class":455},"  # В подобных ситуациях принято возвращать None\n",[431,20472,20473],{"class":433,"line":584},[431,20474,20475],{"class":455},"  # Это классический пример использования идиомы guard expression\n",[431,20477,20478,20481,20484,20486],{"class":433,"line":1244},[431,20479,20480],{"class":654},"  if",[431,20482,20483],{"class":441}," lst ",[431,20485,8409],{"class":654},[431,20487,20488],{"class":441}," []:\n",[431,20490,20491,20493],{"class":433,"line":1985},[431,20492,6599],{"class":654},[431,20494,11872],{"class":437},[431,20496,20497],{"class":433,"line":2041},[431,20498,20499],{"class":455},"  # Сравнение элементов начинаем с первого элемента\n",[431,20501,20502,20505,20507,20510,20512],{"class":433,"line":4018},[431,20503,20504],{"class":437},"  max",[431,20506,2146],{"class":654},[431,20508,20509],{"class":441}," lst[",[431,20511,3302],{"class":437},[431,20513,3568],{"class":441},[431,20515,20516],{"class":433,"line":4030},[431,20517,20518],{"class":455},"  # Обход начинаем со второго элемента\n",[431,20520,20521,20524,20526,20528,20530,20532,20534,20536,20538],{"class":433,"line":4419},[431,20522,20523],{"class":654},"  for",[431,20525,12664],{"class":441},[431,20527,14421],{"class":654},[431,20529,14424],{"class":437},[431,20531,442],{"class":441},[431,20533,1192],{"class":437},[431,20535,4846],{"class":441},[431,20537,5205],{"class":437},[431,20539,20540],{"class":441},"(lst)):\n",[431,20542,20543,20546,20548],{"class":433,"line":4436},[431,20544,20545],{"class":441},"    current ",[431,20547,1189],{"class":654},[431,20549,20550],{"class":441}," lst[i]\n",[431,20552,20553],{"class":433,"line":4446},[431,20554,20555],{"class":455},"    # Если текущий элемент больше максимального,\n",[431,20557,20558],{"class":433,"line":4451},[431,20559,20560],{"class":455},"    # то он становится максимальным\n",[431,20562,20563,20565,20568,20570,20573],{"class":433,"line":4086},[431,20564,10438],{"class":654},[431,20566,20567],{"class":441}," current ",[431,20569,8883],{"class":654},[431,20571,20572],{"class":437}," max",[431,20574,8102],{"class":441},[431,20576,20577,20580,20582],{"class":433,"line":4477},[431,20578,20579],{"class":437},"      max",[431,20581,2146],{"class":654},[431,20583,20584],{"class":441}," current\n",[431,20586,20587],{"class":433,"line":4482},[431,20588,20589],{"class":455},"  # Не забываем вернуть максимальное число\n",[431,20591,20592,20594],{"class":433,"line":4488},[431,20593,20132],{"class":654},[431,20595,20596],{"class":437}," max\n",[431,20598,20599],{"class":433,"line":4505},[431,20600,1662],{"emptyLinePlaceholder":393},[431,20602,20603,20605,20608],{"class":433,"line":12871},[431,20604,438],{"class":437},[431,20606,20607],{"class":441},"(calc_max([])) ",[431,20609,6577],{"class":455},[431,20611,20612,20614,20617,20619,20621,20623,20625,20627,20629,20631,20634,20636,20638,20641],{"class":433,"line":2874},[431,20613,438],{"class":437},[431,20615,20616],{"class":441},"(calc_max([",[431,20618,971],{"class":437},[431,20620,4846],{"class":441},[431,20622,651],{"class":437},[431,20624,4846],{"class":441},[431,20626,853],{"class":654},[431,20628,3565],{"class":437},[431,20630,4846],{"class":441},[431,20632,20633],{"class":437},"35",[431,20635,4846],{"class":441},[431,20637,3302],{"class":437},[431,20639,20640],{"class":441},"])) ",[431,20642,20643],{"class":455},"#=> 35\n",[415,20645,20646],{},"В этом примере агрегации мы видим вычисление.\nОно включает в себя сравнение всех элементов для поиска одного, которое станет результатом этой операции.\nОбратите внимание, что начальным значением max взят первый элемент, а не 0 или любое другое число.\nВедь может оказаться так, что все числа в списке меньше 0, и тогда мы получим неверный ответ.",[458,20648,20650],{"id":20649},"нейтральный-элемент","Нейтральный элемент",[415,20652,20653],{},"Рассмотрим поиск суммы:",[422,20655,20657],{"className":424,"code":20656,"language":396,"meta":426,"style":426},"def calc_sum(lst):\n    # Начальное значение суммы\n    sum = 0\n    for i in range(len(lst)):\n        # Поочередно складываем все элементы\n        sum += lst[i]\n    return sum\n\n# Сумма элементов всегда возвращает какое-то число\n# Если список пустой, то сумма его элементов равна нулю\nprint(calc_sum([]))  # => 0\nprint(calc_sum([3, 2, -10, 38, 0]))  # => 33\n",[428,20658,20659,20667,20672,20680,20696,20701,20709,20715,20719,20724,20729,20738],{"__ignoreMap":426},[431,20660,20661,20663,20665],{"class":433,"line":434},[431,20662,6330],{"class":654},[431,20664,18675],{"class":6333},[431,20666,20460],{"class":441},[431,20668,20669],{"class":433,"line":452},[431,20670,20671],{"class":455},"    # Начальное значение суммы\n",[431,20673,20674,20676,20678],{"class":433,"line":578},[431,20675,13181],{"class":437},[431,20677,2146],{"class":654},[431,20679,3459],{"class":437},[431,20681,20682,20684,20686,20688,20690,20692,20694],{"class":433,"line":584},[431,20683,14745],{"class":654},[431,20685,12664],{"class":441},[431,20687,14421],{"class":654},[431,20689,14424],{"class":437},[431,20691,442],{"class":441},[431,20693,5205],{"class":437},[431,20695,20540],{"class":441},[431,20697,20698],{"class":433,"line":1244},[431,20699,20700],{"class":455},"        # Поочередно складываем все элементы\n",[431,20702,20703,20705,20707],{"class":433,"line":1985},[431,20704,13207],{"class":437},[431,20706,14372],{"class":654},[431,20708,20550],{"class":441},[431,20710,20711,20713],{"class":433,"line":2041},[431,20712,6599],{"class":654},[431,20714,13247],{"class":437},[431,20716,20717],{"class":433,"line":4018},[431,20718,1662],{"emptyLinePlaceholder":393},[431,20720,20721],{"class":433,"line":4030},[431,20722,20723],{"class":455},"# Сумма элементов всегда возвращает какое-то число\n",[431,20725,20726],{"class":433,"line":4419},[431,20727,20728],{"class":455},"# Если список пустой, то сумма его элементов равна нулю\n",[431,20730,20731,20733,20736],{"class":433,"line":4436},[431,20732,438],{"class":437},[431,20734,20735],{"class":441},"(calc_sum([]))  ",[431,20737,4377],{"class":455},[431,20739,20740,20742,20744,20746,20748,20750,20752,20754,20756,20758,20760,20762,20764,20766],{"class":433,"line":4446},[431,20741,438],{"class":437},[431,20743,18723],{"class":441},[431,20745,971],{"class":437},[431,20747,4846],{"class":441},[431,20749,651],{"class":437},[431,20751,4846],{"class":441},[431,20753,853],{"class":654},[431,20755,3565],{"class":437},[431,20757,4846],{"class":441},[431,20759,18740],{"class":437},[431,20761,4846],{"class":441},[431,20763,3302],{"class":437},[431,20765,18747],{"class":441},[431,20767,20768],{"class":455},"# => 33\n",[415,20770,20771],{},"Процесс вычислений: sum = 0 => sum = sum + 3  # 3 => sum = sum + 2  # 5 => sum = sum + -10  # -5 => sum = sum + 38  # 33\n=> sum = sum + 0  # 33",[415,20773,20774],{},"Алгоритм поиска суммы значительно проще, но обладает парой важных нюансов.\nЧему равна сумма элементов пустого списка? С точки зрения математики такая сумма равна 0, что совпадает со здравым смыслом.\nЕсли у нас нет яблок, значит у нас есть 0 яблок. Другими словами, количество яблок равно нулю.\nФункции в программировании работают по такой же логике.\nВторой момент связан с начальным элементом суммы. У переменной sum есть начальное значение равное 0.\nЗачем вообще задавать значение? Любая повторяющаяся операция начинается с какого-то значения.\nНельзя просто так объявить переменную и начать с ней работать внутри цикла.\nЭто приведет к неверному результату:",[422,20776,20778],{"className":424,"code":20777,"language":396,"meta":426,"style":426},"# В Python мы не можем создать переменную не задав какое-то значение\n# В качестве \"отсутствия значения\" используем None\nsum = None\n# Первая итерация цикла\nsum = sum + 1\n",[428,20779,20780,20785,20790,20798,20803],{"__ignoreMap":426},[431,20781,20782],{"class":433,"line":434},[431,20783,20784],{"class":455},"# В Python мы не можем создать переменную не задав какое-то значение\n",[431,20786,20787],{"class":433,"line":452},[431,20788,20789],{"class":455},"# В качестве \"отсутствия значения\" используем None\n",[431,20791,20792,20794,20796],{"class":433,"line":578},[431,20793,13265],{"class":437},[431,20795,2146],{"class":654},[431,20797,11872],{"class":437},[431,20799,20800],{"class":433,"line":584},[431,20801,20802],{"class":455},"# Первая итерация цикла\n",[431,20804,20805,20807,20809,20811,20813],{"class":433,"line":1244},[431,20806,13265],{"class":437},[431,20808,2146],{"class":654},[431,20810,13212],{"class":437},[431,20812,655],{"class":654},[431,20814,3916],{"class":437},[415,20816,20817,20818,20821],{},"В результате такого вызова внутри будет ошибка ",[428,20819,20820],{},"TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'",".\nОна возникает из-за попытки сложить 1 и None. Значит какое-то значение все же нужно.\nВ коде выше выбран 0, потому что все остальные варианты приведут к неверному результату.\nЕсли начальное значение будет равно 1, то результат получится на единицу больше, чем нужно.\nВ математике существует понятие нейтральный элемент бинарной операции — это элемент, который ничего не меняет в результате его использования.\nДругими словами, сложение любого числа с нулем всегда дает это же число.\nТогда любую сумму, например 3 + 2 + 8, можно вычислить как 0 + 3 + 2 + 8, чем мы и пользуемся в нашем коде.\nНейтральный элемент – это важная часть любой агрегирующей операции. Именно с него начинается сам процесс агрегации.\nВ случае сложения – это 0, в случае умножения – 1.\nДаже у конкатенации есть нейтральный элемент – это пустая строка: '' + 'one' будет 'one'.\nАгрегация далеко не всегда означает, что коллекция элементов сводится к некоторому простому значению.\nРезультатом агрегации может быть даже сложная структура — например, список.\nПодобные примеры часто встречаются в реальных задачах. Самый простой пример – это список уникальных слов в тексте.",[632,20823,20825],{"id":20824},"удаление-элементов-списка","Удаление элементов списка",[415,20827,20828,20829,20832,20833,20835],{},"В Python для удаления элементов из списка есть метод ",[800,20830,20831],{},".pop()"," и оператор ",[800,20834,18216],{},".\nНо они изменяют изначальный список, что может привести к ошибкам в коде:",[422,20837,20839],{"className":424,"code":20838,"language":396,"meta":426,"style":426},"# Если удалять элементы в цикле\n# то ломается порядок обхода\nnumbers = [1, 0, 2, 0, 3, 4]\nfor i in range(len(numbers)):\n    print('Текущий элемент = ', numbers[i])\n    if numbers[i] == 0:\n        numbers.pop(i)\n\n#=> Текущий элемент =  1\n#=> Текущий элемент =  0\n# 0\n#=> Текущий элемент =  0\n# 0\n#=> Текущий элемент =  4\n# IndexError: list index out of range\n",[428,20840,20841,20846,20851,20883,20900,20912,20925,20930,20934,20939,20944,20948,20952,20956,20961],{"__ignoreMap":426},[431,20842,20843],{"class":433,"line":434},[431,20844,20845],{"class":455},"# Если удалять элементы в цикле\n",[431,20847,20848],{"class":433,"line":452},[431,20849,20850],{"class":455},"# то ломается порядок обхода\n",[431,20852,20853,20855,20857,20859,20861,20863,20865,20867,20869,20871,20873,20875,20877,20879,20881],{"class":433,"line":578},[431,20854,19577],{"class":441},[431,20856,1189],{"class":654},[431,20858,17401],{"class":441},[431,20860,1192],{"class":437},[431,20862,4846],{"class":441},[431,20864,3302],{"class":437},[431,20866,4846],{"class":441},[431,20868,651],{"class":437},[431,20870,4846],{"class":441},[431,20872,3302],{"class":437},[431,20874,4846],{"class":441},[431,20876,971],{"class":437},[431,20878,4846],{"class":441},[431,20880,762],{"class":437},[431,20882,3568],{"class":441},[431,20884,20885,20887,20889,20891,20893,20895,20897],{"class":433,"line":584},[431,20886,14329],{"class":654},[431,20888,12664],{"class":441},[431,20890,14421],{"class":654},[431,20892,14424],{"class":437},[431,20894,442],{"class":441},[431,20896,5205],{"class":437},[431,20898,20899],{"class":441},"(numbers)):\n",[431,20901,20902,20904,20906,20909],{"class":433,"line":1244},[431,20903,6357],{"class":437},[431,20905,442],{"class":441},[431,20907,20908],{"class":445},"'Текущий элемент = '",[431,20910,20911],{"class":441},", numbers[i])\n",[431,20913,20914,20916,20919,20921,20923],{"class":433,"line":1985},[431,20915,10438],{"class":654},[431,20917,20918],{"class":441}," numbers[i] ",[431,20920,8409],{"class":654},[431,20922,9744],{"class":437},[431,20924,8102],{"class":441},[431,20926,20927],{"class":433,"line":2041},[431,20928,20929],{"class":441},"        numbers.pop(i)\n",[431,20931,20932],{"class":433,"line":4018},[431,20933,1662],{"emptyLinePlaceholder":393},[431,20935,20936],{"class":433,"line":4030},[431,20937,20938],{"class":455},"#=> Текущий элемент =  1\n",[431,20940,20941],{"class":433,"line":4419},[431,20942,20943],{"class":455},"#=> Текущий элемент =  0\n",[431,20945,20946],{"class":433,"line":4436},[431,20947,13922],{"class":455},[431,20949,20950],{"class":433,"line":4446},[431,20951,20943],{"class":455},[431,20953,20954],{"class":433,"line":4451},[431,20955,13922],{"class":455},[431,20957,20958],{"class":433,"line":4086},[431,20959,20960],{"class":455},"#=> Текущий элемент =  4\n",[431,20962,20963],{"class":433,"line":4477},[431,20964,18366],{"class":455},[415,20966,20967,20968,20971,20972,3562],{},"В примере выше мы получили ошибку, потому что удаляя элемент мы смещаем указатель дальше по списку, и перепрыгиваем элементы.\nПри этом задача удаления возникает регулярно. Причем обычно удаляется не один элемент, а набор элементов по определенным правилам.\nНапример, довольно распространена операция ",[800,20969,20970],{},"compact"," – удаление None значений из списка. Как правильно ее реализовать?\nВ подавляющем большинстве ситуаций изменение списка должно трансформироваться в создание нового списка, в котором отсутствуют удаляемые элементы.\nНиже пример реализации функции ",[428,20973,20974],{},"compact()",[422,20976,20978],{"className":424,"code":20977,"language":396,"meta":426,"style":426},"def compact(lst):\n    # Инициализация результата\n    # Для пустой входной коллекции результатом будет пустой список\n    result = []\n    for item in lst:\n        if item is not None:\n            result.append(item)\n    return result\n\nprint(compact([0, 1, False, None, True, 'wow', None]))\n# => [0, 1, False, True, 'wow']\nprint(compact([]))\n# => []\n",[428,20979,20980,20989,20994,20999,21008,21020,21035,21040,21046,21050,21086,21091,21098],{"__ignoreMap":426},[431,20981,20982,20984,20987],{"class":433,"line":434},[431,20983,6330],{"class":654},[431,20985,20986],{"class":6333}," compact",[431,20988,20460],{"class":441},[431,20990,20991],{"class":433,"line":452},[431,20992,20993],{"class":455},"    # Инициализация результата\n",[431,20995,20996],{"class":433,"line":578},[431,20997,20998],{"class":455},"    # Для пустой входной коллекции результатом будет пустой список\n",[431,21000,21001,21003,21005],{"class":433,"line":584},[431,21002,6796],{"class":441},[431,21004,1189],{"class":654},[431,21006,21007],{"class":441}," []\n",[431,21009,21010,21012,21015,21017],{"class":433,"line":1244},[431,21011,14745],{"class":654},[431,21013,21014],{"class":441}," item ",[431,21016,14421],{"class":654},[431,21018,21019],{"class":441}," lst:\n",[431,21021,21022,21024,21026,21028,21030,21033],{"class":433,"line":1985},[431,21023,11471],{"class":654},[431,21025,21014],{"class":441},[431,21027,19884],{"class":654},[431,21029,9498],{"class":654},[431,21031,21032],{"class":437}," None",[431,21034,8102],{"class":441},[431,21036,21037],{"class":433,"line":2041},[431,21038,21039],{"class":441},"            result.append(item)\n",[431,21041,21042,21044],{"class":433,"line":4018},[431,21043,6599],{"class":654},[431,21045,6812],{"class":441},[431,21047,21048],{"class":433,"line":4030},[431,21049,1662],{"emptyLinePlaceholder":393},[431,21051,21052,21054,21057,21059,21061,21063,21065,21067,21069,21071,21073,21075,21077,21079,21081,21083],{"class":433,"line":4419},[431,21053,438],{"class":437},[431,21055,21056],{"class":441},"(compact([",[431,21058,3302],{"class":437},[431,21060,4846],{"class":441},[431,21062,1192],{"class":437},[431,21064,4846],{"class":441},[431,21066,4431],{"class":437},[431,21068,4846],{"class":441},[431,21070,7922],{"class":437},[431,21072,4846],{"class":441},[431,21074,4463],{"class":437},[431,21076,4846],{"class":441},[431,21078,20053],{"class":445},[431,21080,4846],{"class":441},[431,21082,7922],{"class":437},[431,21084,21085],{"class":441},"]))\n",[431,21087,21088],{"class":433,"line":4436},[431,21089,21090],{"class":455},"# => [0, 1, False, True, 'wow']\n",[431,21092,21093,21095],{"class":433,"line":4446},[431,21094,438],{"class":437},[431,21096,21097],{"class":441},"(compact([]))\n",[431,21099,21100],{"class":433,"line":4451},[431,21101,21102],{"class":455},"# => []\n",[415,21104,21105],{},"Главное, на что здесь нужно обратить внимание - не изменяется исходный список coll.\nВместо этого создается новый список result, который наполняется только подходящими под условие значениями.",[415,21107,1849,21108,1853,21110,1857],{},[800,21109,1852],{},[800,21111,1856],{},[1859,21113],{},[1862,21115,21116],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":426,"searchDepth":452,"depth":1244,"links":21118},[21119],{"id":18576,"depth":452,"text":210,"children":21120},[21121,21122,21127,21132,21135],{"id":18579,"depth":578,"text":18580},{"id":18822,"depth":578,"text":18823,"children":21123},[21124,21125,21126],{"id":18953,"depth":584,"text":18954},{"id":19327,"depth":584,"text":19328},{"id":19462,"depth":584,"text":19463},{"id":19730,"depth":578,"text":19731,"children":21128},[21129,21130,21131],{"id":19898,"depth":584,"text":19899},{"id":20026,"depth":584,"text":20027},{"id":20335,"depth":584,"text":20336},{"id":20441,"depth":578,"text":20442,"children":21133},[21134],{"id":20649,"depth":584,"text":20650},{"id":20824,"depth":578,"text":20825},"2025-03-23","Обход списков. Циклы с индексами для работы со списками. Обработка списков в функциях. Агрегация. Удаление элементов списка","images\u002Fblog\u002Fpython\u002Fst14\u002Fimg.png",{},{"title":210,"description":21137},"Vqe7uDdFvPmnmoY58HIniujQVxMaLBeRFnzII-lm9kc",{"id":21143,"title":214,"author":21144,"body":21146,"date":23006,"description":23007,"extension":1887,"image":23008,"meta":23009,"minRead":4488,"navigation":393,"num":4477,"path":215,"seo":23010,"stem":216,"__hash__":23011},"python\u002Fblog\u002Fpython\u002Fst15.md",{"name":402,"avatar":21145},{"src":404,"alt":405},{"type":407,"value":21147,"toc":22988},[21148,21151,21155,21158,21172,21176,21182,21186,21189,21305,21309,21312,21393,21398,21402,21405,21486,21490,21495,21551,21555,21558,21562,21565,21666,21678,21775,21778,21818,21834,21925,21930,22064,22068,22080,22145,22148,22183,22187,22193,22275,22279,22282,22360,22363,22435,22438,22519,22522,22618,22621,22678,22681,22717,22720,22753,22756,22878,22881,22955,22958,22977,22983,22985],[410,21149,214],{"id":21150},"использование-списков-ч1",[632,21152,21154],{"id":21153},"использование-списков-как-множеств","Использование списков как множеств",[415,21156,21157],{},"Теория множеств – крайне важная математическая концепция для любых разработчиков.\nДанные, с которыми работают программы, часто представляются как множества — значит, к ним применимы правила теории множеств.\nВ первую очередь это касается различных операций над множествами, например, пересечения или объединения.\nЭто не значит, что нужно знать эту теорию от и до.\nНапротив, достаточно изучить ее основные понятия и некоторые операции.\nЭтого хватит для эффективного решения подавляющего числа задач.\nСама теория множеств относится к интуитивно понятным концепциям.\nОна хорошо ложится на здравый смысл и понятна людям даже без особой математической подготовки.",[415,21159,21160,21163,21164,21168,21169,2699],{},[800,21161,21162],{},"Множеством"," обозначают набор объектов произвольной природы, который рассматривается как единое целое.\nПростейший пример — цифры. Множество всех цифр включает в себя 10 элементов (от 0 до 9).\nНо не каждый набор объектов можно назвать множеством.\nСуществует важное условие – все элементы множества должны быть уникальными.\nНапример, числа 1, 1 и 3 не могут называться множеством, а 1, 3, 5 могут.\nМножества между собой могут находиться в определенных отношениях.\nНапример, множество натуральных чисел является подмножеством целых чисел, которые в свою очередь являются подмножеством рациональных чисел и так далее.\nПонятие «подмножество» означает, что все элементы одного множества также входят в другое множество, называемое надмножеством.\n",[15324,21165],{"alt":21166,"src":21167},"Множества чисел","\u002Fimages\u002Fblog\u002Fpython\u002Fst15\u002Fimg1.png","\nПредставление множеств кружками довольно удобно. Можно быстро оценить как друг с другом соотносятся разные множества.\nНо математические объекты, такие как числа, не единственные возможные объекты множеств.\nМножеством можно назвать группу людей, стоящих на остановке в ожидании своего автобуса, или жильцов квартир одного дома, города или страны.\nВ программировании в качестве множеств могут выступать списки и таблицы в базе данных.\nВ Python для представления множеств есть встроенный тип ",[800,21170,21171],{},"set",[458,21173,21175],{"id":21174},"операции-над-множествами","Операции над множествами",[415,21177,21178,21179,2699],{},"На практике представление данных в виде множеств полезно тогда, когда мы хотим что-то сделать с ними.\nПростой пример. Когда во Вконтакте вы заходите на страницу другого человека, то Вконтакте показывает вам блок с общими друзьями.\nЕсли принять, что ваши друзья и друзья вашего друга — два множества, то общие друзья — множество, полученное как пересечение исходных множеств друзей.\nПересечение — один из ярких примеров операции над множествами, которая в программировании встречается повсеместно.\nТо же самое можно сказать и о некоторых других операциях.\nВажно, что результатом всех этих операций являются множества, а значит они подчиняются тем же правилам, что и исходные множества.\nНапример, сохраняется уникальность элементов.\nВ Python нет встроенных методов для работы со списками как с множествами.\nПоэтому мы используем библиотеку ",[800,21180,21181],{},"pydash",[12129,21183,21185],{"id":21184},"пересечение","Пересечение",[415,21187,21188],{},"Пересечением множеств называется множество, в которое входят элементы, встречающиеся во всех данных множествах одновременно.\nПример с общими друзьями:",[422,21190,21192],{"className":424,"code":21191,"language":396,"meta":426,"style":426},"import pydash.arrays as ar\n\n# Друзья одного человека\nfriends1 = ['Вася', 'Коля', 'Петя']\n# Друзья другого человека\nfriends2 = ['Игорь', 'Петя', 'Сергей', 'Вася', 'Саша']\n# Общие друзья\ncommon_friends = ar.intersection(friends1, friends2)\n\nprint(common_friends)  # ['Вася', 'Петя']\n",[428,21193,21194,21206,21210,21215,21239,21244,21276,21281,21291,21295],{"__ignoreMap":426},[431,21195,21196,21198,21201,21203],{"class":433,"line":434},[431,21197,5379],{"class":654},[431,21199,21200],{"class":441}," pydash.arrays ",[431,21202,15637],{"class":654},[431,21204,21205],{"class":441}," ar\n",[431,21207,21208],{"class":433,"line":452},[431,21209,1662],{"emptyLinePlaceholder":393},[431,21211,21212],{"class":433,"line":578},[431,21213,21214],{"class":455},"# Друзья одного человека\n",[431,21216,21217,21220,21222,21224,21227,21229,21232,21234,21237],{"class":433,"line":584},[431,21218,21219],{"class":441},"friends1 ",[431,21221,1189],{"class":654},[431,21223,17401],{"class":441},[431,21225,21226],{"class":445},"'Вася'",[431,21228,4846],{"class":441},[431,21230,21231],{"class":445},"'Коля'",[431,21233,4846],{"class":441},[431,21235,21236],{"class":445},"'Петя'",[431,21238,3568],{"class":441},[431,21240,21241],{"class":433,"line":1244},[431,21242,21243],{"class":455},"# Друзья другого человека\n",[431,21245,21246,21249,21251,21253,21256,21258,21260,21262,21265,21267,21269,21271,21274],{"class":433,"line":1985},[431,21247,21248],{"class":441},"friends2 ",[431,21250,1189],{"class":654},[431,21252,17401],{"class":441},[431,21254,21255],{"class":445},"'Игорь'",[431,21257,4846],{"class":441},[431,21259,21236],{"class":445},[431,21261,4846],{"class":441},[431,21263,21264],{"class":445},"'Сергей'",[431,21266,4846],{"class":441},[431,21268,21226],{"class":445},[431,21270,4846],{"class":441},[431,21272,21273],{"class":445},"'Саша'",[431,21275,3568],{"class":441},[431,21277,21278],{"class":433,"line":2041},[431,21279,21280],{"class":455},"# Общие друзья\n",[431,21282,21283,21286,21288],{"class":433,"line":4018},[431,21284,21285],{"class":441},"common_friends ",[431,21287,1189],{"class":654},[431,21289,21290],{"class":441}," ar.intersection(friends1, friends2)\n",[431,21292,21293],{"class":433,"line":4030},[431,21294,1662],{"emptyLinePlaceholder":393},[431,21296,21297,21299,21302],{"class":433,"line":4419},[431,21298,438],{"class":437},[431,21300,21301],{"class":441},"(common_friends)  ",[431,21303,21304],{"class":455},"# ['Вася', 'Петя']\n",[12129,21306,21308],{"id":21307},"объединение","Объединение",[415,21310,21311],{},"Объединением множеств называется множество, в которое входят элементы всех данных множеств.",[422,21313,21315],{"className":424,"code":21314,"language":396,"meta":426,"style":426},"import pydash.arrays as ar\n\nfriends1 = ['Вася', 'Коля', 'Петя']\nfriends2 = ['Игорь', 'Петя', 'Сергей', 'Вася', 'Саша']\n\nprint(ar.union(friends1, friends2)) # => ['Вася', 'Коля', 'Петя', 'Игорь', 'Сергей', 'Саша']\n",[428,21316,21317,21327,21331,21351,21379,21383],{"__ignoreMap":426},[431,21318,21319,21321,21323,21325],{"class":433,"line":434},[431,21320,5379],{"class":654},[431,21322,21200],{"class":441},[431,21324,15637],{"class":654},[431,21326,21205],{"class":441},[431,21328,21329],{"class":433,"line":452},[431,21330,1662],{"emptyLinePlaceholder":393},[431,21332,21333,21335,21337,21339,21341,21343,21345,21347,21349],{"class":433,"line":578},[431,21334,21219],{"class":441},[431,21336,1189],{"class":654},[431,21338,17401],{"class":441},[431,21340,21226],{"class":445},[431,21342,4846],{"class":441},[431,21344,21231],{"class":445},[431,21346,4846],{"class":441},[431,21348,21236],{"class":445},[431,21350,3568],{"class":441},[431,21352,21353,21355,21357,21359,21361,21363,21365,21367,21369,21371,21373,21375,21377],{"class":433,"line":584},[431,21354,21248],{"class":441},[431,21356,1189],{"class":654},[431,21358,17401],{"class":441},[431,21360,21255],{"class":445},[431,21362,4846],{"class":441},[431,21364,21236],{"class":445},[431,21366,4846],{"class":441},[431,21368,21264],{"class":445},[431,21370,4846],{"class":441},[431,21372,21226],{"class":445},[431,21374,4846],{"class":441},[431,21376,21273],{"class":445},[431,21378,3568],{"class":441},[431,21380,21381],{"class":433,"line":1244},[431,21382,1662],{"emptyLinePlaceholder":393},[431,21384,21385,21387,21390],{"class":433,"line":1985},[431,21386,438],{"class":437},[431,21388,21389],{"class":441},"(ar.union(friends1, friends2)) ",[431,21391,21392],{"class":455},"# => ['Вася', 'Коля', 'Петя', 'Игорь', 'Сергей', 'Саша']\n",[415,21394,21395],{},[1355,21396,21397],{},"Каждый друг в объединении встречается ровно один раз.",[12129,21399,21401],{"id":21400},"разность","Разность",[415,21403,21404],{},"Разностью двух множеств называется множество, в которое входят элементы первого множества, не входящие во второе.\nВ программировании такая операция часто называется diff (разница).",[422,21406,21408],{"className":424,"code":21407,"language":396,"meta":426,"style":426},"import pydash.arrays as ar\n\nfriends1 = ['Вася', 'Коля', 'Петя']\nfriends2 = ['Игорь', 'Петя', 'Сергей', 'Вася', 'Саша']\n\nprint(ar.difference(friends1, friends2)) # => ['Коля']\n",[428,21409,21410,21420,21424,21444,21472,21476],{"__ignoreMap":426},[431,21411,21412,21414,21416,21418],{"class":433,"line":434},[431,21413,5379],{"class":654},[431,21415,21200],{"class":441},[431,21417,15637],{"class":654},[431,21419,21205],{"class":441},[431,21421,21422],{"class":433,"line":452},[431,21423,1662],{"emptyLinePlaceholder":393},[431,21425,21426,21428,21430,21432,21434,21436,21438,21440,21442],{"class":433,"line":578},[431,21427,21219],{"class":441},[431,21429,1189],{"class":654},[431,21431,17401],{"class":441},[431,21433,21226],{"class":445},[431,21435,4846],{"class":441},[431,21437,21231],{"class":445},[431,21439,4846],{"class":441},[431,21441,21236],{"class":445},[431,21443,3568],{"class":441},[431,21445,21446,21448,21450,21452,21454,21456,21458,21460,21462,21464,21466,21468,21470],{"class":433,"line":584},[431,21447,21248],{"class":441},[431,21449,1189],{"class":654},[431,21451,17401],{"class":441},[431,21453,21255],{"class":445},[431,21455,4846],{"class":441},[431,21457,21236],{"class":445},[431,21459,4846],{"class":441},[431,21461,21264],{"class":445},[431,21463,4846],{"class":441},[431,21465,21226],{"class":445},[431,21467,4846],{"class":441},[431,21469,21273],{"class":445},[431,21471,3568],{"class":441},[431,21473,21474],{"class":433,"line":1244},[431,21475,1662],{"emptyLinePlaceholder":393},[431,21477,21478,21480,21483],{"class":433,"line":1985},[431,21479,438],{"class":437},[431,21481,21482],{"class":441},"(ar.difference(friends1, friends2)) ",[431,21484,21485],{"class":455},"# => ['Коля']\n",[12129,21487,21489],{"id":21488},"принадлежность-множеству","Принадлежность множеству",[415,21491,21492,21493,3562],{},"Проверку принадлежности элемента множеству можно выполнить с помощью встроенного оператора ",[428,21494,14421],{},[422,21496,21498],{"className":424,"code":21497,"language":396,"meta":426,"style":426},"numbers = [4, 13, 21]\nprint(13 in numbers) # => True\nprint(5 in numbers) # => False\n",[428,21499,21500,21521,21537],{"__ignoreMap":426},[431,21501,21502,21504,21506,21508,21510,21512,21514,21516,21519],{"class":433,"line":434},[431,21503,19577],{"class":441},[431,21505,1189],{"class":654},[431,21507,17401],{"class":441},[431,21509,762],{"class":437},[431,21511,4846],{"class":441},[431,21513,16889],{"class":437},[431,21515,4846],{"class":441},[431,21517,21518],{"class":437},"21",[431,21520,3568],{"class":441},[431,21522,21523,21525,21527,21529,21532,21535],{"class":433,"line":452},[431,21524,438],{"class":437},[431,21526,442],{"class":441},[431,21528,16889],{"class":437},[431,21530,21531],{"class":654}," in",[431,21533,21534],{"class":441}," numbers) ",[431,21536,8470],{"class":455},[431,21538,21539,21541,21543,21545,21547,21549],{"class":433,"line":578},[431,21540,438],{"class":437},[431,21542,442],{"class":441},[431,21544,856],{"class":437},[431,21546,21531],{"class":654},[431,21548,21534],{"class":441},[431,21550,8490],{"class":455},[632,21552,21554],{"id":21553},"управляющие-инструкции","Управляющие инструкции",[415,21556,21557],{},"В циклах Python доступны для использования две инструкции, влияющие на их поведение: break и continue.\nИх использование не является необходимым, но все же они встречаются на практике. Поэтому про них нужно знать.",[458,21559,21561],{"id":21560},"break","Break",[415,21563,21564],{},"Инструкция break производит выход из цикла. Не из функции, а из цикла.\nВстретив ее, интерпретатор перестает выполнять текущий цикл и переходит к инструкциям, идущим сразу за циклом.",[422,21566,21568],{"className":424,"code":21567,"language":396,"meta":426,"style":426},"coll = ['1', '2', '3', '4', 'stop', '6']\n\nfor item in coll:\n  if item == 'stop':\n    break\n  print(item)\n\n# => 1\n# => 2\n# => 3\n# => 4\n",[428,21569,21570,21608,21612,21622,21634,21639,21646,21650,21654,21658,21662],{"__ignoreMap":426},[431,21571,21572,21575,21577,21579,21582,21584,21587,21589,21592,21594,21597,21599,21601,21603,21606],{"class":433,"line":434},[431,21573,21574],{"class":441},"coll ",[431,21576,1189],{"class":654},[431,21578,17401],{"class":441},[431,21580,21581],{"class":445},"'1'",[431,21583,4846],{"class":441},[431,21585,21586],{"class":445},"'2'",[431,21588,4846],{"class":441},[431,21590,21591],{"class":445},"'3'",[431,21593,4846],{"class":441},[431,21595,21596],{"class":445},"'4'",[431,21598,4846],{"class":441},[431,21600,12098],{"class":445},[431,21602,4846],{"class":441},[431,21604,21605],{"class":445},"'6'",[431,21607,3568],{"class":441},[431,21609,21610],{"class":433,"line":452},[431,21611,1662],{"emptyLinePlaceholder":393},[431,21613,21614,21616,21618,21620],{"class":433,"line":578},[431,21615,14329],{"class":654},[431,21617,21014],{"class":441},[431,21619,14421],{"class":654},[431,21621,18697],{"class":441},[431,21623,21624,21626,21628,21630,21632],{"class":433,"line":584},[431,21625,20480],{"class":654},[431,21627,21014],{"class":441},[431,21629,8409],{"class":654},[431,21631,12019],{"class":445},[431,21633,8102],{"class":441},[431,21635,21636],{"class":433,"line":1244},[431,21637,21638],{"class":654},"    break\n",[431,21640,21641,21643],{"class":433,"line":1985},[431,21642,18530],{"class":437},[431,21644,21645],{"class":441},"(item)\n",[431,21647,21648],{"class":433,"line":2041},[431,21649,1662],{"emptyLinePlaceholder":393},[431,21651,21652],{"class":433,"line":4018},[431,21653,791],{"class":455},[431,21655,21656],{"class":433,"line":4030},[431,21657,3518],{"class":455},[431,21659,21660],{"class":433,"line":4419},[431,21661,4513],{"class":455},[431,21663,21664],{"class":433,"line":4436},[431,21665,18874],{"class":455},[415,21667,21668,21669,21677],{},"То же самое легко получить ",[1355,21670,21671,21672,21674,21675],{},"без ",[800,21673,21560],{},", используя цикл ",[800,21676,12737],{},".\nЭтот цикл семантически лучше подходит для такой задачи, так как подразумевает неполный перебор:",[422,21679,21681],{"className":424,"code":21680,"language":396,"meta":426,"style":426},"coll = ['1', '2', '3', '4', 'stop', '6']\n\ni = 0\nwhile coll[i] != 'stop':\n  print(coll[i])\n  i += 1\n\n# => 1\n# => 2\n# => 3\n# => 4\n",[428,21682,21683,21715,21719,21727,21740,21747,21755,21759,21763,21767,21771],{"__ignoreMap":426},[431,21684,21685,21687,21689,21691,21693,21695,21697,21699,21701,21703,21705,21707,21709,21711,21713],{"class":433,"line":434},[431,21686,21574],{"class":441},[431,21688,1189],{"class":654},[431,21690,17401],{"class":441},[431,21692,21581],{"class":445},[431,21694,4846],{"class":441},[431,21696,21586],{"class":445},[431,21698,4846],{"class":441},[431,21700,21591],{"class":445},[431,21702,4846],{"class":441},[431,21704,21596],{"class":445},[431,21706,4846],{"class":441},[431,21708,12098],{"class":445},[431,21710,4846],{"class":441},[431,21712,21605],{"class":445},[431,21714,3568],{"class":441},[431,21716,21717],{"class":433,"line":452},[431,21718,1662],{"emptyLinePlaceholder":393},[431,21720,21721,21723,21725],{"class":433,"line":578},[431,21722,3454],{"class":441},[431,21724,1189],{"class":654},[431,21726,3459],{"class":437},[431,21728,21729,21731,21734,21736,21738],{"class":433,"line":584},[431,21730,12737],{"class":654},[431,21732,21733],{"class":441}," coll[i] ",[431,21735,10686],{"class":654},[431,21737,12019],{"class":445},[431,21739,8102],{"class":441},[431,21741,21742,21744],{"class":433,"line":1244},[431,21743,18530],{"class":437},[431,21745,21746],{"class":441},"(coll[i])\n",[431,21748,21749,21751,21753],{"class":433,"line":1985},[431,21750,19548],{"class":441},[431,21752,12563],{"class":654},[431,21754,3916],{"class":437},[431,21756,21757],{"class":433,"line":2041},[431,21758,1662],{"emptyLinePlaceholder":393},[431,21760,21761],{"class":433,"line":4018},[431,21762,791],{"class":455},[431,21764,21765],{"class":433,"line":4030},[431,21766,3518],{"class":455},[431,21768,21769],{"class":433,"line":4419},[431,21770,4513],{"class":455},[431,21772,21773],{"class":433,"line":4436},[431,21774,18874],{"class":455},[415,21776,21777],{},"Цикл while идеален для ситуаций, когда количество итераций неизвестно заранее.\nНапример, при ожидании условия для выхода или при поиске простого числа — как в коде выше.\nЕсли условие в цикле while будет истинным, то цикл будет бесконечным.\nВажно помнить об этом и всегда проверять условие в таком цикле:",[422,21779,21781],{"className":424,"code":21780,"language":396,"meta":426,"style":426},"i = 0\n# Бесконечный цикл! Опасно запускать!\nwhile True:\n  print(i)\n  i += 1\n",[428,21782,21783,21791,21796,21804,21810],{"__ignoreMap":426},[431,21784,21785,21787,21789],{"class":433,"line":434},[431,21786,3454],{"class":441},[431,21788,1189],{"class":654},[431,21790,3459],{"class":437},[431,21792,21793],{"class":433,"line":452},[431,21794,21795],{"class":455},"# Бесконечный цикл! Опасно запускать!\n",[431,21797,21798,21800,21802],{"class":433,"line":578},[431,21799,12737],{"class":654},[431,21801,9395],{"class":437},[431,21803,8102],{"class":441},[431,21805,21806,21808],{"class":433,"line":584},[431,21807,18530],{"class":437},[431,21809,12677],{"class":441},[431,21811,21812,21814,21816],{"class":433,"line":1244},[431,21813,19548],{"class":441},[431,21815,12563],{"class":654},[431,21817,3916],{"class":437},[415,21819,21820,21821,21823,21824,21826,21827,21830,21831,21833],{},"Когда количество итераций известно, предпочтительнее использовать цикл ",[428,21822,14329],{},".\nВ отличие от ",[428,21825,12737],{},", цикл ",[428,21828,21829],{},"for in"," гарантированно остановится после перебора всех элементов, даже если условие ",[428,21832,21560],{}," не будет достигнуто:",[422,21835,21837],{"className":424,"code":21836,"language":396,"meta":426,"style":426},"coll = ['1', '2', '3', '4', '5']\nfor item in coll:\n  if False:\n    # Условие никогда не выполнится, но цикл все равно завершит работу\n    break\n  print(item)\n\n# => 1\n# => 2\n# => 3\n# => 4\n# => 5\n",[428,21838,21839,21868,21878,21886,21891,21895,21901,21905,21909,21913,21917,21921],{"__ignoreMap":426},[431,21840,21841,21843,21845,21847,21849,21851,21853,21855,21857,21859,21861,21863,21866],{"class":433,"line":434},[431,21842,21574],{"class":441},[431,21844,1189],{"class":654},[431,21846,17401],{"class":441},[431,21848,21581],{"class":445},[431,21850,4846],{"class":441},[431,21852,21586],{"class":445},[431,21854,4846],{"class":441},[431,21856,21591],{"class":445},[431,21858,4846],{"class":441},[431,21860,21596],{"class":445},[431,21862,4846],{"class":441},[431,21864,21865],{"class":445},"'5'",[431,21867,3568],{"class":441},[431,21869,21870,21872,21874,21876],{"class":433,"line":452},[431,21871,14329],{"class":654},[431,21873,21014],{"class":441},[431,21875,14421],{"class":654},[431,21877,18697],{"class":441},[431,21879,21880,21882,21884],{"class":433,"line":578},[431,21881,20480],{"class":654},[431,21883,9405],{"class":437},[431,21885,8102],{"class":441},[431,21887,21888],{"class":433,"line":584},[431,21889,21890],{"class":455},"    # Условие никогда не выполнится, но цикл все равно завершит работу\n",[431,21892,21893],{"class":433,"line":1244},[431,21894,21638],{"class":654},[431,21896,21897,21899],{"class":433,"line":1985},[431,21898,18530],{"class":437},[431,21900,21645],{"class":441},[431,21902,21903],{"class":433,"line":2041},[431,21904,1662],{"emptyLinePlaceholder":393},[431,21906,21907],{"class":433,"line":4018},[431,21908,791],{"class":455},[431,21910,21911],{"class":433,"line":4030},[431,21912,3518],{"class":455},[431,21914,21915],{"class":433,"line":4419},[431,21916,4513],{"class":455},[431,21918,21919],{"class":433,"line":4436},[431,21920,18874],{"class":455},[431,21922,21923],{"class":433,"line":4446},[431,21924,3531],{"class":455},[415,21926,21927,21928,3562],{},"Если же нам нужно совершить полезное действие, если условие в цикле ни разу не выполнилось, то на помощь придет инструкция ",[428,21929,10515],{},[422,21931,21933],{"className":424,"code":21932,"language":396,"meta":426,"style":426},"# Функция возвращает первое число большее, чем переданное, или None, если такого нет\ndef first_greater(coll, n):\n  for item in coll:\n    if item > n:\n      # Условие никогда не выполнится, но цикл все равно завершит работу\n      result = item\n      break\n  else:\n    result = None\n  return result\n\nfirst_greater([1, 15, 25], 10) # 15\nfirst_greater([1, 15, 25], 42) # None\n",[428,21934,21935,21940,21950,21960,21970,21975,21985,21990,21997,22005,22011,22015,22042],{"__ignoreMap":426},[431,21936,21937],{"class":433,"line":434},[431,21938,21939],{"class":455},"# Функция возвращает первое число большее, чем переданное, или None, если такого нет\n",[431,21941,21942,21944,21947],{"class":433,"line":452},[431,21943,6330],{"class":654},[431,21945,21946],{"class":6333}," first_greater",[431,21948,21949],{"class":441},"(coll, n):\n",[431,21951,21952,21954,21956,21958],{"class":433,"line":578},[431,21953,20523],{"class":654},[431,21955,21014],{"class":441},[431,21957,14421],{"class":654},[431,21959,18697],{"class":441},[431,21961,21962,21964,21966,21968],{"class":433,"line":584},[431,21963,10438],{"class":654},[431,21965,21014],{"class":441},[431,21967,8883],{"class":654},[431,21969,12545],{"class":441},[431,21971,21972],{"class":433,"line":1244},[431,21973,21974],{"class":455},"      # Условие никогда не выполнится, но цикл все равно завершит работу\n",[431,21976,21977,21980,21982],{"class":433,"line":1985},[431,21978,21979],{"class":441},"      result ",[431,21981,1189],{"class":654},[431,21983,21984],{"class":441}," item\n",[431,21986,21987],{"class":433,"line":2041},[431,21988,21989],{"class":654},"      break\n",[431,21991,21992,21995],{"class":433,"line":4018},[431,21993,21994],{"class":654},"  else",[431,21996,8102],{"class":441},[431,21998,21999,22001,22003],{"class":433,"line":4030},[431,22000,6796],{"class":441},[431,22002,1189],{"class":654},[431,22004,11872],{"class":437},[431,22006,22007,22009],{"class":433,"line":4419},[431,22008,20132],{"class":654},[431,22010,6812],{"class":441},[431,22012,22013],{"class":433,"line":4436},[431,22014,1662],{"emptyLinePlaceholder":393},[431,22016,22017,22020,22022,22024,22027,22029,22032,22035,22037,22039],{"class":433,"line":4446},[431,22018,22019],{"class":441},"first_greater([",[431,22021,1192],{"class":437},[431,22023,4846],{"class":441},[431,22025,22026],{"class":437},"15",[431,22028,4846],{"class":441},[431,22030,22031],{"class":437},"25",[431,22033,22034],{"class":441},"], ",[431,22036,3565],{"class":437},[431,22038,1014],{"class":441},[431,22040,22041],{"class":455},"# 15\n",[431,22043,22044,22046,22048,22050,22052,22054,22056,22058,22060,22062],{"class":433,"line":4451},[431,22045,22019],{"class":441},[431,22047,1192],{"class":437},[431,22049,4846],{"class":441},[431,22051,22026],{"class":437},[431,22053,4846],{"class":441},[431,22055,22031],{"class":437},[431,22057,22034],{"class":441},[431,22059,9731],{"class":437},[431,22061,1014],{"class":441},[431,22063,18195],{"class":455},[458,22065,22067],{"id":22066},"continue","Continue",[415,22069,22070,22071,22073,22074,22076,22077,22079],{},"Инструкция ",[428,22072,22066],{}," позволяет пропустить итерацию цикла.\nЕсли ",[428,22075,21560],{}," дает команду на прерывание, то ",[428,22078,22066],{}," действует более гибко.\nЕго функция заключается в пропуске определенных элементов последовательности, но без завершения цикла.\nДавайте напишем программу, которая «не любит» букву «А»:",[422,22081,22083],{"className":424,"code":22082,"language":396,"meta":426,"style":426},"word = input('Введите слово: ')\nfor i in word:\n    if i == 'а' or i == 'А':\n        continue\n    print(i)\n",[428,22084,22085,22101,22112,22134,22139],{"__ignoreMap":426},[431,22086,22087,22090,22092,22094,22096,22099],{"class":433,"line":434},[431,22088,22089],{"class":441},"word ",[431,22091,1189],{"class":654},[431,22093,11984],{"class":437},[431,22095,442],{"class":441},[431,22097,22098],{"class":445},"'Введите слово: '",[431,22100,449],{"class":441},[431,22102,22103,22105,22107,22109],{"class":433,"line":452},[431,22104,14329],{"class":654},[431,22106,12664],{"class":441},[431,22108,14421],{"class":654},[431,22110,22111],{"class":441}," word:\n",[431,22113,22114,22116,22118,22120,22123,22125,22127,22129,22132],{"class":433,"line":578},[431,22115,10438],{"class":654},[431,22117,12664],{"class":441},[431,22119,8409],{"class":654},[431,22121,22122],{"class":445}," 'а'",[431,22124,9111],{"class":654},[431,22126,12664],{"class":441},[431,22128,8409],{"class":654},[431,22130,22131],{"class":445}," 'А'",[431,22133,8102],{"class":441},[431,22135,22136],{"class":433,"line":584},[431,22137,22138],{"class":654},"        continue\n",[431,22140,22141,22143],{"class":433,"line":1244},[431,22142,6357],{"class":437},[431,22144,12677],{"class":441},[415,22146,22147],{},"Попробуйте ввести, например, «Автобус», в этом случае вывод будет таким:",[422,22149,22151],{"className":424,"code":22150,"language":396,"meta":426,"style":426},"в\nт\nо\nб\nу\nс\n",[428,22152,22153,22158,22163,22168,22173,22178],{"__ignoreMap":426},[431,22154,22155],{"class":433,"line":434},[431,22156,22157],{"class":441},"в\n",[431,22159,22160],{"class":433,"line":452},[431,22161,22162],{"class":441},"т\n",[431,22164,22165],{"class":433,"line":578},[431,22166,22167],{"class":441},"о\n",[431,22169,22170],{"class":433,"line":584},[431,22171,22172],{"class":441},"б\n",[431,22174,22175],{"class":433,"line":1244},[431,22176,22177],{"class":441},"у\n",[431,22179,22180],{"class":433,"line":1985},[431,22181,22182],{"class":441},"с\n",[458,22184,22186],{"id":22185},"pass","Pass",[415,22188,22189,22190,22192],{},"Назначение оператора ",[428,22191,22185],{}," — продолжение цикла независимо от наличия внешних условий.\nВ готовом коде pass встречается нечасто, но полезен в процессе разработки и применяется в качестве «заглушки» там, где код еще не написан.\nНапример, нам нужно не забыть добавить условие с буквой «а» из примера выше, но сам этот блок по какой-то причине мы пока не написали.\nЗдесь для корректной работы программы и поможет \"заглушка\" pass:",[422,22194,22196],{"className":424,"code":22195,"language":396,"meta":426,"style":426},"word = input('Введите слово: ')\nfor i in word:\n    if i == 'а' or i == 'А':\n        pass\nelse:\n    print('Цикл завершен, запрещенных букв не обнаружено')\nprint('Проверка завершена')\n",[428,22197,22198,22212,22222,22242,22247,22253,22264],{"__ignoreMap":426},[431,22199,22200,22202,22204,22206,22208,22210],{"class":433,"line":434},[431,22201,22089],{"class":441},[431,22203,1189],{"class":654},[431,22205,11984],{"class":437},[431,22207,442],{"class":441},[431,22209,22098],{"class":445},[431,22211,449],{"class":441},[431,22213,22214,22216,22218,22220],{"class":433,"line":452},[431,22215,14329],{"class":654},[431,22217,12664],{"class":441},[431,22219,14421],{"class":654},[431,22221,22111],{"class":441},[431,22223,22224,22226,22228,22230,22232,22234,22236,22238,22240],{"class":433,"line":578},[431,22225,10438],{"class":654},[431,22227,12664],{"class":441},[431,22229,8409],{"class":654},[431,22231,22122],{"class":445},[431,22233,9111],{"class":654},[431,22235,12664],{"class":441},[431,22237,8409],{"class":654},[431,22239,22131],{"class":445},[431,22241,8102],{"class":441},[431,22243,22244],{"class":433,"line":584},[431,22245,22246],{"class":654},"        pass\n",[431,22248,22249,22251],{"class":433,"line":1244},[431,22250,10515],{"class":654},[431,22252,8102],{"class":441},[431,22254,22255,22257,22259,22262],{"class":433,"line":1985},[431,22256,6357],{"class":437},[431,22258,442],{"class":441},[431,22260,22261],{"class":445},"'Цикл завершен, запрещенных букв не обнаружено'",[431,22263,449],{"class":441},[431,22265,22266,22268,22270,22273],{"class":433,"line":2041},[431,22267,438],{"class":437},[431,22269,442],{"class":441},[431,22271,22272],{"class":445},"'Проверка завершена'",[431,22274,449],{"class":441},[632,22276,22278],{"id":22277},"вложенные-списки","Вложенные списки",[415,22280,22281],{},"Значением списка может быть все что угодно, в том числе другой список. Создать список в списке можно так:",[422,22283,22285],{"className":424,"code":22284,"language":396,"meta":426,"style":426},"nested1 = [[3]]\nprint(len(nested1)) # => 1\nnested2 = [1, [3, 2], [3, [4]]]\nprint(len(nested2)) # => 3\n",[428,22286,22287,22302,22315,22347],{"__ignoreMap":426},[431,22288,22289,22292,22294,22297,22299],{"class":433,"line":434},[431,22290,22291],{"class":441},"nested1 ",[431,22293,1189],{"class":654},[431,22295,22296],{"class":441}," [[",[431,22298,971],{"class":437},[431,22300,22301],{"class":441},"]]\n",[431,22303,22304,22306,22308,22310,22313],{"class":433,"line":452},[431,22305,438],{"class":437},[431,22307,442],{"class":441},[431,22309,5205],{"class":437},[431,22311,22312],{"class":441},"(nested1)) ",[431,22314,791],{"class":455},[431,22316,22317,22320,22322,22324,22326,22329,22331,22333,22335,22338,22340,22342,22344],{"class":433,"line":578},[431,22318,22319],{"class":441},"nested2 ",[431,22321,1189],{"class":654},[431,22323,17401],{"class":441},[431,22325,1192],{"class":437},[431,22327,22328],{"class":441},", [",[431,22330,971],{"class":437},[431,22332,4846],{"class":441},[431,22334,651],{"class":437},[431,22336,22337],{"class":441},"], [",[431,22339,971],{"class":437},[431,22341,22328],{"class":441},[431,22343,762],{"class":437},[431,22345,22346],{"class":441},"]]]\n",[431,22348,22349,22351,22353,22355,22358],{"class":433,"line":584},[431,22350,438],{"class":437},[431,22352,442],{"class":441},[431,22354,5205],{"class":437},[431,22356,22357],{"class":441},"(nested2)) ",[431,22359,4513],{"class":455},[415,22361,22362],{},"Каждый элемент, являющийся списком, рассматривается как единое целое. Это видно по размеру второго списка.\nСинтаксис Python позволяет размещать элементы создаваемого списка построчно.\nПерепишем для наглядности создание второго списка:",[422,22364,22366],{"className":424,"code":22365,"language":396,"meta":426,"style":426},"data2 = [\n  1,        # первый элемент (число)\n  [3, 2],   # второй элемент (список)\n  [3, [4]], # третий элемент (список)\n]\nlen(data2) # 3\n",[428,22367,22368,22378,22389,22406,22422,22426],{"__ignoreMap":426},[431,22369,22370,22373,22375],{"class":433,"line":434},[431,22371,22372],{"class":441},"data2 ",[431,22374,1189],{"class":654},[431,22376,22377],{"class":441}," [\n",[431,22379,22380,22383,22386],{"class":433,"line":452},[431,22381,22382],{"class":437},"  1",[431,22384,22385],{"class":441},",        ",[431,22387,22388],{"class":455},"# первый элемент (число)\n",[431,22390,22391,22394,22396,22398,22400,22403],{"class":433,"line":578},[431,22392,22393],{"class":441},"  [",[431,22395,971],{"class":437},[431,22397,4846],{"class":441},[431,22399,651],{"class":437},[431,22401,22402],{"class":441},"],   ",[431,22404,22405],{"class":455},"# второй элемент (список)\n",[431,22407,22408,22410,22412,22414,22416,22419],{"class":433,"line":584},[431,22409,22393],{"class":441},[431,22411,971],{"class":437},[431,22413,22328],{"class":441},[431,22415,762],{"class":437},[431,22417,22418],{"class":441},"]], ",[431,22420,22421],{"class":455},"# третий элемент (список)\n",[431,22423,22424],{"class":433,"line":1244},[431,22425,3568],{"class":441},[431,22427,22428,22430,22433],{"class":433,"line":1985},[431,22429,5205],{"class":437},[431,22431,22432],{"class":441},"(data2) ",[431,22434,5340],{"class":455},[415,22436,22437],{},"Вложенность никак не ограничивается. Можно создавать список списков со списками внутри и так далее.\nОбращение ко вложенным спискам выглядит немного необычно, хотя и логично:",[422,22439,22441],{"className":424,"code":22440,"language":396,"meta":426,"style":426},"data1 = [[3]]\ndata1[0][0] # 3\ndata2 = [1, [3, 2], [3, [4]]]\ndata2[2][1][0] # 4\n",[428,22442,22443,22456,22472,22500],{"__ignoreMap":426},[431,22444,22445,22448,22450,22452,22454],{"class":433,"line":434},[431,22446,22447],{"class":441},"data1 ",[431,22449,1189],{"class":654},[431,22451,22296],{"class":441},[431,22453,971],{"class":437},[431,22455,22301],{"class":441},[431,22457,22458,22461,22463,22466,22468,22470],{"class":433,"line":452},[431,22459,22460],{"class":441},"data1[",[431,22462,3302],{"class":437},[431,22464,22465],{"class":441},"][",[431,22467,3302],{"class":437},[431,22469,4049],{"class":441},[431,22471,5340],{"class":455},[431,22473,22474,22476,22478,22480,22482,22484,22486,22488,22490,22492,22494,22496,22498],{"class":433,"line":578},[431,22475,22372],{"class":441},[431,22477,1189],{"class":654},[431,22479,17401],{"class":441},[431,22481,1192],{"class":437},[431,22483,22328],{"class":441},[431,22485,971],{"class":437},[431,22487,4846],{"class":441},[431,22489,651],{"class":437},[431,22491,22337],{"class":441},[431,22493,971],{"class":437},[431,22495,22328],{"class":441},[431,22497,762],{"class":437},[431,22499,22346],{"class":441},[431,22501,22502,22505,22507,22509,22511,22513,22515,22517],{"class":433,"line":584},[431,22503,22504],{"class":441},"data2[",[431,22506,651],{"class":437},[431,22508,22465],{"class":441},[431,22510,1192],{"class":437},[431,22512,22465],{"class":441},[431,22514,3302],{"class":437},[431,22516,4049],{"class":441},[431,22518,7774],{"class":455},[415,22520,22521],{},"Возможно, с непривычки вы не всегда сразу точно увидите, как добраться до нужного элемента, но это всего лишь вопрос тренировок:",[422,22523,22525],{"className":424,"code":22524,"language":396,"meta":426,"style":426},"data2 = [\n  1,\n  [3, 2],\n  [3, [4]],\n]\ndata2[2]       # [3, [4]]\ndata2[2][1]    # [4]\ndata2[2][1][0] # 4\n",[428,22526,22527,22535,22542,22555,22568,22572,22584,22600],{"__ignoreMap":426},[431,22528,22529,22531,22533],{"class":433,"line":434},[431,22530,22372],{"class":441},[431,22532,1189],{"class":654},[431,22534,22377],{"class":441},[431,22536,22537,22539],{"class":433,"line":452},[431,22538,22382],{"class":437},[431,22540,22541],{"class":441},",\n",[431,22543,22544,22546,22548,22550,22552],{"class":433,"line":578},[431,22545,22393],{"class":441},[431,22547,971],{"class":437},[431,22549,4846],{"class":441},[431,22551,651],{"class":437},[431,22553,22554],{"class":441},"],\n",[431,22556,22557,22559,22561,22563,22565],{"class":433,"line":584},[431,22558,22393],{"class":441},[431,22560,971],{"class":437},[431,22562,22328],{"class":441},[431,22564,762],{"class":437},[431,22566,22567],{"class":441},"]],\n",[431,22569,22570],{"class":433,"line":1244},[431,22571,3568],{"class":441},[431,22573,22574,22576,22578,22581],{"class":433,"line":1985},[431,22575,22504],{"class":441},[431,22577,651],{"class":437},[431,22579,22580],{"class":441},"]       ",[431,22582,22583],{"class":455},"# [3, [4]]\n",[431,22585,22586,22588,22590,22592,22594,22597],{"class":433,"line":2041},[431,22587,22504],{"class":441},[431,22589,651],{"class":437},[431,22591,22465],{"class":441},[431,22593,1192],{"class":437},[431,22595,22596],{"class":441},"]    ",[431,22598,22599],{"class":455},"# [4]\n",[431,22601,22602,22604,22606,22608,22610,22612,22614,22616],{"class":433,"line":4018},[431,22603,22504],{"class":441},[431,22605,651],{"class":437},[431,22607,22465],{"class":441},[431,22609,1192],{"class":437},[431,22611,22465],{"class":441},[431,22613,3302],{"class":437},[431,22615,4049],{"class":441},[431,22617,7774],{"class":455},[415,22619,22620],{},"Изменение и добавление списков в список:",[422,22622,22624],{"className":424,"code":22623,"language":396,"meta":426,"style":426},"data1 = [[3]]\ndata1[0] = [2, 10]\ndata1.append([3, 4, 5]) # [[2, 10], [3, 4, 5]]\n",[428,22625,22626,22638,22658],{"__ignoreMap":426},[431,22627,22628,22630,22632,22634,22636],{"class":433,"line":434},[431,22629,22447],{"class":441},[431,22631,1189],{"class":654},[431,22633,22296],{"class":441},[431,22635,971],{"class":437},[431,22637,22301],{"class":441},[431,22639,22640,22642,22644,22646,22648,22650,22652,22654,22656],{"class":433,"line":452},[431,22641,22460],{"class":441},[431,22643,3302],{"class":437},[431,22645,4049],{"class":441},[431,22647,1189],{"class":654},[431,22649,17401],{"class":441},[431,22651,651],{"class":437},[431,22653,4846],{"class":441},[431,22655,3565],{"class":437},[431,22657,3568],{"class":441},[431,22659,22660,22663,22665,22667,22669,22671,22673,22675],{"class":433,"line":578},[431,22661,22662],{"class":441},"data1.append([",[431,22664,971],{"class":437},[431,22666,4846],{"class":441},[431,22668,762],{"class":437},[431,22670,4846],{"class":441},[431,22672,856],{"class":437},[431,22674,18021],{"class":441},[431,22676,22677],{"class":455},"# [[2, 10], [3, 4, 5]]\n",[415,22679,22680],{},"Вложенные списки можно изменять напрямую, просто обратившись к нужному элементу:",[422,22682,22684],{"className":424,"code":22683,"language":396,"meta":426,"style":426},"data1 = [[3]]\ndata1[0][0] = 5 # [[5]]\n",[428,22685,22686,22698],{"__ignoreMap":426},[431,22687,22688,22690,22692,22694,22696],{"class":433,"line":434},[431,22689,22447],{"class":441},[431,22691,1189],{"class":654},[431,22693,22296],{"class":441},[431,22695,971],{"class":437},[431,22697,22301],{"class":441},[431,22699,22700,22702,22704,22706,22708,22710,22712,22714],{"class":433,"line":452},[431,22701,22460],{"class":441},[431,22703,3302],{"class":437},[431,22705,22465],{"class":441},[431,22707,3302],{"class":437},[431,22709,4049],{"class":441},[431,22711,1189],{"class":654},[431,22713,910],{"class":437},[431,22715,22716],{"class":455}," # [[5]]\n",[415,22718,22719],{},"То же самое касается и добавления нового элемента:",[422,22721,22723],{"className":424,"code":22722,"language":396,"meta":426,"style":426},"data1 = [[3]]\ndata1[0].append(10) # [[3, 10]]\n",[428,22724,22725,22737],{"__ignoreMap":426},[431,22726,22727,22729,22731,22733,22735],{"class":433,"line":434},[431,22728,22447],{"class":441},[431,22730,1189],{"class":654},[431,22732,22296],{"class":441},[431,22734,971],{"class":437},[431,22736,22301],{"class":441},[431,22738,22739,22741,22743,22746,22748,22750],{"class":433,"line":452},[431,22740,22460],{"class":441},[431,22742,3302],{"class":437},[431,22744,22745],{"class":441},"].append(",[431,22747,3565],{"class":437},[431,22749,1014],{"class":441},[431,22751,22752],{"class":455},"# [[3, 10]]\n",[415,22754,22755],{},"Для чего же могут понадобиться вложенные списки?\nТаких примеров довольно много: начиная от математических концепций, например, матриц, заканчивая представлением игровых полей.\nПомните игру крестики-нолики? Это как раз тот самый случай.\nРазберем такую задачку: дано игровое поле для крестиков-ноликов.\nНужно написать функцию, которая проверяет, есть ли на этом поле хотя бы один крестик или нолик, в зависимости от того, что попросят проверить.",[422,22757,22759],{"className":424,"code":22758,"language":396,"meta":426,"style":426},"# Инициализируем поле\nfield = [\n  [None, None, None],\n  [None, None, None],\n  [None, None, None],\n]\n\n# Делаем ход:\nfield[1][2] = 'x'\n# [\n#     [None, None, None],\n#     [None, None, 'x'],\n#     [None, None, None],\n# ]\n",[428,22760,22761,22766,22775,22791,22807,22823,22827,22831,22836,22854,22859,22864,22869,22873],{"__ignoreMap":426},[431,22762,22763],{"class":433,"line":434},[431,22764,22765],{"class":455},"# Инициализируем поле\n",[431,22767,22768,22771,22773],{"class":433,"line":452},[431,22769,22770],{"class":441},"field ",[431,22772,1189],{"class":654},[431,22774,22377],{"class":441},[431,22776,22777,22779,22781,22783,22785,22787,22789],{"class":433,"line":578},[431,22778,22393],{"class":441},[431,22780,7922],{"class":437},[431,22782,4846],{"class":441},[431,22784,7922],{"class":437},[431,22786,4846],{"class":441},[431,22788,7922],{"class":437},[431,22790,22554],{"class":441},[431,22792,22793,22795,22797,22799,22801,22803,22805],{"class":433,"line":584},[431,22794,22393],{"class":441},[431,22796,7922],{"class":437},[431,22798,4846],{"class":441},[431,22800,7922],{"class":437},[431,22802,4846],{"class":441},[431,22804,7922],{"class":437},[431,22806,22554],{"class":441},[431,22808,22809,22811,22813,22815,22817,22819,22821],{"class":433,"line":1244},[431,22810,22393],{"class":441},[431,22812,7922],{"class":437},[431,22814,4846],{"class":441},[431,22816,7922],{"class":437},[431,22818,4846],{"class":441},[431,22820,7922],{"class":437},[431,22822,22554],{"class":441},[431,22824,22825],{"class":433,"line":1985},[431,22826,3568],{"class":441},[431,22828,22829],{"class":433,"line":2041},[431,22830,1662],{"emptyLinePlaceholder":393},[431,22832,22833],{"class":433,"line":4018},[431,22834,22835],{"class":455},"# Делаем ход:\n",[431,22837,22838,22841,22843,22845,22847,22849,22851],{"class":433,"line":4030},[431,22839,22840],{"class":441},"field[",[431,22842,1192],{"class":437},[431,22844,22465],{"class":441},[431,22846,651],{"class":437},[431,22848,4049],{"class":441},[431,22850,1189],{"class":654},[431,22852,22853],{"class":445}," 'x'\n",[431,22855,22856],{"class":433,"line":4419},[431,22857,22858],{"class":455},"# [\n",[431,22860,22861],{"class":433,"line":4436},[431,22862,22863],{"class":455},"#     [None, None, None],\n",[431,22865,22866],{"class":433,"line":4446},[431,22867,22868],{"class":455},"#     [None, None, 'x'],\n",[431,22870,22871],{"class":433,"line":4451},[431,22872,22863],{"class":455},[431,22874,22875],{"class":433,"line":4086},[431,22876,22877],{"class":455},"# ]\n",[415,22879,22880],{},"Теперь реализуем функцию, которая выполняет проверку:",[422,22882,22884],{"className":424,"code":22883,"language":396,"meta":426,"style":426},"def has_player_move(field, symbol):\n  # Обходим поле. Каждый элемент — это строчка в игровом поле.\n  for row in field:\n    # оператор in проверяет присутствует ли элемент в списке,\n    if symbol in row: # Если присутствует, значит мы нашли то, что искали.\n      return True\n  # Если поле было просмотрено, но ничего не нашли,\n  # значит ходов не было.\n  return False\n",[428,22885,22886,22896,22901,22913,22918,22932,22939,22944,22949],{"__ignoreMap":426},[431,22887,22888,22890,22893],{"class":433,"line":434},[431,22889,6330],{"class":654},[431,22891,22892],{"class":6333}," has_player_move",[431,22894,22895],{"class":441},"(field, symbol):\n",[431,22897,22898],{"class":433,"line":452},[431,22899,22900],{"class":455},"  # Обходим поле. Каждый элемент — это строчка в игровом поле.\n",[431,22902,22903,22905,22908,22910],{"class":433,"line":578},[431,22904,20523],{"class":654},[431,22906,22907],{"class":441}," row ",[431,22909,14421],{"class":654},[431,22911,22912],{"class":441}," field:\n",[431,22914,22915],{"class":433,"line":584},[431,22916,22917],{"class":455},"    # оператор in проверяет присутствует ли элемент в списке,\n",[431,22919,22920,22922,22924,22926,22929],{"class":433,"line":1244},[431,22921,10438],{"class":654},[431,22923,14670],{"class":441},[431,22925,14421],{"class":654},[431,22927,22928],{"class":441}," row: ",[431,22930,22931],{"class":455},"# Если присутствует, значит мы нашли то, что искали.\n",[431,22933,22934,22937],{"class":433,"line":1985},[431,22935,22936],{"class":654},"      return",[431,22938,10188],{"class":437},[431,22940,22941],{"class":433,"line":2041},[431,22942,22943],{"class":455},"  # Если поле было просмотрено, но ничего не нашли,\n",[431,22945,22946],{"class":433,"line":4018},[431,22947,22948],{"class":455},"  # значит ходов не было.\n",[431,22950,22951,22953],{"class":433,"line":4030},[431,22952,20132],{"class":654},[431,22954,14187],{"class":437},[415,22956,22957],{},"Проверим:",[422,22959,22961],{"className":424,"code":22960,"language":396,"meta":426,"style":426},"print(has_player_move(field, 'x'))  # True\n",[428,22962,22963],{"__ignoreMap":426},[431,22964,22965,22967,22970,22973,22975],{"class":433,"line":434},[431,22966,438],{"class":437},[431,22968,22969],{"class":441},"(has_player_move(field, ",[431,22971,22972],{"class":445},"'x'",[431,22974,986],{"class":441},[431,22976,19945],{"class":455},[415,22978,1849,22979,1853,22981,1857],{},[800,22980,1852],{},[800,22982,1856],{},[1859,22984],{},[1862,22986,22987],{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":426,"searchDepth":452,"depth":1244,"links":22989},[22990],{"id":21150,"depth":452,"text":214,"children":22991},[22992,23000,23005],{"id":21153,"depth":578,"text":21154,"children":22993},[22994],{"id":21174,"depth":584,"text":21175,"children":22995},[22996,22997,22998,22999],{"id":21184,"depth":1244,"text":21185},{"id":21307,"depth":1244,"text":21308},{"id":21400,"depth":1244,"text":21401},{"id":21488,"depth":1244,"text":21489},{"id":21553,"depth":578,"text":21554,"children":23001},[23002,23003,23004],{"id":21560,"depth":584,"text":21561},{"id":22066,"depth":584,"text":22067},{"id":22185,"depth":584,"text":22186},{"id":22277,"depth":578,"text":22278},"2025-03-29","Списки как множества. Управляющие конструкции. Вложенные списки","images\u002Fblog\u002Fpython\u002Fst15\u002Fimg.png",{},{"title":214,"description":23007},"AEb325_e4FUDEV0s2LJy8CPLseVd_6wVXAD0glbF7LU",{"id":23013,"title":218,"author":23014,"body":23016,"date":24266,"description":24267,"extension":1887,"image":24268,"meta":24269,"minRead":4451,"navigation":393,"num":4482,"path":219,"seo":24270,"stem":220,"__hash__":24271},"python\u002Fblog\u002Fpython\u002Fst16.md",{"name":402,"avatar":23015},{"src":404,"alt":405},{"type":407,"value":23017,"toc":24259},[23018,23021,23025,23028,23065,23068,23079,23212,23219,23329,23332,23340,23343,23396,23399,23472,23475,23478,23609,23612,23746,23750,23753,23756,23778,23781,23792,23799,23848,23851,23949,23953,23956,24093,24096,24099,24248,24254,24256],[410,23019,218],{"id":23020},"использование-списков-ч2",[632,23022,23024],{"id":23023},"генерация-строки-в-цикле","Генерация строки в цикле",[415,23026,23027],{},"Генерация строк в циклах — задача, часто возникающая на практике.\nТипичный пример — функция, помогающая генерировать HTML-списки.\nОна принимает на вход коллекцию элементов и возвращает HTML-список из них:",[422,23029,23031],{"className":424,"code":23030,"language":396,"meta":426,"style":426},"coll = ['milk', 'butter']\n\nbuild_HTML_list(coll)\n# \u003Cul>\u003Cli>milk\u003C\u002Fli>\u003Cli>butter\u003C\u002Fli>\u003C\u002Ful>\n",[428,23032,23033,23051,23055,23060],{"__ignoreMap":426},[431,23034,23035,23037,23039,23041,23044,23046,23049],{"class":433,"line":434},[431,23036,21574],{"class":441},[431,23038,1189],{"class":654},[431,23040,17401],{"class":441},[431,23042,23043],{"class":445},"'milk'",[431,23045,4846],{"class":441},[431,23047,23048],{"class":445},"'butter'",[431,23050,3568],{"class":441},[431,23052,23053],{"class":433,"line":452},[431,23054,1662],{"emptyLinePlaceholder":393},[431,23056,23057],{"class":433,"line":578},[431,23058,23059],{"class":441},"build_HTML_list(coll)\n",[431,23061,23062],{"class":433,"line":584},[431,23063,23064],{"class":455},"# \u003Cul>\u003Cli>milk\u003C\u002Fli>\u003Cli>butter\u003C\u002Fli>\u003C\u002Ful>\n",[415,23066,23067],{},"Как можно решить эту задачу в лоб:",[1588,23069,23070,23073,23076],{},[700,23071,23072],{},"Создать переменную result и записать в нее \u003Cul>.",[700,23074,23075],{},"Пройтись циклом по элементам коллекции и дописать в результирующую строку очередной элемент \u003Cli>.",[700,23077,23078],{},"Добавить в конце \u003C\u002Ful> и вернуть result из функции.",[422,23080,23082],{"className":424,"code":23081,"language":396,"meta":426,"style":426},"def build_HTML_list(coll):\n  result = '\u003Cul>'\n  for item in coll:\n    result = f'{result}\u003Cli>{item}\u003C\u002Fli>'\n    # либо так: result += '\u003Cli>{item}\u003C\u002Fli>'\n  result = f'{result}\u003C\u002Ful>'\n\n  return result\n\ncoll = ['milk', 'butter']\n\nprint(build_HTML_list(coll))\n# => \u003Cul>\u003Cli>milk\u003C\u002Fli>\u003Cli>butter\u003C\u002Fli>\u003C\u002Ful>\n",[428,23083,23084,23093,23103,23113,23142,23147,23166,23170,23176,23180,23196,23200,23207],{"__ignoreMap":426},[431,23085,23086,23088,23091],{"class":433,"line":434},[431,23087,6330],{"class":654},[431,23089,23090],{"class":6333}," build_HTML_list",[431,23092,18678],{"class":441},[431,23094,23095,23098,23100],{"class":433,"line":452},[431,23096,23097],{"class":441},"  result ",[431,23099,1189],{"class":654},[431,23101,23102],{"class":445}," '\u003Cul>'\n",[431,23104,23105,23107,23109,23111],{"class":433,"line":578},[431,23106,20523],{"class":654},[431,23108,21014],{"class":441},[431,23110,14421],{"class":654},[431,23112,18697],{"class":441},[431,23114,23115,23117,23119,23121,23123,23125,23127,23129,23132,23134,23137,23139],{"class":433,"line":584},[431,23116,6796],{"class":441},[431,23118,1189],{"class":654},[431,23120,3058],{"class":654},[431,23122,2993],{"class":445},[431,23124,2996],{"class":437},[431,23126,8177],{"class":441},[431,23128,3002],{"class":437},[431,23130,23131],{"class":445},"\u003Cli>",[431,23133,2996],{"class":437},[431,23135,23136],{"class":441},"item",[431,23138,3002],{"class":437},[431,23140,23141],{"class":445},"\u003C\u002Fli>'\n",[431,23143,23144],{"class":433,"line":1244},[431,23145,23146],{"class":455},"    # либо так: result += '\u003Cli>{item}\u003C\u002Fli>'\n",[431,23148,23149,23151,23153,23155,23157,23159,23161,23163],{"class":433,"line":1985},[431,23150,23097],{"class":441},[431,23152,1189],{"class":654},[431,23154,3058],{"class":654},[431,23156,2993],{"class":445},[431,23158,2996],{"class":437},[431,23160,8177],{"class":441},[431,23162,3002],{"class":437},[431,23164,23165],{"class":445},"\u003C\u002Ful>'\n",[431,23167,23168],{"class":433,"line":2041},[431,23169,1662],{"emptyLinePlaceholder":393},[431,23171,23172,23174],{"class":433,"line":4018},[431,23173,20132],{"class":654},[431,23175,6812],{"class":441},[431,23177,23178],{"class":433,"line":4030},[431,23179,1662],{"emptyLinePlaceholder":393},[431,23181,23182,23184,23186,23188,23190,23192,23194],{"class":433,"line":4419},[431,23183,21574],{"class":441},[431,23185,1189],{"class":654},[431,23187,17401],{"class":441},[431,23189,23043],{"class":445},[431,23191,4846],{"class":441},[431,23193,23048],{"class":445},[431,23195,3568],{"class":441},[431,23197,23198],{"class":433,"line":4436},[431,23199,1662],{"emptyLinePlaceholder":393},[431,23201,23202,23204],{"class":433,"line":4446},[431,23203,438],{"class":437},[431,23205,23206],{"class":441},"(build_HTML_list(coll))\n",[431,23208,23209],{"class":433,"line":4451},[431,23210,23211],{"class":455},"# => \u003Cul>\u003Cli>milk\u003C\u002Fli>\u003Cli>butter\u003C\u002Fli>\u003C\u002Ful>\n",[415,23213,23214,23215,23218],{},"Такой способ вполне рабочий, но для большинства языков программирования максимально неэффективный.\nДело в том, что конкатенация и интерполяция порождают новую строчку вместо старой.\nПодобная ситуация повторяется на каждой итерации. Причем строка становится все больше и больше.\nКопирование строк приводит к серьезному расходу памяти и может влиять на производительность.\nКонечно, для большинства приложений данная проблема неактуальна из-за малого объема прогоняемых данных, но более эффективный подход не сложнее в реализации и обладает рядом плюсов.\nПоэтому стоит сразу приучить себя работать правильно.\nПравильно, в случае с динамическими языками – формировать список, который затем с помощью метода ",[428,23216,23217],{},"join()"," можно превратить в строку:",[422,23220,23222],{"className":424,"code":23221,"language":396,"meta":426,"style":426},"def build_HTML_list(coll):\n  parts = []\n  for item in coll:\n    parts.append(f'\u003Cli>{item}\u003C\u002Fli>')\n\n  # Метод join объединяет элементы списка в строку\n  # В качестве разделителя между значениями\n  # используется значение строки\n  inner_value = ''.join(parts)\n  result = f'\u003Cul>{inner_value}\u003C\u002Ful>'\n  return result\n",[428,23223,23224,23232,23241,23251,23272,23276,23281,23286,23291,23303,23323],{"__ignoreMap":426},[431,23225,23226,23228,23230],{"class":433,"line":434},[431,23227,6330],{"class":654},[431,23229,23090],{"class":6333},[431,23231,18678],{"class":441},[431,23233,23234,23237,23239],{"class":433,"line":452},[431,23235,23236],{"class":441},"  parts ",[431,23238,1189],{"class":654},[431,23240,21007],{"class":441},[431,23242,23243,23245,23247,23249],{"class":433,"line":578},[431,23244,20523],{"class":654},[431,23246,21014],{"class":441},[431,23248,14421],{"class":654},[431,23250,18697],{"class":441},[431,23252,23253,23256,23258,23261,23263,23265,23267,23270],{"class":433,"line":584},[431,23254,23255],{"class":441},"    parts.append(",[431,23257,2990],{"class":654},[431,23259,23260],{"class":445},"'\u003Cli>",[431,23262,2996],{"class":437},[431,23264,23136],{"class":441},[431,23266,3002],{"class":437},[431,23268,23269],{"class":445},"\u003C\u002Fli>'",[431,23271,449],{"class":441},[431,23273,23274],{"class":433,"line":1244},[431,23275,1662],{"emptyLinePlaceholder":393},[431,23277,23278],{"class":433,"line":1985},[431,23279,23280],{"class":455},"  # Метод join объединяет элементы списка в строку\n",[431,23282,23283],{"class":433,"line":2041},[431,23284,23285],{"class":455},"  # В качестве разделителя между значениями\n",[431,23287,23288],{"class":433,"line":4018},[431,23289,23290],{"class":455},"  # используется значение строки\n",[431,23292,23293,23296,23298,23300],{"class":433,"line":4030},[431,23294,23295],{"class":441},"  inner_value ",[431,23297,1189],{"class":654},[431,23299,9644],{"class":445},[431,23301,23302],{"class":441},".join(parts)\n",[431,23304,23305,23307,23309,23311,23314,23316,23319,23321],{"class":433,"line":4419},[431,23306,23097],{"class":441},[431,23308,1189],{"class":654},[431,23310,3058],{"class":654},[431,23312,23313],{"class":445},"'\u003Cul>",[431,23315,2996],{"class":437},[431,23317,23318],{"class":441},"inner_value",[431,23320,3002],{"class":437},[431,23322,23165],{"class":445},[431,23324,23325,23327],{"class":433,"line":4436},[431,23326,20132],{"class":654},[431,23328,6812],{"class":441},[415,23330,23331],{},"Размер кода практически не изменился, но способ формирования результата стал другим.\nВместо строки, сначала собирается список, который затем превращается в строку с помощью метода .join().\nУ такого подхода есть и дополнительные плюсы:2222",[697,23333,23334,23337],{},[700,23335,23336],{},"Такой код проще отлаживать.",[700,23338,23339],{},"Данные, представленные списком, легче вычленять визуально и программно.",[415,23341,23342],{},"Список — это структура, с ним можно производить дополнительные манипуляции. С готовой строкой уже ничего особо не сделать.\nРегулируя разделитель, строки можно объединять разными способами. Например, через запятую с пробелом:",[422,23344,23346],{"className":424,"code":23345,"language":396,"meta":426,"style":426},"parts = ['python', 'PHP', 'Python']\noutput = ', '.join(parts)\n\nprint(output) # => python, PHP, Python\n",[428,23347,23348,23370,23382,23386],{"__ignoreMap":426},[431,23349,23350,23353,23355,23357,23359,23361,23364,23366,23368],{"class":433,"line":434},[431,23351,23352],{"class":441},"parts ",[431,23354,1189],{"class":654},[431,23356,17401],{"class":441},[431,23358,7113],{"class":445},[431,23360,4846],{"class":441},[431,23362,23363],{"class":445},"'PHP'",[431,23365,4846],{"class":441},[431,23367,1304],{"class":445},[431,23369,3568],{"class":441},[431,23371,23372,23375,23377,23380],{"class":433,"line":452},[431,23373,23374],{"class":441},"output ",[431,23376,1189],{"class":654},[431,23378,23379],{"class":445}," ', '",[431,23381,23302],{"class":441},[431,23383,23384],{"class":433,"line":578},[431,23385,1662],{"emptyLinePlaceholder":393},[431,23387,23388,23390,23393],{"class":433,"line":584},[431,23389,438],{"class":437},[431,23391,23392],{"class":441},"(output) ",[431,23394,23395],{"class":455},"# => python, PHP, Python\n",[415,23397,23398],{},"Если каждое слово надо вывести на новой строчке, то в качестве разделителя используем символ перевода строки '\\n':",[422,23400,23402],{"className":424,"code":23401,"language":396,"meta":426,"style":426},"parts = ['python', 'PHP', 'Python']\n\n# Теперь каждое слово будет начинаться с новой строки\noutput = '\\n'.join(parts)\n\nprint(output)\n# => python\n# => PHP\n# => Python\n",[428,23403,23404,23424,23428,23433,23447,23451,23458,23463,23468],{"__ignoreMap":426},[431,23405,23406,23408,23410,23412,23414,23416,23418,23420,23422],{"class":433,"line":434},[431,23407,23352],{"class":441},[431,23409,1189],{"class":654},[431,23411,17401],{"class":441},[431,23413,7113],{"class":445},[431,23415,4846],{"class":441},[431,23417,23363],{"class":445},[431,23419,4846],{"class":441},[431,23421,1304],{"class":445},[431,23423,3568],{"class":441},[431,23425,23426],{"class":433,"line":452},[431,23427,1662],{"emptyLinePlaceholder":393},[431,23429,23430],{"class":433,"line":578},[431,23431,23432],{"class":455},"# Теперь каждое слово будет начинаться с новой строки\n",[431,23434,23435,23437,23439,23441,23443,23445],{"class":433,"line":584},[431,23436,23374],{"class":441},[431,23438,1189],{"class":654},[431,23440,3379],{"class":445},[431,23442,1540],{"class":437},[431,23444,2993],{"class":445},[431,23446,23302],{"class":441},[431,23448,23449],{"class":433,"line":1244},[431,23450,1662],{"emptyLinePlaceholder":393},[431,23452,23453,23455],{"class":433,"line":1985},[431,23454,438],{"class":437},[431,23456,23457],{"class":441},"(output)\n",[431,23459,23460],{"class":433,"line":2041},[431,23461,23462],{"class":455},"# => python\n",[431,23464,23465],{"class":433,"line":4018},[431,23466,23467],{"class":455},"# => PHP\n",[431,23469,23470],{"class":433,"line":4030},[431,23471,1770],{"class":455},[415,23473,23474],{},"Последний пример особенно важен.\nНовички часто допускают ошибку и добавляют перевод строки в момент формирования списка, а не в join().\nПосмотрите на пример с нашей функцией build_HTML_list().",[415,23476,23477],{},"Правильно:",[422,23479,23481],{"className":424,"code":23480,"language":396,"meta":426,"style":426},"def build_HTML_list(coll):\n  parts = []\n  for item in coll:\n    parts.append(f'\u003Cli>{item}\u003C\u002Fli>')\n  inner_value = '\\n'.join(parts) # перевод строки\n  result = f'\u003Cul>{inner_value}\u003C\u002Ful>'\n  return result\n\ncoll = ['milk', 'butter']\n\nprint(build_HTML_list(coll))\n# \u003Cul>\u003Cli>milk\u003C\u002Fli>\n# \u003Cli>butter\u003C\u002Fli>\u003C\u002Ful>\n",[428,23482,23483,23491,23499,23509,23527,23545,23563,23569,23573,23589,23593,23599,23604],{"__ignoreMap":426},[431,23484,23485,23487,23489],{"class":433,"line":434},[431,23486,6330],{"class":654},[431,23488,23090],{"class":6333},[431,23490,18678],{"class":441},[431,23492,23493,23495,23497],{"class":433,"line":452},[431,23494,23236],{"class":441},[431,23496,1189],{"class":654},[431,23498,21007],{"class":441},[431,23500,23501,23503,23505,23507],{"class":433,"line":578},[431,23502,20523],{"class":654},[431,23504,21014],{"class":441},[431,23506,14421],{"class":654},[431,23508,18697],{"class":441},[431,23510,23511,23513,23515,23517,23519,23521,23523,23525],{"class":433,"line":584},[431,23512,23255],{"class":441},[431,23514,2990],{"class":654},[431,23516,23260],{"class":445},[431,23518,2996],{"class":437},[431,23520,23136],{"class":441},[431,23522,3002],{"class":437},[431,23524,23269],{"class":445},[431,23526,449],{"class":441},[431,23528,23529,23531,23533,23535,23537,23539,23542],{"class":433,"line":1244},[431,23530,23295],{"class":441},[431,23532,1189],{"class":654},[431,23534,3379],{"class":445},[431,23536,1540],{"class":437},[431,23538,2993],{"class":445},[431,23540,23541],{"class":441},".join(parts) ",[431,23543,23544],{"class":455},"# перевод строки\n",[431,23546,23547,23549,23551,23553,23555,23557,23559,23561],{"class":433,"line":1985},[431,23548,23097],{"class":441},[431,23550,1189],{"class":654},[431,23552,3058],{"class":654},[431,23554,23313],{"class":445},[431,23556,2996],{"class":437},[431,23558,23318],{"class":441},[431,23560,3002],{"class":437},[431,23562,23165],{"class":445},[431,23564,23565,23567],{"class":433,"line":2041},[431,23566,20132],{"class":654},[431,23568,6812],{"class":441},[431,23570,23571],{"class":433,"line":4018},[431,23572,1662],{"emptyLinePlaceholder":393},[431,23574,23575,23577,23579,23581,23583,23585,23587],{"class":433,"line":4030},[431,23576,21574],{"class":441},[431,23578,1189],{"class":654},[431,23580,17401],{"class":441},[431,23582,23043],{"class":445},[431,23584,4846],{"class":441},[431,23586,23048],{"class":445},[431,23588,3568],{"class":441},[431,23590,23591],{"class":433,"line":4419},[431,23592,1662],{"emptyLinePlaceholder":393},[431,23594,23595,23597],{"class":433,"line":4436},[431,23596,438],{"class":437},[431,23598,23206],{"class":441},[431,23600,23601],{"class":433,"line":4446},[431,23602,23603],{"class":455},"# \u003Cul>\u003Cli>milk\u003C\u002Fli>\n",[431,23605,23606],{"class":433,"line":4451},[431,23607,23608],{"class":455},"# \u003Cli>butter\u003C\u002Fli>\u003C\u002Ful>\n",[415,23610,23611],{},"Неправильно:",[422,23613,23615],{"className":424,"code":23614,"language":396,"meta":426,"style":426},"def build_HTML_list(coll):\n  parts = []\n  for item in coll:\n    parts.append(f'\\n\u003Cli>{item}\u003C\u002Fli>')\n  inner_value = ''.join(parts) # разделителя нет\n  result = f'\u003Cul>{inner_value}\u003C\u002Ful>'\n  return result\n\ncoll = ['milk', 'butter']\n\nprint(build_HTML_list(coll))\n# \u003Cul>\n# \u003Cli>milk\u003C\u002Fli>\n# \u003Cli>butter\u003C\u002Fli>\u003C\u002Ful>\n",[428,23616,23617,23625,23633,23643,23665,23678,23696,23702,23706,23722,23726,23732,23737,23742],{"__ignoreMap":426},[431,23618,23619,23621,23623],{"class":433,"line":434},[431,23620,6330],{"class":654},[431,23622,23090],{"class":6333},[431,23624,18678],{"class":441},[431,23626,23627,23629,23631],{"class":433,"line":452},[431,23628,23236],{"class":441},[431,23630,1189],{"class":654},[431,23632,21007],{"class":441},[431,23634,23635,23637,23639,23641],{"class":433,"line":578},[431,23636,20523],{"class":654},[431,23638,21014],{"class":441},[431,23640,14421],{"class":654},[431,23642,18697],{"class":441},[431,23644,23645,23647,23649,23651,23653,23655,23657,23659,23661,23663],{"class":433,"line":584},[431,23646,23255],{"class":441},[431,23648,2990],{"class":654},[431,23650,2993],{"class":445},[431,23652,1540],{"class":437},[431,23654,23131],{"class":445},[431,23656,2996],{"class":437},[431,23658,23136],{"class":441},[431,23660,3002],{"class":437},[431,23662,23269],{"class":445},[431,23664,449],{"class":441},[431,23666,23667,23669,23671,23673,23675],{"class":433,"line":1244},[431,23668,23295],{"class":441},[431,23670,1189],{"class":654},[431,23672,9644],{"class":445},[431,23674,23541],{"class":441},[431,23676,23677],{"class":455},"# разделителя нет\n",[431,23679,23680,23682,23684,23686,23688,23690,23692,23694],{"class":433,"line":1985},[431,23681,23097],{"class":441},[431,23683,1189],{"class":654},[431,23685,3058],{"class":654},[431,23687,23313],{"class":445},[431,23689,2996],{"class":437},[431,23691,23318],{"class":441},[431,23693,3002],{"class":437},[431,23695,23165],{"class":445},[431,23697,23698,23700],{"class":433,"line":2041},[431,23699,20132],{"class":654},[431,23701,6812],{"class":441},[431,23703,23704],{"class":433,"line":4018},[431,23705,1662],{"emptyLinePlaceholder":393},[431,23707,23708,23710,23712,23714,23716,23718,23720],{"class":433,"line":4030},[431,23709,21574],{"class":441},[431,23711,1189],{"class":654},[431,23713,17401],{"class":441},[431,23715,23043],{"class":445},[431,23717,4846],{"class":441},[431,23719,23048],{"class":445},[431,23721,3568],{"class":441},[431,23723,23724],{"class":433,"line":4419},[431,23725,1662],{"emptyLinePlaceholder":393},[431,23727,23728,23730],{"class":433,"line":4436},[431,23729,438],{"class":437},[431,23731,23206],{"class":441},[431,23733,23734],{"class":433,"line":4446},[431,23735,23736],{"class":455},"# \u003Cul>\n",[431,23738,23739],{"class":433,"line":4451},[431,23740,23741],{"class":455},"# \u003Cli>milk\u003C\u002Fli>\n",[431,23743,23744],{"class":433,"line":4086},[431,23745,23608],{"class":455},[632,23747,23749],{"id":23748},"обработка-строк-через-преобразование-в-список","Обработка строк через преобразование в список",[415,23751,23752],{},"На собеседованиях часто задают подобные задачки:",[415,23754,23755],{},"Дана строка текста. Нужно сделать заглавной первую букву каждого слова в тексте.\nДля простоты считаем что мы работаем с текстом, который не содержит знаков препинания:",[422,23757,23759],{"className":424,"code":23758,"language":396,"meta":426,"style":426},"text = 'hello python'\ncapitalize_words(text) # 'Hello Python'\n",[428,23760,23761,23770],{"__ignoreMap":426},[431,23762,23763,23765,23767],{"class":433,"line":434},[431,23764,3100],{"class":441},[431,23766,1189],{"class":654},[431,23768,23769],{"class":445}," 'hello python'\n",[431,23771,23772,23775],{"class":433,"line":452},[431,23773,23774],{"class":441},"capitalize_words(text) ",[431,23776,23777],{"class":455},"# 'Hello Python'\n",[415,23779,23780],{},"Решить ее можно многими способами. Чем больше называет человек — тем лучше. К ним относятся:",[1588,23782,23783,23786,23789],{},[700,23784,23785],{},"Посимвольный перебор строки",[700,23787,23788],{},"Через преобразование в список",[700,23790,23791],{},"Регулярные выражения",[415,23793,23794,23795,23798],{},"Разберем решение через список. Для этого воспользуемся методом строки ",[428,23796,23797],{},"split()",", который разделяет строку на части:",[422,23800,23802],{"className":424,"code":23801,"language":396,"meta":426,"style":426},"def capitalize_words(sentence):\n  # Определяем разделитель — пробел\n  separator = ' '\n  # split разделяет строку по указанному разделителю\n  words = sentence.split(separator)\n  # ...\n",[428,23803,23804,23813,23818,23828,23833,23843],{"__ignoreMap":426},[431,23805,23806,23808,23811],{"class":433,"line":434},[431,23807,6330],{"class":654},[431,23809,23810],{"class":6333}," capitalize_words",[431,23812,10417],{"class":441},[431,23814,23815],{"class":433,"line":452},[431,23816,23817],{"class":455},"  # Определяем разделитель — пробел\n",[431,23819,23820,23823,23825],{"class":433,"line":578},[431,23821,23822],{"class":441},"  separator ",[431,23824,1189],{"class":654},[431,23826,23827],{"class":445}," ' '\n",[431,23829,23830],{"class":433,"line":584},[431,23831,23832],{"class":455},"  # split разделяет строку по указанному разделителю\n",[431,23834,23835,23838,23840],{"class":433,"line":1244},[431,23836,23837],{"class":441},"  words ",[431,23839,1189],{"class":654},[431,23841,23842],{"class":441}," sentence.split(separator)\n",[431,23844,23845],{"class":433,"line":1985},[431,23846,23847],{"class":455},"  # ...\n",[415,23849,23850],{},"Следующим шагом нужно пройтись по списку получившихся слов и преобразовать первую букву каждого слова к верхнему регистру.",[422,23852,23854],{"className":424,"code":23853,"language":396,"meta":426,"style":426},"def capitalize_words(sentence):\n  separator = ' '\n  words = sentence.split(separator)\n  # Формируем список обработанных слов\n  capitalized_words = []\n  for word in words:\n    capitalized_words.append(word.capitalize())\n\n  # Соединяем обработанные слова обратно в предложение\n  return separator.join(capitalized_words)\n\ntext = 'hello python'\nprint(capitalize_words(text)) # => Hello Python\n",[428,23855,23856,23864,23872,23880,23885,23894,23906,23911,23915,23920,23927,23931,23939],{"__ignoreMap":426},[431,23857,23858,23860,23862],{"class":433,"line":434},[431,23859,6330],{"class":654},[431,23861,23810],{"class":6333},[431,23863,10417],{"class":441},[431,23865,23866,23868,23870],{"class":433,"line":452},[431,23867,23822],{"class":441},[431,23869,1189],{"class":654},[431,23871,23827],{"class":445},[431,23873,23874,23876,23878],{"class":433,"line":578},[431,23875,23837],{"class":441},[431,23877,1189],{"class":654},[431,23879,23842],{"class":441},[431,23881,23882],{"class":433,"line":584},[431,23883,23884],{"class":455},"  # Формируем список обработанных слов\n",[431,23886,23887,23890,23892],{"class":433,"line":1244},[431,23888,23889],{"class":441},"  capitalized_words ",[431,23891,1189],{"class":654},[431,23893,21007],{"class":441},[431,23895,23896,23898,23901,23903],{"class":433,"line":1985},[431,23897,20523],{"class":654},[431,23899,23900],{"class":441}," word ",[431,23902,14421],{"class":654},[431,23904,23905],{"class":441}," words:\n",[431,23907,23908],{"class":433,"line":2041},[431,23909,23910],{"class":441},"    capitalized_words.append(word.capitalize())\n",[431,23912,23913],{"class":433,"line":4018},[431,23914,1662],{"emptyLinePlaceholder":393},[431,23916,23917],{"class":433,"line":4030},[431,23918,23919],{"class":455},"  # Соединяем обработанные слова обратно в предложение\n",[431,23921,23922,23924],{"class":433,"line":4419},[431,23923,20132],{"class":654},[431,23925,23926],{"class":441}," separator.join(capitalized_words)\n",[431,23928,23929],{"class":433,"line":4436},[431,23930,1662],{"emptyLinePlaceholder":393},[431,23932,23933,23935,23937],{"class":433,"line":4446},[431,23934,3100],{"class":441},[431,23936,1189],{"class":654},[431,23938,23769],{"class":445},[431,23940,23941,23943,23946],{"class":433,"line":4451},[431,23942,438],{"class":437},[431,23944,23945],{"class":441},"(capitalize_words(text)) ",[431,23947,23948],{"class":455},"# => Hello Python\n",[632,23950,23952],{"id":23951},"вложенные-циклы","Вложенные циклы",[415,23954,23955],{},"Во многих языках программирования есть очень полезная функция flatten.\nВ определенных задачах она сильно упрощает жизнь и сокращает количество кода.\nЭта функция принимает на вход список и выпрямляет его: если элементами списка являются списки, то flatten сводит все к одному списку, раскрывая каждый вложенный.\nРеализуем эту функцию самостоятельно. В общем случае эта функция раскрывает списки на всех уровнях вложенности.\nНо мы для простоты сделаем вариант функции, в котором происходит раскрытие только до первого уровня.\nТо есть, если элемент основного списка — список, то он раскрывается без просмотра его внутренностей (там тоже могут быть списки).\nЛогика работы функции выглядит так:",[422,23957,23959],{"className":424,"code":23958,"language":396,"meta":426,"style":426},"def flatten(coll):\n    result = []\n    for item in coll:\n        # Функция isinstance проверяет является ли item типом данных список\n        if isinstance(item, list):\n            for sub_item in item:\n                result.append(sub_item)\n        else:\n            result.append(item)\n    return result\n\nprint(flatten([3, 2, [], [3, 4, 2], 3, [123, 3]]))\n# => [ 3, 2, 3, 4, 2, 3, 123, 3 ]\n",[428,23960,23961,23970,23978,23988,23993,24008,24021,24026,24033,24037,24043,24047,24088],{"__ignoreMap":426},[431,23962,23963,23965,23968],{"class":433,"line":434},[431,23964,6330],{"class":654},[431,23966,23967],{"class":6333}," flatten",[431,23969,18678],{"class":441},[431,23971,23972,23974,23976],{"class":433,"line":452},[431,23973,6796],{"class":441},[431,23975,1189],{"class":654},[431,23977,21007],{"class":441},[431,23979,23980,23982,23984,23986],{"class":433,"line":578},[431,23981,14745],{"class":654},[431,23983,21014],{"class":441},[431,23985,14421],{"class":654},[431,23987,18697],{"class":441},[431,23989,23990],{"class":433,"line":584},[431,23991,23992],{"class":455},"        # Функция isinstance проверяет является ли item типом данных список\n",[431,23994,23995,23997,24000,24003,24006],{"class":433,"line":1244},[431,23996,11471],{"class":654},[431,23998,23999],{"class":437}," isinstance",[431,24001,24002],{"class":441},"(item, ",[431,24004,24005],{"class":437},"list",[431,24007,7381],{"class":441},[431,24009,24010,24013,24016,24018],{"class":433,"line":1985},[431,24011,24012],{"class":654},"            for",[431,24014,24015],{"class":441}," sub_item ",[431,24017,14421],{"class":654},[431,24019,24020],{"class":441}," item:\n",[431,24022,24023],{"class":433,"line":2041},[431,24024,24025],{"class":441},"                result.append(sub_item)\n",[431,24027,24028,24031],{"class":433,"line":4018},[431,24029,24030],{"class":654},"        else",[431,24032,8102],{"class":441},[431,24034,24035],{"class":433,"line":4030},[431,24036,21039],{"class":441},[431,24038,24039,24041],{"class":433,"line":4419},[431,24040,6599],{"class":654},[431,24042,6812],{"class":441},[431,24044,24045],{"class":433,"line":4436},[431,24046,1662],{"emptyLinePlaceholder":393},[431,24048,24049,24051,24054,24056,24058,24060,24063,24065,24067,24069,24071,24073,24075,24077,24079,24081,24083,24085],{"class":433,"line":4446},[431,24050,438],{"class":437},[431,24052,24053],{"class":441},"(flatten([",[431,24055,971],{"class":437},[431,24057,4846],{"class":441},[431,24059,651],{"class":437},[431,24061,24062],{"class":441},", [], [",[431,24064,971],{"class":437},[431,24066,4846],{"class":441},[431,24068,762],{"class":437},[431,24070,4846],{"class":441},[431,24072,651],{"class":437},[431,24074,22034],{"class":441},[431,24076,971],{"class":437},[431,24078,22328],{"class":441},[431,24080,12257],{"class":437},[431,24082,4846],{"class":441},[431,24084,971],{"class":437},[431,24086,24087],{"class":441},"]]))\n",[431,24089,24090],{"class":433,"line":4451},[431,24091,24092],{"class":455},"# => [ 3, 2, 3, 4, 2, 3, 123, 3 ]\n",[415,24094,24095],{},"Обратите внимание, что вложенный цикл запускается, только если текущий элемент — список.\nЧисто технически во вложенных циклах нет ничего особенного.\nИх можно вкладывать внутрь любого блока и друг в друга сколько угодно раз.\nНо прямой связи между внешним и вложенным циклами нет.\nВнутренний цикл может использовать результаты внешнего, а может и работать по своей собственной логике независимо.\nВложенные циклы могут резко увеличить сложность кода, так как появляется множество постоянно изменяющихся переменных.\nСтановится тяжело уследить за происходящими внутри процессами.\nКроме того, вложенные циклы могут указывать на использование неэффективного алгоритма решения задачи.\nЭто не всегда так, но вероятность такая есть.\nКак избавиться от вложенных циклов? Есть три варианта.\nПервый – ничего не делать, иногда вложенные циклы это нормально, особенно в низкоуровневых алгоритмах.\nВторой – переписать алгоритм так, чтобы вложенного цикла не осталось вообще, даже в вызываемых функциях.\nКогда это невозможно – использовать третий вариант.\nВынести вложенный цикл в функцию, либо заменить на встроенную функцию (или метод).",[415,24097,24098],{},"Пример выноса в отдельную функцию кода на flatten:",[422,24100,24102],{"className":424,"code":24101,"language":396,"meta":426,"style":426},"# Изменяет первый список напрямую\n# В данном случае такая реализация оправдана\ndef append(data1, data2):\n    for item in data2:\n        data1.append(item)\n\ndef flatten(coll):\n    result = []\n    for item in coll:\n        if isinstance(item, list):\n            append(result, item)\n        else:\n            result.append(item)\n\n    return result\n\nprint(flatten([3, 2, [], [3, 4, 2], 3, [123, 3]]))\n",[428,24103,24104,24109,24114,24123,24134,24139,24143,24151,24159,24169,24181,24186,24192,24196,24200,24206,24210],{"__ignoreMap":426},[431,24105,24106],{"class":433,"line":434},[431,24107,24108],{"class":455},"# Изменяет первый список напрямую\n",[431,24110,24111],{"class":433,"line":452},[431,24112,24113],{"class":455},"# В данном случае такая реализация оправдана\n",[431,24115,24116,24118,24120],{"class":433,"line":578},[431,24117,6330],{"class":654},[431,24119,20351],{"class":6333},[431,24121,24122],{"class":441},"(data1, data2):\n",[431,24124,24125,24127,24129,24131],{"class":433,"line":584},[431,24126,14745],{"class":654},[431,24128,21014],{"class":441},[431,24130,14421],{"class":654},[431,24132,24133],{"class":441}," data2:\n",[431,24135,24136],{"class":433,"line":1244},[431,24137,24138],{"class":441},"        data1.append(item)\n",[431,24140,24141],{"class":433,"line":1985},[431,24142,1662],{"emptyLinePlaceholder":393},[431,24144,24145,24147,24149],{"class":433,"line":2041},[431,24146,6330],{"class":654},[431,24148,23967],{"class":6333},[431,24150,18678],{"class":441},[431,24152,24153,24155,24157],{"class":433,"line":4018},[431,24154,6796],{"class":441},[431,24156,1189],{"class":654},[431,24158,21007],{"class":441},[431,24160,24161,24163,24165,24167],{"class":433,"line":4030},[431,24162,14745],{"class":654},[431,24164,21014],{"class":441},[431,24166,14421],{"class":654},[431,24168,18697],{"class":441},[431,24170,24171,24173,24175,24177,24179],{"class":433,"line":4419},[431,24172,11471],{"class":654},[431,24174,23999],{"class":437},[431,24176,24002],{"class":441},[431,24178,24005],{"class":437},[431,24180,7381],{"class":441},[431,24182,24183],{"class":433,"line":4436},[431,24184,24185],{"class":441},"            append(result, item)\n",[431,24187,24188,24190],{"class":433,"line":4446},[431,24189,24030],{"class":654},[431,24191,8102],{"class":441},[431,24193,24194],{"class":433,"line":4451},[431,24195,21039],{"class":441},[431,24197,24198],{"class":433,"line":4086},[431,24199,1662],{"emptyLinePlaceholder":393},[431,24201,24202,24204],{"class":433,"line":4477},[431,24203,6599],{"class":654},[431,24205,6812],{"class":441},[431,24207,24208],{"class":433,"line":4482},[431,24209,1662],{"emptyLinePlaceholder":393},[431,24211,24212,24214,24216,24218,24220,24222,24224,24226,24228,24230,24232,24234,24236,24238,24240,24242,24244,24246],{"class":433,"line":4488},[431,24213,438],{"class":437},[431,24215,24053],{"class":441},[431,24217,971],{"class":437},[431,24219,4846],{"class":441},[431,24221,651],{"class":437},[431,24223,24062],{"class":441},[431,24225,971],{"class":437},[431,24227,4846],{"class":441},[431,24229,762],{"class":437},[431,24231,4846],{"class":441},[431,24233,651],{"class":437},[431,24235,22034],{"class":441},[431,24237,971],{"class":437},[431,24239,22328],{"class":441},[431,24241,12257],{"class":437},[431,24243,4846],{"class":441},[431,24245,971],{"class":437},[431,24247,24087],{"class":441},[415,24249,1849,24250,1853,24252,1857],{},[800,24251,1852],{},[800,24253,1856],{},[1859,24255],{},[1862,24257,24258],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}",{"title":426,"searchDepth":452,"depth":1244,"links":24260},[24261],{"id":23020,"depth":452,"text":218,"children":24262},[24263,24264,24265],{"id":23023,"depth":578,"text":23024},{"id":23748,"depth":578,"text":23749},{"id":23951,"depth":578,"text":23952},"2025-04-06","Генерация строки в цикле. Обработка строк через преобразование в список. Вложенные циклы","images\u002Fblog\u002Fpython\u002Fst16\u002Fimg.png",{},{"title":218,"description":24267},"avn2B4jC_dLjGrNbMweIjT5gzRTP5yA1w3ogtQ8sfNk",{"id":24273,"title":222,"author":24274,"body":24276,"date":26257,"description":26258,"extension":1887,"image":26259,"meta":26260,"minRead":12871,"navigation":393,"num":4488,"path":223,"seo":26261,"stem":224,"__hash__":26262},"python\u002Fblog\u002Fpython\u002Fst17.md",{"name":402,"avatar":24275},{"src":404,"alt":405},{"type":407,"value":24277,"toc":26239},[24278,24281,24285,24288,24292,24295,24304,24307,24318,24428,24431,24442,24445,24468,24472,24475,24628,24632,24635,24706,24709,24712,24780,24783,24887,24890,24894,24897,24900,25002,25005,25009,25012,25015,25073,25076,25182,25186,25189,25238,25241,25285,25288,25340,25343,25379,25383,25386,25446,25449,25470,25473,25477,25480,25505,25509,25512,25585,25588,25856,25859,25920,25923,25976,25979,25983,25986,26049,26052,26152,26155,26228,26234,26236],[410,24279,222],{"id":24280},"использование-списков-ч3",[632,24282,24284],{"id":24283},"срезы","Срезы",[415,24286,24287],{},"Настало время перейти к очень интересному инструменту,\nкоторый Python предоставляет для работы с целыми подмножествами элементов списка - срезы(slices).",[458,24289,24291],{"id":24290},"синтаксис-срезов","Синтаксис срезов",[415,24293,24294],{},"Срез записывается так же, как записывается обращение к элементу списка по индексу:",[422,24296,24298],{"className":1436,"code":24297,"language":1438,"meta":426,"style":426},"some_list[START:STOP:STEP]\n",[428,24299,24300],{"__ignoreMap":426},[431,24301,24302],{"class":433,"line":434},[431,24303,24297],{},[415,24305,24306],{},"У среза три параметра:",[697,24308,24309,24312,24315],{},[700,24310,24311],{},"START — индекс первого элемента в выборке",[700,24313,24314],{},"STOP — индекс элемента списка, перед которым срез должен закончиться. Сам элемент с индексом STOP не будет входить в выборку",[700,24316,24317],{},"STEP — шаг выбираемых индексов",[422,24319,24321],{"className":424,"code":24320,"language":396,"meta":426,"style":426},"l = [1, 2, 3, 4, 5]\n# Срез от нулевого по четвёртый индекс с шагом 1\nslice = l[0:4:1]\nprint(slice)  # => [1, 2, 3, 4]\n# Срез от нулевого по четвёртый индекс с шагом 2\nslice = l[0:4:2]\nprint(slice)  # => [1, 3] \n",[428,24322,24323,24351,24356,24378,24390,24395,24415],{"__ignoreMap":426},[431,24324,24325,24327,24329,24331,24333,24335,24337,24339,24341,24343,24345,24347,24349],{"class":433,"line":434},[431,24326,18164],{"class":441},[431,24328,1189],{"class":654},[431,24330,17401],{"class":441},[431,24332,1192],{"class":437},[431,24334,4846],{"class":441},[431,24336,651],{"class":437},[431,24338,4846],{"class":441},[431,24340,971],{"class":437},[431,24342,4846],{"class":441},[431,24344,762],{"class":437},[431,24346,4846],{"class":441},[431,24348,856],{"class":437},[431,24350,3568],{"class":441},[431,24352,24353],{"class":433,"line":452},[431,24354,24355],{"class":455},"# Срез от нулевого по четвёртый индекс с шагом 1\n",[431,24357,24358,24361,24363,24366,24368,24370,24372,24374,24376],{"class":433,"line":578},[431,24359,24360],{"class":437},"slice",[431,24362,2146],{"class":654},[431,24364,24365],{"class":441}," l[",[431,24367,3302],{"class":437},[431,24369,3562],{"class":441},[431,24371,762],{"class":437},[431,24373,3562],{"class":441},[431,24375,1192],{"class":437},[431,24377,3568],{"class":441},[431,24379,24380,24382,24384,24386,24388],{"class":433,"line":584},[431,24381,438],{"class":437},[431,24383,442],{"class":441},[431,24385,24360],{"class":437},[431,24387,526],{"class":441},[431,24389,20435],{"class":455},[431,24391,24392],{"class":433,"line":1244},[431,24393,24394],{"class":455},"# Срез от нулевого по четвёртый индекс с шагом 2\n",[431,24396,24397,24399,24401,24403,24405,24407,24409,24411,24413],{"class":433,"line":1985},[431,24398,24360],{"class":437},[431,24400,2146],{"class":654},[431,24402,24365],{"class":441},[431,24404,3302],{"class":437},[431,24406,3562],{"class":441},[431,24408,762],{"class":437},[431,24410,3562],{"class":441},[431,24412,651],{"class":437},[431,24414,3568],{"class":441},[431,24416,24417,24419,24421,24423,24425],{"class":433,"line":2041},[431,24418,438],{"class":437},[431,24420,442],{"class":441},[431,24422,24360],{"class":437},[431,24424,526],{"class":441},[431,24426,24427],{"class":455},"# => [1, 3]\n",[415,24429,24430],{},"При этом любой из трех параметров среза может быть пропущен и вместо соответствующего параметра будет значение по умолчанию:",[697,24432,24433,24436,24439],{},[700,24434,24435],{},"По умолчанию START означает «от начала списка».",[700,24437,24438],{},"По умолчанию STOP означает «до конца списка включительно».",[700,24440,24441],{},"По умолчанию STEP означает «брать каждый элемент».",[415,24443,24444],{},"Вот несколько примеров с разными наборами параметров:",[697,24446,24447,24450,24453,24456,24459,24462,24465],{},[700,24448,24449],{},"[:] или [::] — весь список.",[700,24451,24452],{},"[::2] — нечетные по порядку элементы.",[700,24454,24455],{},"[1::2] — четные по порядку элементы.",[700,24457,24458],{},"[::-1] — все элементы в обратном порядке.",[700,24460,24461],{},"[5:] — все элементы, начиная с шестого.",[700,24463,24464],{},"[:5] — все элементы, не доходя до шестого.",[700,24466,24467],{},"[-2:1:-1] — все элементы от предпоследнего до третьего в обратном порядке. Во всех случаях выборки от большего индекса к меньшему нужно указывать шаг.\nТеперь разберем как можно использовать срезы.",[12129,24469,24471],{"id":24470},"выборка-элементов","Выборка элементов",[415,24473,24474],{},"Срезы работают не только со списками, но и с кортежами, и даже со строками.\nРезультатом применения выборки всегда становится новое значение соответствующего типа — список, кортеж, строка:",[422,24476,24478],{"className":424,"code":24477,"language":396,"meta":426,"style":426},"word = \"hello\"\nprint(word[3:])  # => lo\n\nuser_data = (\n    \"Alex\",\n    \"alex@example.com\",\n    \"student\",\n)\nprint(user_data[1::])  # ('alexn@example.com', 'student')\n\nnumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\nprint(numbers[1::2])  # [2, 4, 6, 8, 10]\n",[428,24479,24480,24489,24504,24508,24518,24525,24532,24539,24543,24558,24562,24610],{"__ignoreMap":426},[431,24481,24482,24484,24486],{"class":433,"line":434},[431,24483,22089],{"class":441},[431,24485,1189],{"class":654},[431,24487,24488],{"class":445}," \"hello\"\n",[431,24490,24491,24493,24496,24498,24501],{"class":433,"line":452},[431,24492,438],{"class":437},[431,24494,24495],{"class":441},"(word[",[431,24497,971],{"class":437},[431,24499,24500],{"class":441},":])  ",[431,24502,24503],{"class":455},"# => lo\n",[431,24505,24506],{"class":433,"line":578},[431,24507,1662],{"emptyLinePlaceholder":393},[431,24509,24510,24513,24515],{"class":433,"line":584},[431,24511,24512],{"class":441},"user_data ",[431,24514,1189],{"class":654},[431,24516,24517],{"class":441}," (\n",[431,24519,24520,24523],{"class":433,"line":1244},[431,24521,24522],{"class":445},"    \"Alex\"",[431,24524,22541],{"class":441},[431,24526,24527,24530],{"class":433,"line":1985},[431,24528,24529],{"class":445},"    \"alex@example.com\"",[431,24531,22541],{"class":441},[431,24533,24534,24537],{"class":433,"line":2041},[431,24535,24536],{"class":445},"    \"student\"",[431,24538,22541],{"class":441},[431,24540,24541],{"class":433,"line":4018},[431,24542,449],{"class":441},[431,24544,24545,24547,24550,24552,24555],{"class":433,"line":4030},[431,24546,438],{"class":437},[431,24548,24549],{"class":441},"(user_data[",[431,24551,1192],{"class":437},[431,24553,24554],{"class":441},"::])  ",[431,24556,24557],{"class":455},"# ('alexn@example.com', 'student')\n",[431,24559,24560],{"class":433,"line":4419},[431,24561,1662],{"emptyLinePlaceholder":393},[431,24563,24564,24566,24568,24570,24572,24574,24576,24578,24580,24582,24584,24586,24588,24590,24592,24594,24596,24598,24600,24602,24604,24606,24608],{"class":433,"line":4436},[431,24565,19577],{"class":441},[431,24567,1189],{"class":654},[431,24569,17401],{"class":441},[431,24571,1192],{"class":437},[431,24573,4846],{"class":441},[431,24575,651],{"class":437},[431,24577,4846],{"class":441},[431,24579,971],{"class":437},[431,24581,4846],{"class":441},[431,24583,762],{"class":437},[431,24585,4846],{"class":441},[431,24587,856],{"class":437},[431,24589,4846],{"class":441},[431,24591,742],{"class":437},[431,24593,4846],{"class":441},[431,24595,781],{"class":437},[431,24597,4846],{"class":441},[431,24599,1021],{"class":437},[431,24601,4846],{"class":441},[431,24603,3357],{"class":437},[431,24605,4846],{"class":441},[431,24607,3565],{"class":437},[431,24609,3568],{"class":441},[431,24611,24612,24614,24617,24619,24621,24623,24625],{"class":433,"line":4446},[431,24613,438],{"class":437},[431,24615,24616],{"class":441},"(numbers[",[431,24618,1192],{"class":437},[431,24620,3816],{"class":441},[431,24622,651],{"class":437},[431,24624,3305],{"class":441},[431,24626,24627],{"class":455},"# [2, 4, 6, 8, 10]\n",[12129,24629,24631],{"id":24630},"присваивание-срезу","Присваивание срезу",[415,24633,24634],{},"В отличие от строк и кортежей списки могут изменяться.\nОдним из вариантов модификации является присваивание срезу.\nСрезу с указанным шагом можно присвоить список из новых элементов:",[422,24636,24638],{"className":424,"code":24637,"language":396,"meta":426,"style":426},"l = [1, 2, 3, 4, 5, 6]\nl[::2] = [0, 0, 0]\nprint(l)  # => [0, 2, 0, 4, 0, 6]\n",[428,24639,24640,24672,24697],{"__ignoreMap":426},[431,24641,24642,24644,24646,24648,24650,24652,24654,24656,24658,24660,24662,24664,24666,24668,24670],{"class":433,"line":434},[431,24643,18164],{"class":441},[431,24645,1189],{"class":654},[431,24647,17401],{"class":441},[431,24649,1192],{"class":437},[431,24651,4846],{"class":441},[431,24653,651],{"class":437},[431,24655,4846],{"class":441},[431,24657,971],{"class":437},[431,24659,4846],{"class":441},[431,24661,762],{"class":437},[431,24663,4846],{"class":441},[431,24665,856],{"class":437},[431,24667,4846],{"class":441},[431,24669,742],{"class":437},[431,24671,3568],{"class":441},[431,24673,24674,24677,24679,24681,24683,24685,24687,24689,24691,24693,24695],{"class":433,"line":452},[431,24675,24676],{"class":441},"l[::",[431,24678,651],{"class":437},[431,24680,4049],{"class":441},[431,24682,1189],{"class":654},[431,24684,17401],{"class":441},[431,24686,3302],{"class":437},[431,24688,4846],{"class":441},[431,24690,3302],{"class":437},[431,24692,4846],{"class":441},[431,24694,3302],{"class":437},[431,24696,3568],{"class":441},[431,24698,24699,24701,24703],{"class":433,"line":578},[431,24700,438],{"class":437},[431,24702,18192],{"class":441},[431,24704,24705],{"class":455},"# => [0, 2, 0, 4, 0, 6]\n",[415,24707,24708],{},"Срез [::2] означает, что мы выбираем элементы с шагом 2, то есть берем каждый второй элемент.\nСписок [0, 0, 0] - это список, который мы присваиваем выбранным элементам.\nСрез l[::2] теперь содержит элементы с индексами 0, 2 и 4 (т.е. 1, 3 и 5).\nПрисваивание [0, 0, 0] этим элементам заменяет их на нули.\nВ результате изменения списка l становится равным [0, 2, 0, 4, 0, 6].",[415,24710,24711],{},"Если вы попробуете присвоить срезу с шагом неверное количество элементов, то получите ошибку:",[422,24713,24715],{"className":424,"code":24714,"language":396,"meta":426,"style":426},"l = [1, 2, 3, 4]\nl[::2] = [5, 6, 7]\n# Traceback (most recent call last):\n#   File \"\u003Cstdin>\", line 1, in \u003Cmodule>\n# ValueError: attempt to assign sequence of size 3 to extended slice of size 2\n",[428,24716,24717,24741,24765,24770,24775],{"__ignoreMap":426},[431,24718,24719,24721,24723,24725,24727,24729,24731,24733,24735,24737,24739],{"class":433,"line":434},[431,24720,18164],{"class":441},[431,24722,1189],{"class":654},[431,24724,17401],{"class":441},[431,24726,1192],{"class":437},[431,24728,4846],{"class":441},[431,24730,651],{"class":437},[431,24732,4846],{"class":441},[431,24734,971],{"class":437},[431,24736,4846],{"class":441},[431,24738,762],{"class":437},[431,24740,3568],{"class":441},[431,24742,24743,24745,24747,24749,24751,24753,24755,24757,24759,24761,24763],{"class":433,"line":452},[431,24744,24676],{"class":441},[431,24746,651],{"class":437},[431,24748,4049],{"class":441},[431,24750,1189],{"class":654},[431,24752,17401],{"class":441},[431,24754,856],{"class":437},[431,24756,4846],{"class":441},[431,24758,742],{"class":437},[431,24760,4846],{"class":441},[431,24762,781],{"class":437},[431,24764,3568],{"class":441},[431,24766,24767],{"class":433,"line":578},[431,24768,24769],{"class":455},"# Traceback (most recent call last):\n",[431,24771,24772],{"class":433,"line":584},[431,24773,24774],{"class":455},"#   File \"\u003Cstdin>\", line 1, in \u003Cmodule>\n",[431,24776,24777],{"class":433,"line":1244},[431,24778,24779],{"class":455},"# ValueError: attempt to assign sequence of size 3 to extended slice of size 2\n",[415,24781,24782],{},"Если срез непрерывный, то есть шаг не указан и индексы идут подряд, то свободы нам дается больше.\nТакому срезу можно присвоить как больше элементов — тогда список вырастет, так и меньше, что приведет к урезанию списка:",[422,24784,24786],{"className":424,"code":24785,"language":396,"meta":426,"style":426},"l = [1, 2, 3]\nl[2:] = [4, 5]\nprint(l)  # => [1, 2, 4, 5]\nl[1:-1] = [100]\nprint(l)  # => [1, 100, 5]\nl[:] = []\nprint(l)  # => []\n",[428,24787,24788,24808,24830,24839,24861,24870,24879],{"__ignoreMap":426},[431,24789,24790,24792,24794,24796,24798,24800,24802,24804,24806],{"class":433,"line":434},[431,24791,18164],{"class":441},[431,24793,1189],{"class":654},[431,24795,17401],{"class":441},[431,24797,1192],{"class":437},[431,24799,4846],{"class":441},[431,24801,651],{"class":437},[431,24803,4846],{"class":441},[431,24805,971],{"class":437},[431,24807,3568],{"class":441},[431,24809,24810,24813,24815,24818,24820,24822,24824,24826,24828],{"class":433,"line":452},[431,24811,24812],{"class":441},"l[",[431,24814,651],{"class":437},[431,24816,24817],{"class":441},":] ",[431,24819,1189],{"class":654},[431,24821,17401],{"class":441},[431,24823,762],{"class":437},[431,24825,4846],{"class":441},[431,24827,856],{"class":437},[431,24829,3568],{"class":441},[431,24831,24832,24834,24836],{"class":433,"line":578},[431,24833,438],{"class":437},[431,24835,18192],{"class":441},[431,24837,24838],{"class":455},"# => [1, 2, 4, 5]\n",[431,24840,24841,24843,24845,24847,24849,24851,24853,24855,24857,24859],{"class":433,"line":584},[431,24842,24812],{"class":441},[431,24844,1192],{"class":437},[431,24846,3562],{"class":441},[431,24848,853],{"class":654},[431,24850,1192],{"class":437},[431,24852,4049],{"class":441},[431,24854,1189],{"class":654},[431,24856,17401],{"class":441},[431,24858,2249],{"class":437},[431,24860,3568],{"class":441},[431,24862,24863,24865,24867],{"class":433,"line":1244},[431,24864,438],{"class":437},[431,24866,18192],{"class":441},[431,24868,24869],{"class":455},"# => [1, 100, 5]\n",[431,24871,24872,24875,24877],{"class":433,"line":1985},[431,24873,24874],{"class":441},"l[:] ",[431,24876,1189],{"class":654},[431,24878,21007],{"class":441},[431,24880,24881,24883,24885],{"class":433,"line":2041},[431,24882,438],{"class":437},[431,24884,18192],{"class":441},[431,24886,21102],{"class":455},[415,24888,24889],{},"Сначала список растет, потом уменьшается, а под конец вообще становится пустым — и все с помощью компактного, но мощного синтаксиса срезов.",[12129,24891,24893],{"id":24892},"срезы-значения","Срезы-значения",[415,24895,24896],{},"Хоть срезы и имеют специальную поддержку со стороны синтаксиса, но можно создавать и использовать срезы сами по себе — как обычные значения.",[415,24898,24899],{},"Значение среза можно сконструировать с помощью функции slice():",[422,24901,24903],{"className":424,"code":24902,"language":396,"meta":426,"style":426},"first_two = slice(2)\neach_odd = slice(None, None, 2)\nprint(each_odd)  # => slice(None, None, 2)\nl = [1, 2, 3, 4, 5]\nprint(l[first_two])  # => [1, 2]\nprint(l[each_odd])  # => [1, 3, 5]\n",[428,24904,24905,24921,24944,24954,24982,24992],{"__ignoreMap":426},[431,24906,24907,24910,24912,24915,24917,24919],{"class":433,"line":434},[431,24908,24909],{"class":441},"first_two ",[431,24911,1189],{"class":654},[431,24913,24914],{"class":437}," slice",[431,24916,442],{"class":441},[431,24918,651],{"class":437},[431,24920,449],{"class":441},[431,24922,24923,24926,24928,24930,24932,24934,24936,24938,24940,24942],{"class":433,"line":452},[431,24924,24925],{"class":441},"each_odd ",[431,24927,1189],{"class":654},[431,24929,24914],{"class":437},[431,24931,442],{"class":441},[431,24933,7922],{"class":437},[431,24935,4846],{"class":441},[431,24937,7922],{"class":437},[431,24939,4846],{"class":441},[431,24941,651],{"class":437},[431,24943,449],{"class":441},[431,24945,24946,24948,24951],{"class":433,"line":578},[431,24947,438],{"class":437},[431,24949,24950],{"class":441},"(each_odd)  ",[431,24952,24953],{"class":455},"# => slice(None, None, 2)\n",[431,24955,24956,24958,24960,24962,24964,24966,24968,24970,24972,24974,24976,24978,24980],{"class":433,"line":584},[431,24957,18164],{"class":441},[431,24959,1189],{"class":654},[431,24961,17401],{"class":441},[431,24963,1192],{"class":437},[431,24965,4846],{"class":441},[431,24967,651],{"class":437},[431,24969,4846],{"class":441},[431,24971,971],{"class":437},[431,24973,4846],{"class":441},[431,24975,762],{"class":437},[431,24977,4846],{"class":441},[431,24979,856],{"class":437},[431,24981,3568],{"class":441},[431,24983,24984,24986,24989],{"class":433,"line":1244},[431,24985,438],{"class":437},[431,24987,24988],{"class":441},"(l[first_two])  ",[431,24990,24991],{"class":455},"# => [1, 2]\n",[431,24993,24994,24996,24999],{"class":433,"line":1985},[431,24995,438],{"class":437},[431,24997,24998],{"class":441},"(l[each_odd])  ",[431,25000,25001],{"class":455},"# => [1, 3, 5]\n",[415,25003,25004],{},"Функция slice() принимает от одного до трех параметров — те самые START, STOP и STEP.\nПри вызове функции с одним параметром, функция вызывается с параметром STOP.\nЕсли необходимо пропустить один из параметров, то подставляется вместо него None.\nТакже None можно использовать и в записи срезов в квадратных скобках — там он так же будет означать пропуск значения.\nНа месте параметров среза могут быть любые выражения, лишь бы эти выражения вычислялись в целые числа или None.",[12129,25006,25008],{"id":25007},"соотношение-start-и-stop","Соотношение start и stop",[415,25010,25011],{},"В срезе элемент с индексом STOP не включается в результат, в отличие от элемента с индексом START.",[415,25013,25014],{},"Эту особенность можно использовать, какой бы неотрицательный индекс n мы ни выбрали, для любого списка будет соблюдаться указанное равенство:",[422,25016,25018],{"className":424,"code":25017,"language":396,"meta":426,"style":426},"l = [1, 2, 3, 4, 5]\nn = 2\nl == l[:n] + l[n:]  # True\n",[428,25019,25020,25048,25057],{"__ignoreMap":426},[431,25021,25022,25024,25026,25028,25030,25032,25034,25036,25038,25040,25042,25044,25046],{"class":433,"line":434},[431,25023,18164],{"class":441},[431,25025,1189],{"class":654},[431,25027,17401],{"class":441},[431,25029,1192],{"class":437},[431,25031,4846],{"class":441},[431,25033,651],{"class":437},[431,25035,4846],{"class":441},[431,25037,971],{"class":437},[431,25039,4846],{"class":441},[431,25041,762],{"class":437},[431,25043,4846],{"class":441},[431,25045,856],{"class":437},[431,25047,3568],{"class":441},[431,25049,25050,25053,25055],{"class":433,"line":452},[431,25051,25052],{"class":441},"n ",[431,25054,1189],{"class":654},[431,25056,658],{"class":437},[431,25058,25059,25061,25063,25066,25068,25071],{"class":433,"line":578},[431,25060,18164],{"class":441},[431,25062,8409],{"class":654},[431,25064,25065],{"class":441}," l[:n] ",[431,25067,802],{"class":654},[431,25069,25070],{"class":441}," l[n:]  ",[431,25072,19945],{"class":455},[415,25074,25075],{},"Ещё пример:",[422,25077,25079],{"className":424,"code":25078,"language":396,"meta":426,"style":426},"word = \"Hello!\"\nprint(word[:2] + word[2:])  # => 'Hello!'\nprint(word[:4] + word[4:])  # => 'Hello!'\nprint(word[:0] + word[0:] == word)  # => True\nprint(word[:100] + word[100:] == word)  # => True\n",[428,25080,25081,25090,25113,25133,25158],{"__ignoreMap":426},[431,25082,25083,25085,25087],{"class":433,"line":434},[431,25084,22089],{"class":441},[431,25086,1189],{"class":654},[431,25088,25089],{"class":445}," \"Hello!\"\n",[431,25091,25092,25094,25097,25099,25101,25103,25106,25108,25110],{"class":433,"line":452},[431,25093,438],{"class":437},[431,25095,25096],{"class":441},"(word[:",[431,25098,651],{"class":437},[431,25100,4049],{"class":441},[431,25102,802],{"class":654},[431,25104,25105],{"class":441}," word[",[431,25107,651],{"class":437},[431,25109,24500],{"class":441},[431,25111,25112],{"class":455},"# => 'Hello!'\n",[431,25114,25115,25117,25119,25121,25123,25125,25127,25129,25131],{"class":433,"line":578},[431,25116,438],{"class":437},[431,25118,25096],{"class":441},[431,25120,762],{"class":437},[431,25122,4049],{"class":441},[431,25124,802],{"class":654},[431,25126,25105],{"class":441},[431,25128,762],{"class":437},[431,25130,24500],{"class":441},[431,25132,25112],{"class":455},[431,25134,25135,25137,25139,25141,25143,25145,25147,25149,25151,25153,25156],{"class":433,"line":584},[431,25136,438],{"class":437},[431,25138,25096],{"class":441},[431,25140,3302],{"class":437},[431,25142,4049],{"class":441},[431,25144,802],{"class":654},[431,25146,25105],{"class":441},[431,25148,3302],{"class":437},[431,25150,24817],{"class":441},[431,25152,8409],{"class":654},[431,25154,25155],{"class":441}," word)  ",[431,25157,8470],{"class":455},[431,25159,25160,25162,25164,25166,25168,25170,25172,25174,25176,25178,25180],{"class":433,"line":1244},[431,25161,438],{"class":437},[431,25163,25096],{"class":441},[431,25165,2249],{"class":437},[431,25167,4049],{"class":441},[431,25169,802],{"class":654},[431,25171,25105],{"class":441},[431,25173,2249],{"class":437},[431,25175,24817],{"class":441},[431,25177,8409],{"class":654},[431,25179,25155],{"class":441},[431,25181,8470],{"class":455},[632,25183,25185],{"id":25184},"destructuring","Destructuring",[415,25187,25188],{},"Destructuring – синтаксическая возможность \"раскладывать\" элементы списка (и не только) в отдельные переменные.\nДеструктуризация относится к необязательным, но очень приятным возможностям языка.\nПредставьте, что у нас есть список из двух элементов, которыми мы хотим оперировать в нашей программе.\nСамый простой вариант использования его элементов — постоянное обращение по индексу point[0] и point[1].",[422,25190,25192],{"className":424,"code":25191,"language":396,"meta":426,"style":426},"point = [1, 1]\nprint(f`{point[0]}:{point[1]}`) # => 1:2\n",[428,25193,25194,25211],{"__ignoreMap":426},[431,25195,25196,25199,25201,25203,25205,25207,25209],{"class":433,"line":434},[431,25197,25198],{"class":441},"point ",[431,25200,1189],{"class":654},[431,25202,17401],{"class":441},[431,25204,1192],{"class":437},[431,25206,4846],{"class":441},[431,25208,1192],{"class":437},[431,25210,3568],{"class":441},[431,25212,25213,25215,25218,25222,25225,25228,25230,25233,25235],{"class":433,"line":452},[431,25214,438],{"class":437},[431,25216,25217],{"class":441},"(f",[431,25219,25221],{"class":25220},"sB1qb","`{point[",[431,25223,3302],{"class":25224},"sdV6q",[431,25226,25227],{"class":25220},"]}:{point[",[431,25229,1192],{"class":25224},[431,25231,25232],{"class":25220},"]}`",[431,25234,1014],{"class":441},[431,25236,25237],{"class":455},"# => 1:2\n",[415,25239,25240],{},"Индексы ничего не говорят о содержимом, и для понимания этого кода придется прикладывать дополнительные усилия.\nГораздо лучше сначала присвоить эти значения переменным с хорошими именами. Тогда код станет читаемым:",[422,25242,25244],{"className":424,"code":25243,"language":396,"meta":426,"style":426},"x = point[0]\ny = point[1]\nprint(f`{x}:{y}`) # => 1:2\n",[428,25245,25246,25259,25272],{"__ignoreMap":426},[431,25247,25248,25250,25252,25255,25257],{"class":433,"line":434},[431,25249,1186],{"class":441},[431,25251,1189],{"class":654},[431,25253,25254],{"class":441}," point[",[431,25256,3302],{"class":437},[431,25258,3568],{"class":441},[431,25260,25261,25264,25266,25268,25270],{"class":433,"line":452},[431,25262,25263],{"class":441},"y ",[431,25265,1189],{"class":654},[431,25267,25254],{"class":441},[431,25269,1192],{"class":437},[431,25271,3568],{"class":441},[431,25273,25274,25276,25278,25281,25283],{"class":433,"line":578},[431,25275,438],{"class":437},[431,25277,25217],{"class":441},[431,25279,25280],{"class":25220},"`{x}:{y}`",[431,25282,1014],{"class":441},[431,25284,25237],{"class":455},[415,25286,25287],{},"Код стал значительно понятнее, хотя и длиннее. С помощью деструктуризации то же самое можно сделать короче:",[422,25289,25291],{"className":424,"code":25290,"language":396,"meta":426,"style":426},"[x, y] = point\n# Слева список повторяет структуру правого списка\n# но вместо значений используются идентификаторы\n# они заполняются значениями, стоящими на тех же позициях в правом списке\n# [x, y] = [1, 2]\n# x = 1, y = 2\nprint(f`{x}:{y}`) # => 1:2\n",[428,25292,25293,25303,25308,25313,25318,25323,25328],{"__ignoreMap":426},[431,25294,25295,25298,25300],{"class":433,"line":434},[431,25296,25297],{"class":441},"[x, y] ",[431,25299,1189],{"class":654},[431,25301,25302],{"class":441}," point\n",[431,25304,25305],{"class":433,"line":452},[431,25306,25307],{"class":455},"# Слева список повторяет структуру правого списка\n",[431,25309,25310],{"class":433,"line":578},[431,25311,25312],{"class":455},"# но вместо значений используются идентификаторы\n",[431,25314,25315],{"class":433,"line":584},[431,25316,25317],{"class":455},"# они заполняются значениями, стоящими на тех же позициях в правом списке\n",[431,25319,25320],{"class":433,"line":1244},[431,25321,25322],{"class":455},"# [x, y] = [1, 2]\n",[431,25324,25325],{"class":433,"line":1985},[431,25326,25327],{"class":455},"# x = 1, y = 2\n",[431,25329,25330,25332,25334,25336,25338],{"class":433,"line":2041},[431,25331,438],{"class":437},[431,25333,25217],{"class":441},[431,25335,25280],{"class":25220},[431,25337,1014],{"class":441},[431,25339,25237],{"class":455},[415,25341,25342],{},"Деструктуризация работает на любом уровне вложенности.\nНапример, с ее помощью можно извлекать данные из списков внутри списков:",[422,25344,25346],{"className":424,"code":25345,"language":396,"meta":426,"style":426},"[one, [two, three]] = [1, [2, 3]]\nprint(one, two, three)  # => 1 2 3\n",[428,25347,25348,25369],{"__ignoreMap":426},[431,25349,25350,25353,25355,25357,25359,25361,25363,25365,25367],{"class":433,"line":434},[431,25351,25352],{"class":441},"[one, [two, three]] ",[431,25354,1189],{"class":654},[431,25356,17401],{"class":441},[431,25358,1192],{"class":437},[431,25360,22328],{"class":441},[431,25362,651],{"class":437},[431,25364,4846],{"class":441},[431,25366,971],{"class":437},[431,25368,22301],{"class":441},[431,25370,25371,25373,25376],{"class":433,"line":452},[431,25372,438],{"class":437},[431,25374,25375],{"class":441},"(one, two, three)  ",[431,25377,25378],{"class":455},"# => 1 2 3\n",[458,25380,25382],{"id":25381},"деструктуризация-в-циклах","Деструктуризация в циклах",[415,25384,25385],{},"Разложение списка можно использовать не только как отдельную инструкцию в коде, но и в циклах:",[422,25387,25389],{"className":424,"code":25388,"language":396,"meta":426,"style":426},"points = [[1, 2], [0, -1]]\nfor x, y in points:\n    print([x, y])\n# => [1, 2]\n# => [0, -1]\n",[428,25390,25391,25418,25430,25437,25441],{"__ignoreMap":426},[431,25392,25393,25396,25398,25400,25402,25404,25406,25408,25410,25412,25414,25416],{"class":433,"line":434},[431,25394,25395],{"class":441},"points ",[431,25397,1189],{"class":654},[431,25399,22296],{"class":441},[431,25401,1192],{"class":437},[431,25403,4846],{"class":441},[431,25405,651],{"class":437},[431,25407,22337],{"class":441},[431,25409,3302],{"class":437},[431,25411,4846],{"class":441},[431,25413,853],{"class":654},[431,25415,1192],{"class":437},[431,25417,22301],{"class":441},[431,25419,25420,25422,25425,25427],{"class":433,"line":452},[431,25421,14329],{"class":654},[431,25423,25424],{"class":441}," x, y ",[431,25426,14421],{"class":654},[431,25428,25429],{"class":441}," points:\n",[431,25431,25432,25434],{"class":433,"line":578},[431,25433,6357],{"class":437},[431,25435,25436],{"class":441},"([x, y])\n",[431,25438,25439],{"class":433,"line":584},[431,25440,24991],{"class":455},[431,25442,25443],{"class":433,"line":1244},[431,25444,25445],{"class":455},"# => [0, -1]\n",[415,25447,25448],{},"В этом примере каждый элемент в цикле является списком. Без деструктуризации цикл выглядит так:",[422,25450,25452],{"className":424,"code":25451,"language":396,"meta":426,"style":426},"for item in points:\n    print(item)\n",[428,25453,25454,25464],{"__ignoreMap":426},[431,25455,25456,25458,25460,25462],{"class":433,"line":434},[431,25457,14329],{"class":654},[431,25459,21014],{"class":441},[431,25461,14421],{"class":654},[431,25463,25429],{"class":441},[431,25465,25466,25468],{"class":433,"line":452},[431,25467,6357],{"class":437},[431,25469,21645],{"class":441},[415,25471,25472],{},"Внутри for переменная item - это список, поэтому вместо нее можно подставить деструктуризацию [x, y].",[458,25474,25476],{"id":25475},"деструктуризация-строк","Деструктуризация строк",[415,25478,25479],{},"В python строки ведут себя подобно спискам и их также можно деструктурировать.",[422,25481,25483],{"className":424,"code":25482,"language":396,"meta":426,"style":426},"[first, second, third] = \"two\"\nprint(first)  # => 't'\n",[428,25484,25485,25495],{"__ignoreMap":426},[431,25486,25487,25490,25492],{"class":433,"line":434},[431,25488,25489],{"class":441},"[first, second, third] ",[431,25491,1189],{"class":654},[431,25493,25494],{"class":445}," \"two\"\n",[431,25496,25497,25499,25502],{"class":433,"line":452},[431,25498,438],{"class":437},[431,25500,25501],{"class":441},"(first)  ",[431,25503,25504],{"class":455},"# => 't'\n",[632,25506,25508],{"id":25507},"оператор-упаковки","Оператор упаковки",[415,25510,25511],{},"Мощь деструктуризации больше всего проявляется там, где она используется вместе с синтаксисом упаковки-распаковки.\nОператор * (в Python у него нет фиксированного названия, но часто используют \"оператор распаковки\u002Fупаковки аргументов\") позволяет \"свернуть\" часть элементов во время деструктуризации.\nНапример, с его помощью можно разложить список на первый элемент и все остальные:",[422,25513,25515],{"className":424,"code":25514,"language":396,"meta":426,"style":426},"fruits = [\"apple\", \"orange\", \"banana\", \"pineapple\"]\n# Разделяем первый элемент и оставшиеся элементы\nfirst, *rest = fruits\nprint(first)  # => 'apple'\nprint(rest)  # => ['orange', 'banana', 'pineapple']\n",[428,25516,25517,25546,25551,25566,25575],{"__ignoreMap":426},[431,25518,25519,25522,25524,25526,25529,25531,25534,25536,25539,25541,25544],{"class":433,"line":434},[431,25520,25521],{"class":441},"fruits ",[431,25523,1189],{"class":654},[431,25525,17401],{"class":441},[431,25527,25528],{"class":445},"\"apple\"",[431,25530,4846],{"class":441},[431,25532,25533],{"class":445},"\"orange\"",[431,25535,4846],{"class":441},[431,25537,25538],{"class":445},"\"banana\"",[431,25540,4846],{"class":441},[431,25542,25543],{"class":445},"\"pineapple\"",[431,25545,3568],{"class":441},[431,25547,25548],{"class":433,"line":452},[431,25549,25550],{"class":455},"# Разделяем первый элемент и оставшиеся элементы\n",[431,25552,25553,25556,25558,25561,25563],{"class":433,"line":578},[431,25554,25555],{"class":441},"first, ",[431,25557,1357],{"class":654},[431,25559,25560],{"class":441},"rest ",[431,25562,1189],{"class":654},[431,25564,25565],{"class":441}," fruits\n",[431,25567,25568,25570,25572],{"class":433,"line":584},[431,25569,438],{"class":437},[431,25571,25501],{"class":441},[431,25573,25574],{"class":455},"# => 'apple'\n",[431,25576,25577,25579,25582],{"class":433,"line":1244},[431,25578,438],{"class":437},[431,25580,25581],{"class":441},"(rest)  ",[431,25583,25584],{"class":455},"# => ['orange', 'banana', 'pineapple']\n",[415,25586,25587],{},"Запись *rest означает, что нужно взять все элементы, которые остались от деструктуризации и поместить их в список с именем rest.\nЭтому списку можно дать любое имя. Упаковка срабатывает в самом конце, когда все остальные данные уже разложены по своим переменным.\nИменно поэтому мы и назвали список rest, оставшиеся.\nПодобным образом любой список раскладывается на любое количество элементов + остальные.",[422,25589,25591],{"className":424,"code":25590,"language":396,"meta":426,"style":426},"# Исходный список\nfruits = [\"apple\", \"orange\", \"banana\", \"pineapple\"]\nhead, *tail = fruits\nprint(head)  # => 'apple'\nprint(tail)  # => ['orange', 'banana', 'pineapple']\n# Первый, второй и оставшиеся элементы\nfirst, second, *rest = fruits\nprint(first)  # => 'apple'\nprint(second)  # => 'orange'\nprint(rest)  # => ['banana', 'pineapple']\n# Если элементов нет, то rest окажется пустым списком\nfirst, second, third, one_more, *rest = fruits\nprint(first)  # => 'apple'\nprint(second)  # => 'orange'\nprint(third)  # => 'banana'\nprint(one_more)  # => 'pineapple'\nprint(rest)  # => []\n# Пропуск элемента\nfirst, _, third, *rest = fruits\nprint(first)  # => 'apple'\nprint(third)  # => 'banana'\nprint(rest)  # => ['pineapple']\n# Также можно упаковывать элементы в любом месте списка\n# Первый, последний и оставшиеся центральные элементы\nfirst, *mid, last = fruits\nprint(first)  # => 'apple'\nprint(last)  # => 'pineapple'\nprint(mid)  # => ['orange', 'banana']\n",[428,25592,25593,25598,25622,25636,25645,25654,25659,25672,25680,25690,25699,25704,25717,25725,25733,25743,25753,25761,25766,25779,25787,25795,25804,25809,25814,25827,25836,25846],{"__ignoreMap":426},[431,25594,25595],{"class":433,"line":434},[431,25596,25597],{"class":455},"# Исходный список\n",[431,25599,25600,25602,25604,25606,25608,25610,25612,25614,25616,25618,25620],{"class":433,"line":452},[431,25601,25521],{"class":441},[431,25603,1189],{"class":654},[431,25605,17401],{"class":441},[431,25607,25528],{"class":445},[431,25609,4846],{"class":441},[431,25611,25533],{"class":445},[431,25613,4846],{"class":441},[431,25615,25538],{"class":445},[431,25617,4846],{"class":441},[431,25619,25543],{"class":445},[431,25621,3568],{"class":441},[431,25623,25624,25627,25629,25632,25634],{"class":433,"line":578},[431,25625,25626],{"class":441},"head, ",[431,25628,1357],{"class":654},[431,25630,25631],{"class":441},"tail ",[431,25633,1189],{"class":654},[431,25635,25565],{"class":441},[431,25637,25638,25640,25643],{"class":433,"line":584},[431,25639,438],{"class":437},[431,25641,25642],{"class":441},"(head)  ",[431,25644,25574],{"class":455},[431,25646,25647,25649,25652],{"class":433,"line":1244},[431,25648,438],{"class":437},[431,25650,25651],{"class":441},"(tail)  ",[431,25653,25584],{"class":455},[431,25655,25656],{"class":433,"line":1985},[431,25657,25658],{"class":455},"# Первый, второй и оставшиеся элементы\n",[431,25660,25661,25664,25666,25668,25670],{"class":433,"line":2041},[431,25662,25663],{"class":441},"first, second, ",[431,25665,1357],{"class":654},[431,25667,25560],{"class":441},[431,25669,1189],{"class":654},[431,25671,25565],{"class":441},[431,25673,25674,25676,25678],{"class":433,"line":4018},[431,25675,438],{"class":437},[431,25677,25501],{"class":441},[431,25679,25574],{"class":455},[431,25681,25682,25684,25687],{"class":433,"line":4030},[431,25683,438],{"class":437},[431,25685,25686],{"class":441},"(second)  ",[431,25688,25689],{"class":455},"# => 'orange'\n",[431,25691,25692,25694,25696],{"class":433,"line":4419},[431,25693,438],{"class":437},[431,25695,25581],{"class":441},[431,25697,25698],{"class":455},"# => ['banana', 'pineapple']\n",[431,25700,25701],{"class":433,"line":4436},[431,25702,25703],{"class":455},"# Если элементов нет, то rest окажется пустым списком\n",[431,25705,25706,25709,25711,25713,25715],{"class":433,"line":4446},[431,25707,25708],{"class":441},"first, second, third, one_more, ",[431,25710,1357],{"class":654},[431,25712,25560],{"class":441},[431,25714,1189],{"class":654},[431,25716,25565],{"class":441},[431,25718,25719,25721,25723],{"class":433,"line":4451},[431,25720,438],{"class":437},[431,25722,25501],{"class":441},[431,25724,25574],{"class":455},[431,25726,25727,25729,25731],{"class":433,"line":4086},[431,25728,438],{"class":437},[431,25730,25686],{"class":441},[431,25732,25689],{"class":455},[431,25734,25735,25737,25740],{"class":433,"line":4477},[431,25736,438],{"class":437},[431,25738,25739],{"class":441},"(third)  ",[431,25741,25742],{"class":455},"# => 'banana'\n",[431,25744,25745,25747,25750],{"class":433,"line":4482},[431,25746,438],{"class":437},[431,25748,25749],{"class":441},"(one_more)  ",[431,25751,25752],{"class":455},"# => 'pineapple'\n",[431,25754,25755,25757,25759],{"class":433,"line":4488},[431,25756,438],{"class":437},[431,25758,25581],{"class":441},[431,25760,21102],{"class":455},[431,25762,25763],{"class":433,"line":4505},[431,25764,25765],{"class":455},"# Пропуск элемента\n",[431,25767,25768,25771,25773,25775,25777],{"class":433,"line":12871},[431,25769,25770],{"class":441},"first, _, third, ",[431,25772,1357],{"class":654},[431,25774,25560],{"class":441},[431,25776,1189],{"class":654},[431,25778,25565],{"class":441},[431,25780,25781,25783,25785],{"class":433,"line":2874},[431,25782,438],{"class":437},[431,25784,25501],{"class":441},[431,25786,25574],{"class":455},[431,25788,25789,25791,25793],{"class":433,"line":12887},[431,25790,438],{"class":437},[431,25792,25739],{"class":441},[431,25794,25742],{"class":455},[431,25796,25797,25799,25801],{"class":433,"line":12892},[431,25798,438],{"class":437},[431,25800,25581],{"class":441},[431,25802,25803],{"class":455},"# => ['pineapple']\n",[431,25805,25806],{"class":433,"line":12898},[431,25807,25808],{"class":455},"# Также можно упаковывать элементы в любом месте списка\n",[431,25810,25811],{"class":433,"line":12904},[431,25812,25813],{"class":455},"# Первый, последний и оставшиеся центральные элементы\n",[431,25815,25816,25818,25820,25823,25825],{"class":433,"line":8382},[431,25817,25555],{"class":441},[431,25819,1357],{"class":654},[431,25821,25822],{"class":441},"mid, last ",[431,25824,1189],{"class":654},[431,25826,25565],{"class":441},[431,25828,25830,25832,25834],{"class":433,"line":25829},26,[431,25831,438],{"class":437},[431,25833,25501],{"class":441},[431,25835,25574],{"class":455},[431,25837,25839,25841,25844],{"class":433,"line":25838},27,[431,25840,438],{"class":437},[431,25842,25843],{"class":441},"(last)  ",[431,25845,25752],{"class":455},[431,25847,25848,25850,25853],{"class":433,"line":1890},[431,25849,438],{"class":437},[431,25851,25852],{"class":441},"(mid)  ",[431,25854,25855],{"class":455},"# => ['orange', 'banana']\n",[415,25857,25858],{},"В ситуациях, когда нас интересует только часть списка, но не важны первые элементы, лучше воспользоваться срезом:",[422,25860,25862],{"className":424,"code":25861,"language":396,"meta":426,"style":426},"# Исходный список\nfruits = [\"apple\", \"orange\", \"banana\", \"pineapple\"]\n# Срез списка, начиная с элемента с индексом 1\nrest = fruits[1:]\nprint(rest)  # ['orange', 'banana', 'pineapple']\n",[428,25863,25864,25868,25892,25897,25911],{"__ignoreMap":426},[431,25865,25866],{"class":433,"line":434},[431,25867,25597],{"class":455},[431,25869,25870,25872,25874,25876,25878,25880,25882,25884,25886,25888,25890],{"class":433,"line":452},[431,25871,25521],{"class":441},[431,25873,1189],{"class":654},[431,25875,17401],{"class":441},[431,25877,25528],{"class":445},[431,25879,4846],{"class":441},[431,25881,25533],{"class":445},[431,25883,4846],{"class":441},[431,25885,25538],{"class":445},[431,25887,4846],{"class":441},[431,25889,25543],{"class":445},[431,25891,3568],{"class":441},[431,25893,25894],{"class":433,"line":578},[431,25895,25896],{"class":455},"# Срез списка, начиная с элемента с индексом 1\n",[431,25898,25899,25901,25903,25906,25908],{"class":433,"line":584},[431,25900,25560],{"class":441},[431,25902,1189],{"class":654},[431,25904,25905],{"class":441}," fruits[",[431,25907,1192],{"class":437},[431,25909,25910],{"class":441},":]\n",[431,25912,25913,25915,25917],{"class":433,"line":1244},[431,25914,438],{"class":437},[431,25916,25581],{"class":441},[431,25918,25919],{"class":455},"# ['orange', 'banana', 'pineapple']\n",[415,25921,25922],{},"Синтаксис упаковки можно применять также и при деструктуризации строк.",[422,25924,25926],{"className":424,"code":25925,"language":396,"meta":426,"style":426},"string = \"some string\"\nfirst, second, *rest = string\nprint(first)  # => 's'\nprint(second)  # => 'o'\nprint(rest)  # => ['m', 'e', ' ', 's', 't', 'r', 'i', 'n', 'g']\n",[428,25927,25928,25937,25949,25958,25967],{"__ignoreMap":426},[431,25929,25930,25932,25934],{"class":433,"line":434},[431,25931,14072],{"class":441},[431,25933,1189],{"class":654},[431,25935,25936],{"class":445}," \"some string\"\n",[431,25938,25939,25941,25943,25945,25947],{"class":433,"line":452},[431,25940,25663],{"class":441},[431,25942,1357],{"class":654},[431,25944,25560],{"class":441},[431,25946,1189],{"class":654},[431,25948,8999],{"class":441},[431,25950,25951,25953,25955],{"class":433,"line":578},[431,25952,438],{"class":437},[431,25954,25501],{"class":441},[431,25956,25957],{"class":455},"# => 's'\n",[431,25959,25960,25962,25964],{"class":433,"line":584},[431,25961,438],{"class":437},[431,25963,25686],{"class":441},[431,25965,25966],{"class":455},"# => 'o'\n",[431,25968,25969,25971,25973],{"class":433,"line":1244},[431,25970,438],{"class":437},[431,25972,25581],{"class":441},[431,25974,25975],{"class":455},"# => ['m', 'e', ' ', 's', 't', 'r', 'i', 'n', 'g']\n",[415,25977,25978],{},"Обратите внимание, что после упаковки оставшейся части строки в rest мы получаем список, а не строку.\nДеструктуризация в Python позволяет эффективно разделять элементы коллекций на отдельные переменные и собирать оставшиеся элементы в список с помощью синтаксиса оператора упаковки аргументов - *.\nЭто удобно для работы с данными, когда нужно отделить часть элементов от остальных.\nСинтаксис * можно использовать для разделения коллекций на фиксированное количество элементов и оставшиеся.",[632,25980,25982],{"id":25981},"оператор-распаковки","Оператор распаковки",[415,25984,25985],{},"У оператора упаковки есть вторая функциональность - распаковка. Она имеет такой же синтаксис, но выполняет противоположную задачу: не сворачивает элементы, а наоборот, растягивает их.\nС ее помощью обычно копируют или соединяют списки.\nПредставьте, что нам нужно определить список, добавив туда элементы из другого списка.\nТакая задача часто встречается при работе со значениями по умолчанию:",[422,25987,25989],{"className":424,"code":25988,"language":396,"meta":426,"style":426},"# Исходные списки\nfrench_cities = [\"paris\", \"marseille\"]\ncities = [\"milan\", \"rome\", *french_cities]\nprint(cities)  # => ['milan', 'rome', 'paris', 'marseille']\n",[428,25990,25991,25996,26015,26039],{"__ignoreMap":426},[431,25992,25993],{"class":433,"line":434},[431,25994,25995],{"class":455},"# Исходные списки\n",[431,25997,25998,26001,26003,26005,26008,26010,26013],{"class":433,"line":452},[431,25999,26000],{"class":441},"french_cities ",[431,26002,1189],{"class":654},[431,26004,17401],{"class":441},[431,26006,26007],{"class":445},"\"paris\"",[431,26009,4846],{"class":441},[431,26011,26012],{"class":445},"\"marseille\"",[431,26014,3568],{"class":441},[431,26016,26017,26020,26022,26024,26027,26029,26032,26034,26036],{"class":433,"line":578},[431,26018,26019],{"class":441},"cities ",[431,26021,1189],{"class":654},[431,26023,17401],{"class":441},[431,26025,26026],{"class":445},"\"milan\"",[431,26028,4846],{"class":441},[431,26030,26031],{"class":445},"\"rome\"",[431,26033,4846],{"class":441},[431,26035,1357],{"class":654},[431,26037,26038],{"class":441},"french_cities]\n",[431,26040,26041,26043,26046],{"class":433,"line":584},[431,26042,438],{"class":437},[431,26044,26045],{"class":441},"(cities)  ",[431,26047,26048],{"class":455},"# => ['milan', 'rome', 'paris', 'marseille']\n",[415,26050,26051],{},"В этом случае * — это распаковка. Оператор растянул список, добавив все его элементы в новый список.\nКак понять какая функциональность используется? Все дело в контексте использования.\nЕсли * появляется слева от знака равно, то происходит упаковка в переменные.\nЕсли * стоит справа от знака равно, то происходит упаковка в список.",[422,26053,26055],{"className":424,"code":26054,"language":396,"meta":426,"style":426},"# Исходные списки\nfrench_cities = [\"paris\", \"marseille\"]\ncities = [*french_cities, \"milan\", \"rome\"]\nprint(cities)  # => ['paris', 'marseille', 'milan', 'rome']\nfrench_cities = [\"paris\", \"marseille\"]\ncities = [\"milan\", *french_cities, \"rome\"]\nprint(cities)  # => ['milan', 'paris', 'marseille', 'rome']\n",[428,26056,26057,26061,26077,26098,26107,26123,26143],{"__ignoreMap":426},[431,26058,26059],{"class":433,"line":434},[431,26060,25995],{"class":455},[431,26062,26063,26065,26067,26069,26071,26073,26075],{"class":433,"line":452},[431,26064,26000],{"class":441},[431,26066,1189],{"class":654},[431,26068,17401],{"class":441},[431,26070,26007],{"class":445},[431,26072,4846],{"class":441},[431,26074,26012],{"class":445},[431,26076,3568],{"class":441},[431,26078,26079,26081,26083,26085,26087,26090,26092,26094,26096],{"class":433,"line":578},[431,26080,26019],{"class":441},[431,26082,1189],{"class":654},[431,26084,17401],{"class":441},[431,26086,1357],{"class":654},[431,26088,26089],{"class":441},"french_cities, ",[431,26091,26026],{"class":445},[431,26093,4846],{"class":441},[431,26095,26031],{"class":445},[431,26097,3568],{"class":441},[431,26099,26100,26102,26104],{"class":433,"line":584},[431,26101,438],{"class":437},[431,26103,26045],{"class":441},[431,26105,26106],{"class":455},"# => ['paris', 'marseille', 'milan', 'rome']\n",[431,26108,26109,26111,26113,26115,26117,26119,26121],{"class":433,"line":1244},[431,26110,26000],{"class":441},[431,26112,1189],{"class":654},[431,26114,17401],{"class":441},[431,26116,26007],{"class":445},[431,26118,4846],{"class":441},[431,26120,26012],{"class":445},[431,26122,3568],{"class":441},[431,26124,26125,26127,26129,26131,26133,26135,26137,26139,26141],{"class":433,"line":1985},[431,26126,26019],{"class":441},[431,26128,1189],{"class":654},[431,26130,17401],{"class":441},[431,26132,26026],{"class":445},[431,26134,4846],{"class":441},[431,26136,1357],{"class":654},[431,26138,26089],{"class":441},[431,26140,26031],{"class":445},[431,26142,3568],{"class":441},[431,26144,26145,26147,26149],{"class":433,"line":2041},[431,26146,438],{"class":437},[431,26148,26045],{"class":441},[431,26150,26151],{"class":455},"# => ['milan', 'paris', 'marseille', 'rome']\n",[415,26153,26154],{},"* работает с любым количеством списков:",[422,26156,26158],{"className":424,"code":26157,"language":396,"meta":426,"style":426},"# Исходные списки\nfrench_cities = [\"paris\", \"marseille\"]\nitalian_cities = [\"rome\", \"milan\"]\n# Объединение списков с использованием *\ncities = [*french_cities, *italian_cities]\nprint(cities)  # ['paris', 'marseille', 'rome', 'milan']\n",[428,26159,26160,26164,26180,26197,26202,26219],{"__ignoreMap":426},[431,26161,26162],{"class":433,"line":434},[431,26163,25995],{"class":455},[431,26165,26166,26168,26170,26172,26174,26176,26178],{"class":433,"line":452},[431,26167,26000],{"class":441},[431,26169,1189],{"class":654},[431,26171,17401],{"class":441},[431,26173,26007],{"class":445},[431,26175,4846],{"class":441},[431,26177,26012],{"class":445},[431,26179,3568],{"class":441},[431,26181,26182,26185,26187,26189,26191,26193,26195],{"class":433,"line":578},[431,26183,26184],{"class":441},"italian_cities ",[431,26186,1189],{"class":654},[431,26188,17401],{"class":441},[431,26190,26031],{"class":445},[431,26192,4846],{"class":441},[431,26194,26026],{"class":445},[431,26196,3568],{"class":441},[431,26198,26199],{"class":433,"line":584},[431,26200,26201],{"class":455},"# Объединение списков с использованием *\n",[431,26203,26204,26206,26208,26210,26212,26214,26216],{"class":433,"line":1244},[431,26205,26019],{"class":441},[431,26207,1189],{"class":654},[431,26209,17401],{"class":441},[431,26211,1357],{"class":654},[431,26213,26089],{"class":441},[431,26215,1357],{"class":654},[431,26217,26218],{"class":441},"italian_cities]\n",[431,26220,26221,26223,26225],{"class":433,"line":1985},[431,26222,438],{"class":437},[431,26224,26045],{"class":441},[431,26226,26227],{"class":455},"# ['paris', 'marseille', 'rome', 'milan']\n",[415,26229,1849,26230,1853,26232,1857],{},[800,26231,1852],{},[800,26233,1856],{},[1859,26235],{},[1862,26237,26238],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sB1qb, html code.shiki .sB1qb{--shiki-default:#B31D28;--shiki-default-font-style:italic}html pre.shiki code .sdV6q, html code.shiki .sdV6q{--shiki-default:#005CC5;--shiki-default-font-style:italic}",{"title":426,"searchDepth":452,"depth":1244,"links":26240},[26241],{"id":24280,"depth":452,"text":222,"children":26242},[26243,26251,26255,26256],{"id":24283,"depth":578,"text":24284,"children":26244},[26245],{"id":24290,"depth":584,"text":24291,"children":26246},[26247,26248,26249,26250],{"id":24470,"depth":1244,"text":24471},{"id":24630,"depth":1244,"text":24631},{"id":24892,"depth":1244,"text":24893},{"id":25007,"depth":1244,"text":25008},{"id":25184,"depth":578,"text":25185,"children":26252},[26253,26254],{"id":25381,"depth":584,"text":25382},{"id":25475,"depth":584,"text":25476},{"id":25507,"depth":578,"text":25508},{"id":25981,"depth":578,"text":25982},"2025-04-26","Срезы, де-структуризация списков. Операторы упаковки и распаковки","images\u002Fblog\u002Fpython\u002Fst17\u002Fimg.png",{},{"title":222,"description":26258},"9ddkRIBcrpXCG-Eco4EHr2p4K8qqSro4USjjKW3C_1s",{"id":26264,"title":226,"author":26265,"body":26267,"date":27733,"description":27734,"extension":1887,"image":27735,"meta":27736,"minRead":4505,"navigation":393,"num":4505,"path":227,"seo":27737,"stem":228,"__hash__":27738},"python\u002Fblog\u002Fpython\u002Fst18.md",{"name":402,"avatar":26266},{"src":404,"alt":405},{"type":407,"value":26268,"toc":27712},[26269,26273,26275,26278,26284,26384,26387,26415,26419,26426,26455,26458,26461,26487,26490,26517,26523,26566,26572,26576,26579,26631,26637,26669,26675,26706,26712,26758,26762,26769,26843,26846,26850,26853,26914,26921,26981,26991,27027,27030,27038,27042,27056,27064,27067,27138,27141,27145,27148,27156,27163,27263,27273,27277,27286,27292,27327,27331,27334,27373,27379,27382,27387,27396,27401,27408,27424,27496,27508,27518,27536,27555,27635,27641,27650,27653,27656,27659,27662,27665,27668,27676,27686,27701,27707,27709],[410,26270,26272],{"id":26271},"использование-словарей","Использование словарей",[632,26274,17446],{"id":17445},[415,26276,26277],{},"Как и другие встроенные коллекции, словари поддерживаются языком и имеют собственный синтаксис для описания литералов.",[415,26279,26280,26283],{},[1355,26281,26282],{},"Литерал словаря"," записывается в фигурных скобках.\nПары «ключ-значение» разделяются запятыми, а ключ отделяется от значения двоеточием:",[422,26285,26287],{"className":424,"code":26286,"language":396,"meta":426,"style":426},"dictionary = {\n    \"one\": \"1\",\n    \"two\": 2,\n    \"items\": {1: \"apple\", 2: \"orange\", 3: \"grape\"},\n    True: \"Python\n    \",\n}\ndictionary  # {'one': '1', 'two': 2, 'items': {1: 'apple', 2: 'orange', 3: 'grape'}, True: 'Python'}\n",[428,26288,26289,26299,26312,26323,26357,26367,26372,26376],{"__ignoreMap":426},[431,26290,26291,26294,26296],{"class":433,"line":434},[431,26292,26293],{"class":441},"dictionary ",[431,26295,1189],{"class":654},[431,26297,26298],{"class":441}," {\n",[431,26300,26301,26304,26307,26310],{"class":433,"line":452},[431,26302,26303],{"class":445},"    \"one\"",[431,26305,26306],{"class":441},": ",[431,26308,26309],{"class":445},"\"1\"",[431,26311,22541],{"class":441},[431,26313,26314,26317,26319,26321],{"class":433,"line":578},[431,26315,26316],{"class":445},"    \"two\"",[431,26318,26306],{"class":441},[431,26320,651],{"class":437},[431,26322,22541],{"class":441},[431,26324,26325,26328,26331,26333,26335,26337,26339,26341,26343,26345,26347,26349,26351,26354],{"class":433,"line":584},[431,26326,26327],{"class":445},"    \"items\"",[431,26329,26330],{"class":441},": {",[431,26332,1192],{"class":437},[431,26334,26306],{"class":441},[431,26336,25528],{"class":445},[431,26338,4846],{"class":441},[431,26340,651],{"class":437},[431,26342,26306],{"class":441},[431,26344,25533],{"class":445},[431,26346,4846],{"class":441},[431,26348,971],{"class":437},[431,26350,26306],{"class":441},[431,26352,26353],{"class":445},"\"grape\"",[431,26355,26356],{"class":441},"},\n",[431,26358,26359,26362,26364],{"class":433,"line":1244},[431,26360,26361],{"class":437},"    True",[431,26363,26306],{"class":441},[431,26365,26366],{"class":445},"\"Python\n",[431,26368,26369],{"class":433,"line":1985},[431,26370,26371],{"class":445},"    \",\n",[431,26373,26374],{"class":433,"line":2041},[431,26375,3236],{"class":441},[431,26377,26378,26381],{"class":433,"line":4018},[431,26379,26380],{"class":441},"dictionary  ",[431,26382,26383],{"class":455},"# {'one': '1', 'two': 2, 'items': {1: 'apple', 2: 'orange', 3: 'grape'}, True: 'Python'}\n",[415,26385,26386],{},"В этом примере есть и ключи-строки, и ключи-числа, и вложенные словари.\nИ конечно же, здесь есть переменные, которые могут выступать в роли значений и ключей:",[422,26388,26390],{"className":424,"code":26389,"language":396,"meta":426,"style":426},"key, val = \"x\", 3\n{key: val}  # {'x': 3}\n",[428,26391,26392,26407],{"__ignoreMap":426},[431,26393,26394,26397,26399,26402,26404],{"class":433,"line":434},[431,26395,26396],{"class":441},"key, val ",[431,26398,1189],{"class":654},[431,26400,26401],{"class":445}," \"x\"",[431,26403,4846],{"class":441},[431,26405,26406],{"class":437},"3\n",[431,26408,26409,26412],{"class":433,"line":452},[431,26410,26411],{"class":441},"{key: val}  ",[431,26413,26414],{"class":455},"# {'x': 3}\n",[458,26416,26418],{"id":26417},"доступ-по-ключу","Доступ по ключу",[415,26420,26421,26422,26425],{},"Выше мы объявили словарь ",[428,26423,26424],{},"dictionary",". Запросить у него значение по ключу можно так:",[422,26427,26429],{"className":424,"code":26428,"language":396,"meta":426,"style":426},"dictionary[\"two\"]  # 2\ndictionary[\"four\"]  # KeyError: 'four'\n",[428,26430,26431,26443],{"__ignoreMap":426},[431,26432,26433,26436,26439,26441],{"class":433,"line":434},[431,26434,26435],{"class":441},"dictionary[",[431,26437,26438],{"class":445},"\"two\"",[431,26440,3612],{"class":441},[431,26442,5652],{"class":455},[431,26444,26445,26447,26450,26452],{"class":433,"line":452},[431,26446,26435],{"class":441},[431,26448,26449],{"class":445},"\"four\"",[431,26451,3612],{"class":441},[431,26453,26454],{"class":455},"# KeyError: 'four'\n",[415,26456,26457],{},"Ключа \"four\" в dictionary нет, поэтому выбросилось исключение KeyError — аналог IndexError для списков.",[415,26459,26460],{},"Проверить наличие ключа в словаре можно с помощью привычного оператора in:",[422,26462,26464],{"className":424,"code":26463,"language":396,"meta":426,"style":426},"\"two\" in dictionary  # True\n\"four\" in dictionary  # False\n",[428,26465,26466,26477],{"__ignoreMap":426},[431,26467,26468,26470,26472,26475],{"class":433,"line":434},[431,26469,26438],{"class":445},[431,26471,21531],{"class":654},[431,26473,26474],{"class":441}," dictionary  ",[431,26476,19945],{"class":455},[431,26478,26479,26481,26483,26485],{"class":433,"line":452},[431,26480,26449],{"class":445},[431,26482,21531],{"class":654},[431,26484,26474],{"class":441},[431,26486,20020],{"class":455},[415,26488,26489],{},"Если вы захотите получить значение по ключу, которого может и не быть, можно сделать это так:",[422,26491,26493],{"className":424,"code":26492,"language":396,"meta":426,"style":426},"dictionary[\"four\"] if \"four\" in dictionary else None\n",[428,26494,26495],{"__ignoreMap":426},[431,26496,26497,26499,26501,26503,26505,26508,26510,26513,26515],{"class":433,"line":434},[431,26498,26435],{"class":441},[431,26500,26449],{"class":445},[431,26502,4049],{"class":441},[431,26504,10399],{"class":654},[431,26506,26507],{"class":445}," \"four\"",[431,26509,21531],{"class":654},[431,26511,26512],{"class":441}," dictionary ",[431,26514,10515],{"class":654},[431,26516,11872],{"class":437},[415,26518,26519,26520,3562],{},"Подобный безопасный запрос элементов нужен довольно часто.\nПоэтому объект словаря имеет для этого специальный метод ",[428,26521,26522],{},".get",[422,26524,26526],{"className":424,"code":26525,"language":396,"meta":426,"style":426},"dictionary.get(\"two\")  # 42\ndictionary.get(\"four\")  # Вернет None\ndictionary.get(\"four\", \"no such key\")  # 'no such key'\n",[428,26527,26528,26539,26550],{"__ignoreMap":426},[431,26529,26530,26533,26535,26537],{"class":433,"line":434},[431,26531,26532],{"class":441},"dictionary.get(",[431,26534,26438],{"class":445},[431,26536,526],{"class":441},[431,26538,16948],{"class":455},[431,26540,26541,26543,26545,26547],{"class":433,"line":452},[431,26542,26532],{"class":441},[431,26544,26449],{"class":445},[431,26546,526],{"class":441},[431,26548,26549],{"class":455},"# Вернет None\n",[431,26551,26552,26554,26556,26558,26561,26563],{"class":433,"line":578},[431,26553,26532],{"class":441},[431,26555,26449],{"class":445},[431,26557,4846],{"class":441},[431,26559,26560],{"class":445},"\"no such key\"",[431,26562,526],{"class":441},[431,26564,26565],{"class":455},"# 'no such key'\n",[415,26567,26568,26569,26571],{},"Третий вызов метода показывает, как можно явно задать значение по умолчанию.\nЕсли его не указывать, метод вернет ",[800,26570,7922],{}," при отсутствии значения по указанному ключу.",[458,26573,26575],{"id":26574},"методы-keys-values-и-items","Методы keys, values и items",[415,26577,26578],{},"Если попробовать проитерировать словарь, то мы получим перечень ключей:",[422,26580,26582],{"className":424,"code":26581,"language":396,"meta":426,"style":426},"for k in {\"a\": 1, \"b\": 2}:\n    print(k)\n# => a\n# => b\n",[428,26583,26584,26614,26621,26626],{"__ignoreMap":426},[431,26585,26586,26588,26591,26593,26595,26598,26600,26602,26604,26607,26609,26611],{"class":433,"line":434},[431,26587,14329],{"class":654},[431,26589,26590],{"class":441}," k ",[431,26592,14421],{"class":654},[431,26594,3005],{"class":441},[431,26596,26597],{"class":445},"\"a\"",[431,26599,26306],{"class":441},[431,26601,1192],{"class":437},[431,26603,4846],{"class":441},[431,26605,26606],{"class":445},"\"b\"",[431,26608,26306],{"class":441},[431,26610,651],{"class":437},[431,26612,26613],{"class":441},"}:\n",[431,26615,26616,26618],{"class":433,"line":452},[431,26617,6357],{"class":437},[431,26619,26620],{"class":441},"(k)\n",[431,26622,26623],{"class":433,"line":578},[431,26624,26625],{"class":455},"# => a\n",[431,26627,26628],{"class":433,"line":584},[431,26629,26630],{"class":455},"# => b\n",[415,26632,26633,26634,3562],{},"Этого же результата можно добиться и более явно. Для этого нужно вызвать метод ",[428,26635,26636],{},".keys()",[422,26638,26640],{"className":424,"code":26639,"language":396,"meta":426,"style":426},"print({\"a\": 1, \"b\": 2}.keys())  # dict_keys(['a', 'b'])\n",[428,26641,26642],{"__ignoreMap":426},[431,26643,26644,26646,26649,26651,26653,26655,26657,26659,26661,26663,26666],{"class":433,"line":434},[431,26645,438],{"class":437},[431,26647,26648],{"class":441},"({",[431,26650,26597],{"class":445},[431,26652,26306],{"class":441},[431,26654,1192],{"class":437},[431,26656,4846],{"class":441},[431,26658,26606],{"class":445},[431,26660,26306],{"class":441},[431,26662,651],{"class":437},[431,26664,26665],{"class":441},"}.keys())  ",[431,26667,26668],{"class":455},"# dict_keys(['a', 'b'])\n",[415,26670,26671,26672,3562],{},"Чтобы получить значения, нужно вызвать метод ",[428,26673,26674],{},".values()",[422,26676,26678],{"className":424,"code":26677,"language":396,"meta":426,"style":426},"print({\"a\": 1, \"b\": 2}.values())  # dict_values([1, 2])\n",[428,26679,26680],{"__ignoreMap":426},[431,26681,26682,26684,26686,26688,26690,26692,26694,26696,26698,26700,26703],{"class":433,"line":434},[431,26683,438],{"class":437},[431,26685,26648],{"class":441},[431,26687,26597],{"class":445},[431,26689,26306],{"class":441},[431,26691,1192],{"class":437},[431,26693,4846],{"class":441},[431,26695,26606],{"class":445},[431,26697,26306],{"class":441},[431,26699,651],{"class":437},[431,26701,26702],{"class":441},"}.values())  ",[431,26704,26705],{"class":455},"# dict_values([1, 2])\n",[415,26707,26708,26709,3562],{},"Чтобы получить одновременно и ключи, и соответствующие значения, можно вызвать метод ",[428,26710,26711],{},".items()",[422,26713,26715],{"className":424,"code":26714,"language":396,"meta":426,"style":426},"for k, v in {\"a\": 1, \"b\": 2}.items():\n    print(k, \"=\", v)\n",[428,26716,26717,26745],{"__ignoreMap":426},[431,26718,26719,26721,26724,26726,26728,26730,26732,26734,26736,26738,26740,26742],{"class":433,"line":434},[431,26720,14329],{"class":654},[431,26722,26723],{"class":441}," k, v ",[431,26725,14421],{"class":654},[431,26727,3005],{"class":441},[431,26729,26597],{"class":445},[431,26731,26306],{"class":441},[431,26733,1192],{"class":437},[431,26735,4846],{"class":441},[431,26737,26606],{"class":445},[431,26739,26306],{"class":441},[431,26741,651],{"class":437},[431,26743,26744],{"class":441},"}.items():\n",[431,26746,26747,26749,26752,26755],{"class":433,"line":452},[431,26748,6357],{"class":437},[431,26750,26751],{"class":441},"(k, ",[431,26753,26754],{"class":445},"\"=\"",[431,26756,26757],{"class":441},", v)\n",[632,26759,26761],{"id":26760},"изменение-данных-в-словаре","Изменение данных в словаре",[415,26763,26764,26765,26768],{},"Словарь в Python — изменяемый или mutable.\nНо для добавления новой пары «ключ-значение» не нужны отдельные методы, вроде спискового метода ",[428,26766,26767],{},".append"," — достаточно обычного присваивания:",[422,26770,26772],{"className":424,"code":26771,"language":396,"meta":426,"style":426},"d = {}  # пустой словарь\nd[\"a\"] = 1\nprint(d)  # => {\"a\": 1}\nd[\"b\"] = 2\nd[\"a\"] = 0\nprint(d)  # => {\"a\": 0, \"b\": 2}\n",[428,26773,26774,26787,26800,26810,26822,26834],{"__ignoreMap":426},[431,26775,26776,26779,26781,26784],{"class":433,"line":434},[431,26777,26778],{"class":441},"d ",[431,26780,1189],{"class":654},[431,26782,26783],{"class":441}," {}  ",[431,26785,26786],{"class":455},"# пустой словарь\n",[431,26788,26789,26792,26794,26796,26798],{"class":433,"line":452},[431,26790,26791],{"class":441},"d[",[431,26793,26597],{"class":445},[431,26795,4049],{"class":441},[431,26797,1189],{"class":654},[431,26799,3916],{"class":437},[431,26801,26802,26804,26807],{"class":433,"line":578},[431,26803,438],{"class":437},[431,26805,26806],{"class":441},"(d)  ",[431,26808,26809],{"class":455},"# => {\"a\": 1}\n",[431,26811,26812,26814,26816,26818,26820],{"class":433,"line":584},[431,26813,26791],{"class":441},[431,26815,26606],{"class":445},[431,26817,4049],{"class":441},[431,26819,1189],{"class":654},[431,26821,658],{"class":437},[431,26823,26824,26826,26828,26830,26832],{"class":433,"line":1244},[431,26825,26791],{"class":441},[431,26827,26597],{"class":445},[431,26829,4049],{"class":441},[431,26831,1189],{"class":654},[431,26833,3459],{"class":437},[431,26835,26836,26838,26840],{"class":433,"line":1985},[431,26837,438],{"class":437},[431,26839,26806],{"class":441},[431,26841,26842],{"class":455},"# => {\"a\": 0, \"b\": 2}\n",[415,26844,26845],{},"Здесь вы можете увидеть, что присваивание значения новому ключу выглядит точно так же, как и присваивание существующему.",[458,26847,26849],{"id":26848},"метод-pop","Метод pop",[415,26851,26852],{},"Удаление элементов из словаря можно сделать с помощью метода pop — в этом словарь уже больше похож на список.\nТолько вместо индекса используется ключ:",[422,26854,26856],{"className":424,"code":26855,"language":396,"meta":426,"style":426},"d = {\"a\": 0, \"b\": 2}\nd.pop(\"a\")  # 0\nprint(d)  # {\"b\": 2}\nd.pop(\"c\")  # KeyError: \"c\"\n",[428,26857,26858,26882,26893,26902],{"__ignoreMap":426},[431,26859,26860,26862,26864,26866,26868,26870,26872,26874,26876,26878,26880],{"class":433,"line":434},[431,26861,26778],{"class":441},[431,26863,1189],{"class":654},[431,26865,3005],{"class":441},[431,26867,26597],{"class":445},[431,26869,26306],{"class":441},[431,26871,3302],{"class":437},[431,26873,4846],{"class":441},[431,26875,26606],{"class":445},[431,26877,26306],{"class":441},[431,26879,651],{"class":437},[431,26881,3236],{"class":441},[431,26883,26884,26887,26889,26891],{"class":433,"line":452},[431,26885,26886],{"class":441},"d.pop(",[431,26888,26597],{"class":445},[431,26890,526],{"class":441},[431,26892,13922],{"class":455},[431,26894,26895,26897,26899],{"class":433,"line":578},[431,26896,438],{"class":437},[431,26898,26806],{"class":441},[431,26900,26901],{"class":455},"# {\"b\": 2}\n",[431,26903,26904,26906,26909,26911],{"class":433,"line":584},[431,26905,26886],{"class":441},[431,26907,26908],{"class":445},"\"c\"",[431,26910,526],{"class":441},[431,26912,26913],{"class":455},"# KeyError: \"c\"\n",[415,26915,26916,26917,26920],{},"Этот пример показывает, что будет, если попытаться извлечь значение по несуществующему ключу — мы получим исключение.\nОднако метод ",[428,26918,26919],{},"pop"," можно вызывать с указанием значения по умолчанию.\nВ этом случае при отсутствии ключа в словаре будет возвращено это самое значение, а исключение \"выброшено\" не будет:",[422,26922,26924],{"className":424,"code":26923,"language":396,"meta":426,"style":426},"d = {\"a\": 1, \"b\": 2}\nd.pop(\"3\", None)  # None\nd.pop(\"3\", 33)  # 33\n",[428,26925,26926,26950,26965],{"__ignoreMap":426},[431,26927,26928,26930,26932,26934,26936,26938,26940,26942,26944,26946,26948],{"class":433,"line":434},[431,26929,26778],{"class":441},[431,26931,1189],{"class":654},[431,26933,3005],{"class":441},[431,26935,26597],{"class":445},[431,26937,26306],{"class":441},[431,26939,1192],{"class":437},[431,26941,4846],{"class":441},[431,26943,26606],{"class":445},[431,26945,26306],{"class":441},[431,26947,651],{"class":437},[431,26949,3236],{"class":441},[431,26951,26952,26954,26957,26959,26961,26963],{"class":433,"line":452},[431,26953,26886],{"class":441},[431,26955,26956],{"class":445},"\"3\"",[431,26958,4846],{"class":441},[431,26960,7922],{"class":437},[431,26962,526],{"class":441},[431,26964,18195],{"class":455},[431,26966,26967,26969,26971,26973,26976,26978],{"class":433,"line":578},[431,26968,26886],{"class":441},[431,26970,26956],{"class":445},[431,26972,4846],{"class":441},[431,26974,26975],{"class":437},"33",[431,26977,526],{"class":441},[431,26979,26980],{"class":455},"# 33\n",[415,26982,26983,26984,26986,26987,26990],{},"Аналогом спискового ",[428,26985,26919],{}," без аргументов для словаря служит метод ",[428,26988,26989],{},"popitem",".\nЭтот метод извлекает ключ и значение в виде кортежа, а если словарь уже пуст, то \"выбрасывает\" исключение:",[422,26992,26994],{"className":424,"code":26993,"language":396,"meta":426,"style":426},"d = {\"a\": 1}\nd.popitem()  # (\"a\", 1)\nd.popitem()  # KeyError: \"popitem(): dictionary is empty\"\n",[428,26995,26996,27012,27020],{"__ignoreMap":426},[431,26997,26998,27000,27002,27004,27006,27008,27010],{"class":433,"line":434},[431,26999,26778],{"class":441},[431,27001,1189],{"class":654},[431,27003,3005],{"class":441},[431,27005,26597],{"class":445},[431,27007,26306],{"class":441},[431,27009,1192],{"class":437},[431,27011,3236],{"class":441},[431,27013,27014,27017],{"class":433,"line":452},[431,27015,27016],{"class":441},"d.popitem()  ",[431,27018,27019],{"class":455},"# (\"a\", 1)\n",[431,27021,27022,27024],{"class":433,"line":578},[431,27023,27016],{"class":441},[431,27025,27026],{"class":455},"# KeyError: \"popitem(): dictionary is empty\"\n",[415,27028,27029],{},"В Python, начиная с версии 3.7, гарантирован порядок LIFO - Last In First Out.\nЭто значит, что пары будут извлекаться в порядке обратном добавлению, то есть последняя добавленная пара, будет извлечена первой.\nПри этом мы можем быть уверены в том, что:",[697,27031,27032,27035],{},[700,27033,27034],{},"Все пары будут извлечены",[700,27036,27037],{},"Каждая пара будет извлечена строго один раз",[458,27039,27041],{"id":27040},"дополнение-одного-словаря-другим","Дополнение одного словаря другим",[415,27043,27044,27045,27048,27049,27052,27053,27055],{},"У списка есть метод ",[428,27046,27047],{},"extend",", который расширяет один список другим.\nУ словаря есть похожий по смыслу метод ",[428,27050,27051],{},"update",".\nНо при вызове ",[428,27054,27051],{}," ассоциированный объект словаря не просто получает пары «ключ-значение» из нового словаря.\nПроисходит именно обновление данных — поэтому метод и называется update. Работает это так:",[697,27057,27058,27061],{},[700,27059,27060],{},"Новые ключи дописываются в словарь",[700,27062,27063],{},"Если какие-то ключи уже существовали до этого, то связанные с ними значения будут заменены новыми",[415,27065,27066],{},"Так это выглядит в коде:",[422,27068,27070],{"className":424,"code":27069,"language":396,"meta":426,"style":426},"cart = {\"apples\": 5, \"oranges\": 7}\naddon = {\"oranges\": 4, \"lemons\": 2}\ncart.update(addon)\ncart  # {\"apples\": 5, \"oranges\": 4, \"lemons\": 2}\n",[428,27071,27072,27099,27125,27130],{"__ignoreMap":426},[431,27073,27074,27077,27079,27081,27084,27086,27088,27090,27093,27095,27097],{"class":433,"line":434},[431,27075,27076],{"class":441},"cart ",[431,27078,1189],{"class":654},[431,27080,3005],{"class":441},[431,27082,27083],{"class":445},"\"apples\"",[431,27085,26306],{"class":441},[431,27087,856],{"class":437},[431,27089,4846],{"class":441},[431,27091,27092],{"class":445},"\"oranges\"",[431,27094,26306],{"class":441},[431,27096,781],{"class":437},[431,27098,3236],{"class":441},[431,27100,27101,27104,27106,27108,27110,27112,27114,27116,27119,27121,27123],{"class":433,"line":452},[431,27102,27103],{"class":441},"addon ",[431,27105,1189],{"class":654},[431,27107,3005],{"class":441},[431,27109,27092],{"class":445},[431,27111,26306],{"class":441},[431,27113,762],{"class":437},[431,27115,4846],{"class":441},[431,27117,27118],{"class":445},"\"lemons\"",[431,27120,26306],{"class":441},[431,27122,651],{"class":437},[431,27124,3236],{"class":441},[431,27126,27127],{"class":433,"line":578},[431,27128,27129],{"class":441},"cart.update(addon)\n",[431,27131,27132,27135],{"class":433,"line":584},[431,27133,27134],{"class":441},"cart  ",[431,27136,27137],{"class":455},"# {\"apples\": 5, \"oranges\": 4, \"lemons\": 2}\n",[415,27139,27140],{},"В коде выше мы добавили лимоны и обновили количество апельсинов.",[458,27142,27144],{"id":27143},"копирование-словаря","Копирование словаря",[415,27146,27147],{},"В случае списков мы можем сложить два списка двумя способами:",[697,27149,27150,27153],{},[700,27151,27152],{},"Просто сложить с помощью оператора + два списка и получить новый",[700,27154,27155],{},"Сделать копию одного списка и дополнить ее данными из второго",[415,27157,27158,27159,27162],{},"Но словари нельзя складывать, да и срезы словари тоже не поддерживают.\nЗато у словаря есть метод ",[428,27160,27161],{},"copy",".\nОн работает как копирование списка с помощью среза [:] — при вызове он возвращает поверхностную копию из словаря.\nТак же ее называют «неглубокой копией» или shallow copy.\nПоверхностная копия воспроизводит только структуру словаря: не копирует значения, а только создает на них новые ссылки.\nТем не менее поверхностная копия — это новый словарь, который может изменять свой состав, не влияя на оригинал:",[422,27164,27166],{"className":424,"code":27165,"language":396,"meta":426,"style":426},"d = {\"a\": 1, \"b\": [2]}\nc = d.copy()\nc.update({\"a\": 10, \"1k\": 1000})\nc  # {'a': 10, 'b': [2], '1k': 1000}\nc[\"b\"].append(None)\nc  # {'a': 10, 'b': [2, None], '1k': 1000}\nd  # {'a': 1, 'b': [2, None]}\n",[428,27167,27168,27194,27204,27228,27235,27248,27255],{"__ignoreMap":426},[431,27169,27170,27172,27174,27176,27178,27180,27182,27184,27186,27189,27191],{"class":433,"line":434},[431,27171,26778],{"class":441},[431,27173,1189],{"class":654},[431,27175,3005],{"class":441},[431,27177,26597],{"class":445},[431,27179,26306],{"class":441},[431,27181,1192],{"class":437},[431,27183,4846],{"class":441},[431,27185,26606],{"class":445},[431,27187,27188],{"class":441},": [",[431,27190,651],{"class":437},[431,27192,27193],{"class":441},"]}\n",[431,27195,27196,27199,27201],{"class":433,"line":452},[431,27197,27198],{"class":441},"c ",[431,27200,1189],{"class":654},[431,27202,27203],{"class":441}," d.copy()\n",[431,27205,27206,27209,27211,27213,27215,27217,27220,27222,27225],{"class":433,"line":578},[431,27207,27208],{"class":441},"c.update({",[431,27210,26597],{"class":445},[431,27212,26306],{"class":441},[431,27214,3565],{"class":437},[431,27216,4846],{"class":441},[431,27218,27219],{"class":445},"\"1k\"",[431,27221,26306],{"class":441},[431,27223,27224],{"class":437},"1000",[431,27226,27227],{"class":441},"})\n",[431,27229,27230,27232],{"class":433,"line":584},[431,27231,17178],{"class":441},[431,27233,27234],{"class":455},"# {'a': 10, 'b': [2], '1k': 1000}\n",[431,27236,27237,27240,27242,27244,27246],{"class":433,"line":1244},[431,27238,27239],{"class":441},"c[",[431,27241,26606],{"class":445},[431,27243,22745],{"class":441},[431,27245,7922],{"class":437},[431,27247,449],{"class":441},[431,27249,27250,27252],{"class":433,"line":1985},[431,27251,17178],{"class":441},[431,27253,27254],{"class":455},"# {'a': 10, 'b': [2, None], '1k': 1000}\n",[431,27256,27257,27260],{"class":433,"line":2041},[431,27258,27259],{"class":441},"d  ",[431,27261,27262],{"class":455},"# {'a': 1, 'b': [2, None]}\n",[415,27264,27265,27266,27269,27270,27272],{},"Словарь ",[428,27267,27268],{},"c"," получил собственную структуру, при этом его обновление не затронуло оригинальный словарь ",[428,27271,7989],{},".\nОднако изменение объекта списка по ссылке затронуло и оригинал, потому что при копировании словаря ссылка на список тоже \"скопировалась\".",[458,27274,27276],{"id":27275},"очистка-словаря","Очистка словаря",[415,27278,27279,27280,27282,27283,2699],{},"Списки можно очистить с помощью присваивания срезу my_list[:] = ",[431,27281],{}," .\nВ случае словаря вместо присваивания срезу используется метод ",[428,27284,27285],{},"clear",[415,27287,17944,27288,27291],{},[428,27289,27290],{},"clear()"," удаляет все элементы из текущего словаря:",[422,27293,27295],{"className":424,"code":27294,"language":396,"meta":426,"style":426},"d = {\"a\": 1}\nd.clear()\nprint(d)  # {}\n",[428,27296,27297,27313,27318],{"__ignoreMap":426},[431,27298,27299,27301,27303,27305,27307,27309,27311],{"class":433,"line":434},[431,27300,26778],{"class":441},[431,27302,1189],{"class":654},[431,27304,3005],{"class":441},[431,27306,26597],{"class":445},[431,27308,26306],{"class":441},[431,27310,1192],{"class":437},[431,27312,3236],{"class":441},[431,27314,27315],{"class":433,"line":452},[431,27316,27317],{"class":441},"d.clear()\n",[431,27319,27320,27322,27324],{"class":433,"line":578},[431,27321,438],{"class":437},[431,27323,26806],{"class":441},[431,27325,27326],{"class":455},"# {}\n",[632,27328,27330],{"id":27329},"инициализация-новых-значений","Инициализация новых значений",[415,27332,27333],{},"Представьте ситуацию: вам нужно хранить в словаре в качестве значений списки или любые другие изменяемые данные.\nУ вас есть ключ и элемент для добавления в список-значение, но сам ключ в словаре может быть не представлен.\nВ таком случае придется писать подобный код:",[422,27335,27337],{"className":424,"code":27336,"language":396,"meta":426,"style":426},"if key not in dictionary:\n    dictionary[key] = []  # инициализируем список\ndictionary[key].append(value)  # изменяем список\n",[428,27338,27339,27353,27365],{"__ignoreMap":426},[431,27340,27341,27343,27346,27348,27350],{"class":433,"line":434},[431,27342,10399],{"class":654},[431,27344,27345],{"class":441}," key ",[431,27347,9369],{"class":654},[431,27349,21531],{"class":654},[431,27351,27352],{"class":441}," dictionary:\n",[431,27354,27355,27358,27360,27362],{"class":433,"line":452},[431,27356,27357],{"class":441},"    dictionary[key] ",[431,27359,1189],{"class":654},[431,27361,17473],{"class":441},[431,27363,27364],{"class":455},"# инициализируем список\n",[431,27366,27367,27370],{"class":433,"line":578},[431,27368,27369],{"class":441},"dictionary[key].append(value)  ",[431,27371,27372],{"class":455},"# изменяем список\n",[415,27374,27375,27376,2699],{},"Подобная ситуация встречается не так уж и редко.\nЭто понимали и авторы стандартной библиотеки Python и дали словарю метод ",[428,27377,27378],{},"setdefault",[458,27380,27330],{"id":27381},"инициализация-новых-значений-1",[415,27383,27384,27385,3562],{},"Попробуем переписать код выше с помощью метода ",[428,27386,27378],{},[422,27388,27390],{"className":424,"code":27389,"language":396,"meta":426,"style":426},"dictionary.setdefault(key, []).append(value)\n",[428,27391,27392],{"__ignoreMap":426},[431,27393,27394],{"class":433,"line":434},[431,27395,27389],{"class":441},[415,27397,17944,27398,27400],{},[428,27399,27378],{}," принимает ключ и значение по умолчанию, а затем возвращает ссылку на значение в словаре, связанное с указанным ключом.\nЕсли ключ в словаре отсутствует, то метод помещает по ключу, то самое значение по умолчанию и возвращает ссылку на него.\nВ примере выше значением по умолчанию выступает пустой список [].",[458,27402,27404,27405],{"id":27403},"тип-defaultdict","Тип ",[428,27406,27407],{},"defaultdict",[415,27409,27410,27411,27414,27415,27417,27418,27420,27421,27423],{},"В стандартной поставке Python присутствует модуль ",[428,27412,27413],{},"collections",", который предоставляет тип ",[428,27416,27407],{},".\nВо всех отношениях ",[428,27419,27407],{}," — это обычный словарь.\nПри этом у него есть одно уникальное свойство: там, где обычный словарь \"ругается\" на отсутствие ключа, ",[428,27422,27407],{}," сам возвращает значение по умолчанию.\nРассмотрим пример:",[422,27425,27427],{"className":424,"code":27426,"language":396,"meta":426,"style":426},"from collections import defaultdict\nd = defaultdict(int)\nd[\"a\"] += 1\nd[\"b\"] = d[\"c\"] + 5\nprint(d)  # defaultdict(\u003Cclass 'int'>, {'a': 1, 'c': 0, 'b': 5})\n",[428,27428,27429,27441,27454,27466,27487],{"__ignoreMap":426},[431,27430,27431,27433,27436,27438],{"class":433,"line":434},[431,27432,5373],{"class":654},[431,27434,27435],{"class":441}," collections ",[431,27437,5379],{"class":654},[431,27439,27440],{"class":441}," defaultdict\n",[431,27442,27443,27445,27447,27450,27452],{"class":433,"line":452},[431,27444,26778],{"class":441},[431,27446,1189],{"class":654},[431,27448,27449],{"class":441}," defaultdict(",[431,27451,2266],{"class":437},[431,27453,449],{"class":441},[431,27455,27456,27458,27460,27462,27464],{"class":433,"line":578},[431,27457,26791],{"class":441},[431,27459,26597],{"class":445},[431,27461,4049],{"class":441},[431,27463,12563],{"class":654},[431,27465,3916],{"class":437},[431,27467,27468,27470,27472,27474,27476,27479,27481,27483,27485],{"class":433,"line":584},[431,27469,26791],{"class":441},[431,27471,26606],{"class":445},[431,27473,4049],{"class":441},[431,27475,1189],{"class":654},[431,27477,27478],{"class":441}," d[",[431,27480,26908],{"class":445},[431,27482,4049],{"class":441},[431,27484,802],{"class":654},[431,27486,3926],{"class":437},[431,27488,27489,27491,27493],{"class":433,"line":1244},[431,27490,438],{"class":437},[431,27492,26806],{"class":441},[431,27494,27495],{"class":455},"# defaultdict(\u003Cclass 'int'>, {'a': 1, 'c': 0, 'b': 5})\n",[415,27497,27498,27499,27501,27502,27504,27505,27507],{},"При создании словаря мы указали в качестве аргумента функцию ",[428,27500,2266],{},".\nЕсли эту функцию вызвать без аргументов, то она вернет ",[428,27503,3302],{},".\nИменно этот вызов внутри словаря ",[428,27506,7989],{}," и происходит всякий раз, когда нужно получить значение для несуществующего ключа.",[415,27509,27510,27511,27514,27515,27517],{},"В примере выше ",[428,27512,27513],{},"d[\"a\"] += 1"," дает ",[428,27516,1192],{},", потому что этот код работает так:",[697,27519,27520,27531],{},[700,27521,27522,27523,27525,27526,27528,27529],{},"Сначала для ключа ",[428,27524,26597],{}," создается начальное значение — делается вызов ",[428,27527,4334],{}," и получается ",[428,27530,3302],{},[700,27532,27533,27534],{},"Уже потом к нему прибавляется ",[428,27535,1192],{},[415,27537,27538,27539,27542,27543,3228,27545,27547,27548,27550,27551,27554],{},"В строчке ",[428,27540,27541],{},"d[\"b\"] = d[\"c\"] + 5"," создаются значения для ключей ",[428,27544,26606],{},[428,27546,26908],{},". Затем уже по ключу ",[428,27549,26606],{}," записывается сумма ",[428,27552,27553],{},"0 + 5",".\nВот еще один пример — на этот раз с самодельной функцией-инициализатором:",[422,27556,27558],{"className":424,"code":27557,"language":396,"meta":426,"style":426},"from collections import defaultdict\n\ndef new_value():\n    return \"1\"\n\nx = defaultdict(new_value)\nx[1]  # '1'\nx[\"2\"]  # '1'\nprint(x)  # defaultdict(\u003Cfunction new_value at 0x0000018652C1E2A0>, {1: '1', '2': '1'})\n",[428,27559,27560,27570,27574,27583,27590,27594,27603,27615,27626],{"__ignoreMap":426},[431,27561,27562,27564,27566,27568],{"class":433,"line":434},[431,27563,5373],{"class":654},[431,27565,27435],{"class":441},[431,27567,5379],{"class":654},[431,27569,27440],{"class":441},[431,27571,27572],{"class":433,"line":452},[431,27573,1662],{"emptyLinePlaceholder":393},[431,27575,27576,27578,27581],{"class":433,"line":578},[431,27577,6330],{"class":654},[431,27579,27580],{"class":6333}," new_value",[431,27582,6337],{"class":441},[431,27584,27585,27587],{"class":433,"line":584},[431,27586,6599],{"class":654},[431,27588,27589],{"class":445}," \"1\"\n",[431,27591,27592],{"class":433,"line":1244},[431,27593,1662],{"emptyLinePlaceholder":393},[431,27595,27596,27598,27600],{"class":433,"line":1985},[431,27597,1186],{"class":441},[431,27599,1189],{"class":654},[431,27601,27602],{"class":441}," defaultdict(new_value)\n",[431,27604,27605,27608,27610,27612],{"class":433,"line":2041},[431,27606,27607],{"class":441},"x[",[431,27609,1192],{"class":437},[431,27611,3612],{"class":441},[431,27613,27614],{"class":455},"# '1'\n",[431,27616,27617,27619,27622,27624],{"class":433,"line":4018},[431,27618,27607],{"class":441},[431,27620,27621],{"class":445},"\"2\"",[431,27623,3612],{"class":441},[431,27625,27614],{"class":455},[431,27627,27628,27630,27632],{"class":433,"line":4030},[431,27629,438],{"class":437},[431,27631,5754],{"class":441},[431,27633,27634],{"class":455},"# defaultdict(\u003Cfunction new_value at 0x0000018652C1E2A0>, {1: '1', '2': '1'})\n",[415,27636,27637,27638,27640],{},"Попробуем отбросить немного непонятное упоминание функции-инициализатора.\nТак станет видно, что теперь строки ",[428,27639,21581],{}," записаны по всем ключам, по которым мы обращались к содержимому словаря.",[458,27642,27644,27645,27647,27648],{"id":27643},"отличия-defaultdict-от-обычного-словаря-с-setdefault","Отличия ",[428,27646,27407],{}," от обычного словаря с ",[428,27649,27378],{},[415,27651,27652],{},"Пока не совсем понятно, зачем иметь оба способа, если они настолько похожи. Но давайте сравним эти две строки:",[415,27654,27655],{},"a.setdefault(key, []).append…",[415,27657,27658],{},"и",[415,27660,27661],{},"b[key].append…",[415,27663,27664],{},"b — это defaultdict(list).",[415,27666,27667],{},"Строки очень похожи, но есть одно различие:",[697,27669,27670,27673],{},[700,27671,27672],{},"В первом случае объект пустого списка будет создаваться каждый раз",[700,27674,27675],{},"Во втором случае новый список создается только тогда, когда ключ не будет найден",[415,27677,27678,27679,27682,27683,27685],{},"Значения аргументов всегда вычисляются до того, как будет вызвана функция.\nПоэтому здесь в случае с ",[428,27680,27681],{},"setdefault(key, [])"," затратами на создание пустого списка можно пренебречь.\nЕсли вдруг затраты на создание значения по умолчанию окажутся велики, вариант с ",[428,27684,27407],{}," окажется гораздо предпочтительнее.",[415,27687,27688,27689,27691,27692,27694,27695,27697,27698,27700],{},"Зачем вообще использовать ",[428,27690,27378],{},"? Он помогает инициализировать разные значения по разным ключам.\nЗначение по умолчанию передается каждый раз, поэтому мы можем хранить по разным ключам даже разные типы данных.\nС ",[428,27693,27407],{}," у нас нет контроля над тем, какие значения по каким ключам класть.\nФункция-инициализатор вызывается каждый раз одна и та же — ключ в нее не передается.\nНаконец, всегда остаются редкие случаи, когда и ",[428,27696,27407],{}," не подходит.\nНапример, если нужно инициализировать значения по-разному, но не подходит и ",[428,27699,27378],{},".\nНовые значения неизменяемы, их не получится изменить по возвращаемой ссылке.",[415,27702,1849,27703,1853,27705,1857],{},[800,27704,1852],{},[800,27706,1856],{},[1859,27708],{},[1862,27710,27711],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":426,"searchDepth":452,"depth":1244,"links":27713},[27714],{"id":26271,"depth":452,"text":26272,"children":27715},[27716,27720,27726],{"id":17445,"depth":578,"text":17446,"children":27717},[27718,27719],{"id":26417,"depth":584,"text":26418},{"id":26574,"depth":584,"text":26575},{"id":26760,"depth":578,"text":26761,"children":27721},[27722,27723,27724,27725],{"id":26848,"depth":584,"text":26849},{"id":27040,"depth":584,"text":27041},{"id":27143,"depth":584,"text":27144},{"id":27275,"depth":584,"text":27276},{"id":27329,"depth":578,"text":27330,"children":27727},[27728,27729,27731],{"id":27381,"depth":584,"text":27330},{"id":27403,"depth":584,"text":27730},"Тип defaultdict",{"id":27643,"depth":584,"text":27732},"Отличия defaultdict от обычного словаря с setdefault","2025-07-03","Синтаксис. Изменение данных в словаре. Инициализация новых значений","images\u002Fblog\u002Fpython\u002Fst18\u002Fimg.png",{},{"title":226,"description":27734},"iEJzQQHeKHRAGpC23j7IzHCFwushoPCY_PunQ8Mg5HM",{"id":27740,"title":230,"author":27741,"body":27743,"date":29114,"description":29115,"extension":1887,"image":29116,"meta":29117,"minRead":4477,"navigation":393,"num":12871,"path":231,"seo":29118,"stem":232,"__hash__":29119},"python\u002Fblog\u002Fpython\u002Fst19.md",{"name":402,"avatar":27742},{"src":404,"alt":405},{"type":407,"value":27744,"toc":29093},[27745,27749,27752,27755,27759,27762,27815,27825,27852,27855,27928,27931,27935,27938,27988,27992,28004,28093,28105,28109,28119,28203,28208,28235,28237,28240,28244,28247,28297,28300,28426,28429,28433,28443,28448,28454,28508,28512,28522,28527,28533,28581,28585,28593,28653,28659,28663,28671,28676,28686,28734,28738,28749,28754,28763,28815,28819,28822,28826,28829,28866,28870,28876,28890,28895,28940,28945,28987,28992,29035,29040,29082,29088,29090],[410,27746,27748],{"id":27747},"использование-множеств","Использование множеств",[415,27750,27751],{},"Ключи словаря хранятся в нем в единственном экземпляре.\nДобавление нового значения по существующему ключу заменяет старое значение.\nХранение в единственном экземпляре полезно и в тех случаях, когда нам нужно хранить не столько значения по ключам, сколько именно сами ключи.",[415,27753,27754],{},"Например, нужно хранить список городов, которые посетил каждый пользователь.\nПри повторном посещении города дублировать запись не требуется.\nЭто позволяет сэкономить память и упростить поиск информации.\nТакже нам может понадобиться узнать, какие города посетили и Вася и Маша, а какие — только Маша или только Вася.\nПо сути, это хранения перечня элементов в неких наборах и сопоставления этих наборов между собой.\nВ математике для решения такого рода задач служат множества.\nВ свою очередь, Python предоставляет одноименную структуру данных — set.\nИтак, множества в Python — это неупорядоченные последовательности элементов, каждый из которых в множестве представлен ровно один раз.",[632,27756,27758],{"id":27757},"создание-множеств-и-манипуляции-над-ними","Создание множеств и манипуляции над ними",[415,27760,27761],{},"Множество можно создать с помощью соответствующего литерала:",[422,27763,27765],{"className":424,"code":27764,"language":396,"meta":426,"style":426},"s = {1, 2, 3, 2, 1}\ns  # {1, 2, 3}\ntype(s)  # \u003Cclass 'set'>\n",[428,27766,27767,27796,27804],{"__ignoreMap":426},[431,27768,27769,27772,27774,27776,27778,27780,27782,27784,27786,27788,27790,27792,27794],{"class":433,"line":434},[431,27770,27771],{"class":441},"s ",[431,27773,1189],{"class":654},[431,27775,3005],{"class":441},[431,27777,1192],{"class":437},[431,27779,4846],{"class":441},[431,27781,651],{"class":437},[431,27783,4846],{"class":441},[431,27785,971],{"class":437},[431,27787,4846],{"class":441},[431,27789,651],{"class":437},[431,27791,4846],{"class":441},[431,27793,1192],{"class":437},[431,27795,3236],{"class":441},[431,27797,27798,27801],{"class":433,"line":452},[431,27799,27800],{"class":441},"s  ",[431,27802,27803],{"class":455},"# {1, 2, 3}\n",[431,27805,27806,27809,27812],{"class":433,"line":578},[431,27807,27808],{"class":437},"type",[431,27810,27811],{"class":441},"(s)  ",[431,27813,27814],{"class":455},"# \u003Cclass 'set'>\n",[415,27816,27817,27818,27821,27822,27824],{},"Литералы множеств записываются в фигурных скобках, как и литералы словарей.\nОднако внутри скобок через запятую перечисляются только элементы множества.\nЛитерал ",[428,27819,27820],{},"{}"," уже занят словарями, поэтому пустое множество создается вызовом функции ",[428,27823,21171],{}," без аргументов:",[422,27826,27828],{"className":424,"code":27827,"language":396,"meta":426,"style":426},"set()  # {}\ntype(set())  # \u003Cclass 'set'>\n",[428,27829,27830,27839],{"__ignoreMap":426},[431,27831,27832,27834,27837],{"class":433,"line":434},[431,27833,21171],{"class":437},[431,27835,27836],{"class":441},"()  ",[431,27838,27326],{"class":455},[431,27840,27841,27843,27845,27847,27850],{"class":433,"line":452},[431,27842,27808],{"class":437},[431,27844,442],{"class":441},[431,27846,21171],{"class":437},[431,27848,27849],{"class":441},"())  ",[431,27851,27814],{"class":455},[415,27853,27854],{},"Эту же функцию можно использовать, чтобы создать множество из элементов произвольного количества итераторов или итерируемых элементов:",[422,27856,27858],{"className":424,"code":27857,"language":396,"meta":426,"style":426},"set(\"abracadabra\")  # {'c', 'd', 'a', 'r', 'b'}\nset([1, 2, 3, 2, 1])  # {1, 2, 3}\nset({\"a\": 1, \"b\": \"2\"})  # {'a', 'b'}\n",[428,27859,27860,27874,27902],{"__ignoreMap":426},[431,27861,27862,27864,27866,27869,27871],{"class":433,"line":434},[431,27863,21171],{"class":437},[431,27865,442],{"class":441},[431,27867,27868],{"class":445},"\"abracadabra\"",[431,27870,526],{"class":441},[431,27872,27873],{"class":455},"# {'c', 'd', 'a', 'r', 'b'}\n",[431,27875,27876,27878,27880,27882,27884,27886,27888,27890,27892,27894,27896,27898,27900],{"class":433,"line":452},[431,27877,21171],{"class":437},[431,27879,17778],{"class":441},[431,27881,1192],{"class":437},[431,27883,4846],{"class":441},[431,27885,651],{"class":437},[431,27887,4846],{"class":441},[431,27889,971],{"class":437},[431,27891,4846],{"class":441},[431,27893,651],{"class":437},[431,27895,4846],{"class":441},[431,27897,1192],{"class":437},[431,27899,3305],{"class":441},[431,27901,27803],{"class":455},[431,27903,27904,27906,27908,27910,27912,27914,27916,27918,27920,27922,27925],{"class":433,"line":578},[431,27905,21171],{"class":437},[431,27907,26648],{"class":441},[431,27909,26597],{"class":445},[431,27911,26306],{"class":441},[431,27913,1192],{"class":437},[431,27915,4846],{"class":441},[431,27917,26606],{"class":445},[431,27919,26306],{"class":441},[431,27921,27621],{"class":445},[431,27923,27924],{"class":441},"})  ",[431,27926,27927],{"class":455},"# {'a', 'b'}\n",[415,27929,27930],{},"Заметьте, что в множестве каждый уникальный элемент представлен ровно один раз, даже если в коллекции-источнике были повторы.",[458,27932,27934],{"id":27933},"проверка-на-вхождение","Проверка на вхождение",[415,27936,27937],{},"Для некоторых задач нужно проверять, является ли некое значение элементом множества — другими словами, «входит ли оно в множество» или «принадлежит ли оно множеству».\nВ таких случаях нужно использовать оператор in:",[422,27939,27941],{"className":424,"code":27940,"language":396,"meta":426,"style":426},"42 in set()  # False\n42 in set([42])  # True\n\"a\" in set(\"abracadabra\")  # True\n",[428,27942,27943,27956,27972],{"__ignoreMap":426},[431,27944,27945,27947,27949,27952,27954],{"class":433,"line":434},[431,27946,9731],{"class":437},[431,27948,21531],{"class":654},[431,27950,27951],{"class":437}," set",[431,27953,27836],{"class":441},[431,27955,20020],{"class":455},[431,27957,27958,27960,27962,27964,27966,27968,27970],{"class":433,"line":452},[431,27959,9731],{"class":437},[431,27961,21531],{"class":654},[431,27963,27951],{"class":437},[431,27965,17778],{"class":441},[431,27967,9731],{"class":437},[431,27969,3305],{"class":441},[431,27971,19945],{"class":455},[431,27973,27974,27976,27978,27980,27982,27984,27986],{"class":433,"line":578},[431,27975,26597],{"class":445},[431,27977,21531],{"class":654},[431,27979,27951],{"class":437},[431,27981,442],{"class":441},[431,27983,27868],{"class":445},[431,27985,526],{"class":441},[431,27987,19945],{"class":455},[632,27989,27991],{"id":27990},"изменение-состава-элементов-множества","Изменение состава элементов множества",[415,27993,27994,27995,4846,27998,3228,28001,3562],{},"Множества в Python — изменяемые. Добавлять и удалять элементы из множества можно с помощью методов ",[428,27996,27997],{},"add",[428,27999,28000],{},"discard",[428,28002,28003],{},"remove",[422,28005,28007],{"className":424,"code":28006,"language":396,"meta":426,"style":426},"s = set()\ns.add(1)\ns.add(2)\ns.add(2)\ns  # {1, 2}\ns.discard(1)\ns  # {2}\ns.discard(1)\ns  # {2}\ns.remove(1)  # KeyError: 1\n",[428,28008,28009,28019,28028,28036,28044,28051,28060,28067,28075,28081],{"__ignoreMap":426},[431,28010,28011,28013,28015,28017],{"class":433,"line":434},[431,28012,27771],{"class":441},[431,28014,1189],{"class":654},[431,28016,27951],{"class":437},[431,28018,5728],{"class":441},[431,28020,28021,28024,28026],{"class":433,"line":452},[431,28022,28023],{"class":441},"s.add(",[431,28025,1192],{"class":437},[431,28027,449],{"class":441},[431,28029,28030,28032,28034],{"class":433,"line":578},[431,28031,28023],{"class":441},[431,28033,651],{"class":437},[431,28035,449],{"class":441},[431,28037,28038,28040,28042],{"class":433,"line":584},[431,28039,28023],{"class":441},[431,28041,651],{"class":437},[431,28043,449],{"class":441},[431,28045,28046,28048],{"class":433,"line":1244},[431,28047,27800],{"class":441},[431,28049,28050],{"class":455},"# {1, 2}\n",[431,28052,28053,28056,28058],{"class":433,"line":1985},[431,28054,28055],{"class":441},"s.discard(",[431,28057,1192],{"class":437},[431,28059,449],{"class":441},[431,28061,28062,28064],{"class":433,"line":2041},[431,28063,27800],{"class":441},[431,28065,28066],{"class":455},"# {2}\n",[431,28068,28069,28071,28073],{"class":433,"line":4018},[431,28070,28055],{"class":441},[431,28072,1192],{"class":437},[431,28074,449],{"class":441},[431,28076,28077,28079],{"class":433,"line":4030},[431,28078,27800],{"class":441},[431,28080,28066],{"class":455},[431,28082,28083,28086,28088,28090],{"class":433,"line":4419},[431,28084,28085],{"class":441},"s.remove(",[431,28087,1192],{"class":437},[431,28089,526],{"class":441},[431,28091,28092],{"class":455},"# KeyError: 1\n",[415,28094,28095,28096,28098,28099,28101,28102,28104],{},"При чтении кода в этом примере вы должны были заметить, что добавление лишних элементов с помощью ",[428,28097,27997],{}," и отбрасывание несуществующих элементов с помощью ",[428,28100,28000],{}," не приводят к ошибке.\nОднако вызов метода ",[428,28103,28003],{}," с несуществующим элементом приводит к ошибке.",[632,28106,28108],{"id":28107},"копирование-и-очистка-множеств","Копирование и очистка множеств",[415,28110,28111,28112,28114,28115,28118],{},"Множества изменяемы, поэтому требуется сделать копию перед изменением оригинала.\nКак и словари, множества не поддерживают операцию получения среза.\nДля копирования приходится использовать метод ",[428,28113,27161],{},", создающий ",[1355,28116,28117],{},"поверхностную копию"," множества:",[422,28120,28122],{"className":424,"code":28121,"language":396,"meta":426,"style":426},"s1 = {1, 2, 3}\ns2 = s1.copy()\ns1 is s2  # False\ns1 == s2  # True\ns2.add(4)\ns1 == s2  # False\ns2  # {1, 2, 3, 4}\n",[428,28123,28124,28145,28155,28166,28176,28185,28195],{"__ignoreMap":426},[431,28125,28126,28129,28131,28133,28135,28137,28139,28141,28143],{"class":433,"line":434},[431,28127,28128],{"class":441},"s1 ",[431,28130,1189],{"class":654},[431,28132,3005],{"class":441},[431,28134,1192],{"class":437},[431,28136,4846],{"class":441},[431,28138,651],{"class":437},[431,28140,4846],{"class":441},[431,28142,971],{"class":437},[431,28144,3236],{"class":441},[431,28146,28147,28150,28152],{"class":433,"line":452},[431,28148,28149],{"class":441},"s2 ",[431,28151,1189],{"class":654},[431,28153,28154],{"class":441}," s1.copy()\n",[431,28156,28157,28159,28161,28164],{"class":433,"line":578},[431,28158,28128],{"class":441},[431,28160,19884],{"class":654},[431,28162,28163],{"class":441}," s2  ",[431,28165,20020],{"class":455},[431,28167,28168,28170,28172,28174],{"class":433,"line":584},[431,28169,28128],{"class":441},[431,28171,8409],{"class":654},[431,28173,28163],{"class":441},[431,28175,19945],{"class":455},[431,28177,28178,28181,28183],{"class":433,"line":1244},[431,28179,28180],{"class":441},"s2.add(",[431,28182,762],{"class":437},[431,28184,449],{"class":441},[431,28186,28187,28189,28191,28193],{"class":433,"line":1985},[431,28188,28128],{"class":441},[431,28190,8409],{"class":654},[431,28192,28163],{"class":441},[431,28194,20020],{"class":455},[431,28196,28197,28200],{"class":433,"line":2041},[431,28198,28199],{"class":441},"s2  ",[431,28201,28202],{"class":455},"# {1, 2, 3, 4}\n",[415,28204,28205,28206,3562],{},"Очистить множество без пересоздания можно с помощью метода ",[428,28207,27285],{},[422,28209,28211],{"className":424,"code":28210,"language":396,"meta":426,"style":426},"s = set(\"foobar\")\ns  # {'f', 'a', 'r', 'o', 'b'}\n",[428,28212,28213,28228],{"__ignoreMap":426},[431,28214,28215,28217,28219,28221,28223,28226],{"class":433,"line":434},[431,28216,27771],{"class":441},[431,28218,1189],{"class":654},[431,28220,27951],{"class":437},[431,28222,442],{"class":441},[431,28224,28225],{"class":445},"\"foobar\"",[431,28227,449],{"class":441},[431,28229,28230,28232],{"class":433,"line":452},[431,28231,27800],{"class":441},[431,28233,28234],{"class":455},"# {'f', 'a', 'r', 'o', 'b'}\n",[632,28236,21175],{"id":21174},[415,28238,28239],{},"Если при изучении множеств остановиться на создании и модифицировании, может показаться, что множества не сильно-то и отличаются от списков.\nКажется, что они просто позволяют быстрее проверить вхождение элемента, но при этом не поддерживают механизм срезов.",[458,28241,28243],{"id":28242},"проверка-на-равенство","Проверка на равенство",[415,28245,28246],{},"Сопоставление множеств — это довольно мощный инструмент. Давайте проверим два множества на равенство:",[422,28248,28250],{"className":424,"code":28249,"language":396,"meta":426,"style":426},"set([1, 2, 3, 2, 1]) == {3, 1, 2}  # True\n",[428,28251,28252],{"__ignoreMap":426},[431,28253,28254,28256,28258,28260,28262,28264,28266,28268,28270,28272,28274,28276,28278,28280,28282,28284,28286,28288,28290,28292,28295],{"class":433,"line":434},[431,28255,21171],{"class":437},[431,28257,17778],{"class":441},[431,28259,1192],{"class":437},[431,28261,4846],{"class":441},[431,28263,651],{"class":437},[431,28265,4846],{"class":441},[431,28267,971],{"class":437},[431,28269,4846],{"class":441},[431,28271,651],{"class":437},[431,28273,4846],{"class":441},[431,28275,1192],{"class":437},[431,28277,18021],{"class":441},[431,28279,8409],{"class":654},[431,28281,3005],{"class":441},[431,28283,971],{"class":437},[431,28285,4846],{"class":441},[431,28287,1192],{"class":437},[431,28289,4846],{"class":441},[431,28291,651],{"class":437},[431,28293,28294],{"class":441},"}  ",[431,28296,19945],{"class":455},[415,28298,28299],{},"Можно подумать, что два множества равны, если каждый отдельный элемент одного множества содержится и во втором.\nЭта догадка близка к истине, но вспомним, что коллекции в Python хранят только ссылки на объекты.\nМножества равны, если ссылаются на одни и те же объекты.\nОдинаковые ссылки равны, но при этом могут быть равны и разные объекты.\nДело в том, что в Python есть специальный протокол проверки на равенство.\nБольшинство встроенных типов данных поддерживает этот протокол.\nМы можем проверять на равенство числа, строки, булевы значения. А еще можем приравнивать кортежи, списки, словари.\nЗдесь Python поступает очень разумно.\nЕсли вы приравняете две коллекции одного типа, то эти коллекции будут считаться равными, если их элементы попарно равны с точки зрения протокола.\nПосмотрите:",[422,28301,28303],{"className":424,"code":28302,"language":396,"meta":426,"style":426},"[1, 2, [\"foo\", \"bar\"]] == [1, 2, [\"foo\"] + [\"bar\"]]  # True\n(1, True, []) == (1, True, [])  # True\n{\"a\": 1, \"b\": 2} == {\"b\": 2, \"a\": 1}  # True\n",[428,28304,28305,28355,28383],{"__ignoreMap":426},[431,28306,28307,28309,28311,28313,28315,28317,28320,28322,28325,28328,28330,28332,28334,28336,28338,28340,28342,28344,28346,28348,28350,28353],{"class":433,"line":434},[431,28308,19914],{"class":441},[431,28310,1192],{"class":437},[431,28312,4846],{"class":441},[431,28314,651],{"class":437},[431,28316,22328],{"class":441},[431,28318,28319],{"class":445},"\"foo\"",[431,28321,4846],{"class":441},[431,28323,28324],{"class":445},"\"bar\"",[431,28326,28327],{"class":441},"]] ",[431,28329,8409],{"class":654},[431,28331,17401],{"class":441},[431,28333,1192],{"class":437},[431,28335,4846],{"class":441},[431,28337,651],{"class":437},[431,28339,22328],{"class":441},[431,28341,28319],{"class":445},[431,28343,4049],{"class":441},[431,28345,802],{"class":654},[431,28347,17401],{"class":441},[431,28349,28324],{"class":445},[431,28351,28352],{"class":441},"]]  ",[431,28354,19945],{"class":455},[431,28356,28357,28359,28361,28363,28365,28368,28370,28372,28374,28376,28378,28381],{"class":433,"line":452},[431,28358,442],{"class":441},[431,28360,1192],{"class":437},[431,28362,4846],{"class":441},[431,28364,4463],{"class":437},[431,28366,28367],{"class":441},", []) ",[431,28369,8409],{"class":654},[431,28371,976],{"class":441},[431,28373,1192],{"class":437},[431,28375,4846],{"class":441},[431,28377,4463],{"class":437},[431,28379,28380],{"class":441},", [])  ",[431,28382,19945],{"class":455},[431,28384,28385,28387,28389,28391,28393,28395,28397,28399,28401,28404,28406,28408,28410,28412,28414,28416,28418,28420,28422,28424],{"class":433,"line":578},[431,28386,2996],{"class":441},[431,28388,26597],{"class":445},[431,28390,26306],{"class":441},[431,28392,1192],{"class":437},[431,28394,4846],{"class":441},[431,28396,26606],{"class":445},[431,28398,26306],{"class":441},[431,28400,651],{"class":437},[431,28402,28403],{"class":441},"} ",[431,28405,8409],{"class":654},[431,28407,3005],{"class":441},[431,28409,26606],{"class":445},[431,28411,26306],{"class":441},[431,28413,651],{"class":437},[431,28415,4846],{"class":441},[431,28417,26597],{"class":445},[431,28419,26306],{"class":441},[431,28421,1192],{"class":437},[431,28423,28294],{"class":441},[431,28425,19945],{"class":455},[415,28427,28428],{},"Словари равны, если порядок ключей разный — лишь бы были равны значения по соответствующим ключам и сами наборы ключей были одинаковыми.\nВот и множества равны, если содержат одинаковые наборы равных попарно элементов.",[458,28430,28432],{"id":28431},"объединение-множеств","Объединение множеств",[415,28434,28435,28436,8399,28439,28442],{},"По аналогии с множествами в математике, множества в Python поддерживают операцию ",[800,28437,28438],{},"объединения",[1355,28440,28441],{},"(union)",".\nЭта операция не объединяет множества, а возвращает новый объект.\nЭтот объект — это такое множество, которое содержит все элементы, содержащиеся хотя бы в одном из оригинальных множеств.\nПо смыслу объединение похоже на операцию \"ИЛИ\" из булевой логики: элемент будет присутствовать в объединении, если он присутствует в первом исходном множестве ИЛИ во втором.\nТак это выглядит на схеме:",[415,28444,28445],{},[15324,28446],{"alt":28432,"src":28447},"\u002Fimages\u002Fblog\u002Fpython\u002Fst19\u002Fimg1.webp",[415,28449,28450,28451,3562],{},"Для объединения множеств в Python используется оператор ",[428,28452,28453],{},"|",[422,28455,28457],{"className":424,"code":28456,"language":396,"meta":426,"style":426},"visited_by_masha = {\"Paris\", \"London\"}\nvisited_by_kolya = {\"Moscow\", \"Paris\"}\nvisited_by_kolya | visited_by_masha  # {'London', 'Moscow', 'Paris'}\n",[428,28458,28459,28478,28496],{"__ignoreMap":426},[431,28460,28461,28464,28466,28468,28471,28473,28476],{"class":433,"line":434},[431,28462,28463],{"class":441},"visited_by_masha ",[431,28465,1189],{"class":654},[431,28467,3005],{"class":441},[431,28469,28470],{"class":445},"\"Paris\"",[431,28472,4846],{"class":441},[431,28474,28475],{"class":445},"\"London\"",[431,28477,3236],{"class":441},[431,28479,28480,28483,28485,28487,28490,28492,28494],{"class":433,"line":452},[431,28481,28482],{"class":441},"visited_by_kolya ",[431,28484,1189],{"class":654},[431,28486,3005],{"class":441},[431,28488,28489],{"class":445},"\"Moscow\"",[431,28491,4846],{"class":441},[431,28493,28470],{"class":445},[431,28495,3236],{"class":441},[431,28497,28498,28500,28502,28505],{"class":433,"line":578},[431,28499,28482],{"class":441},[431,28501,28453],{"class":654},[431,28503,28504],{"class":441}," visited_by_masha  ",[431,28506,28507],{"class":455},"# {'London', 'Moscow', 'Paris'}\n",[458,28509,28511],{"id":28510},"пересечение-множеств","Пересечение множеств",[415,28513,28514,28515,8399,28518,28521],{},"Еще есть «операция И» — ",[800,28516,28517],{},"пересечение множеств",[1355,28519,28520],{},"(intersection)",". В пересечение входят элементы, присутствующие в первом из оригинальных множеств И во втором:",[415,28523,28524],{},[15324,28525],{"alt":28511,"src":28526},"\u002Fimages\u002Fblog\u002Fpython\u002Fst19\u002Fimg2.png",[415,28528,28529,28530,3562],{},"В Python оператор пересечения — ",[428,28531,28532],{},"&",[422,28534,28536],{"className":424,"code":28535,"language":396,"meta":426,"style":426},"visited_by_masha = {\"Paris\", \"London\"}\nvisited_by_kolya = {\"Moscow\", \"Paris\"}\nvisited_by_kolya & visited_by_masha  # {'Paris'}\n",[428,28537,28538,28554,28570],{"__ignoreMap":426},[431,28539,28540,28542,28544,28546,28548,28550,28552],{"class":433,"line":434},[431,28541,28463],{"class":441},[431,28543,1189],{"class":654},[431,28545,3005],{"class":441},[431,28547,28470],{"class":445},[431,28549,4846],{"class":441},[431,28551,28475],{"class":445},[431,28553,3236],{"class":441},[431,28555,28556,28558,28560,28562,28564,28566,28568],{"class":433,"line":452},[431,28557,28482],{"class":441},[431,28559,1189],{"class":654},[431,28561,3005],{"class":441},[431,28563,28489],{"class":445},[431,28565,4846],{"class":441},[431,28567,28470],{"class":445},[431,28569,3236],{"class":441},[431,28571,28572,28574,28576,28578],{"class":433,"line":578},[431,28573,28482],{"class":441},[431,28575,28532],{"class":654},[431,28577,28504],{"class":441},[431,28579,28580],{"class":455},"# {'Paris'}\n",[458,28582,28584],{"id":28583},"разность-множеств","Разность множеств",[415,28586,28587,8399,28589,28592],{},[800,28588,28584],{},[1355,28590,28591],{},"(difference)"," — такое множество, элементы которого содержатся в первом оригинальном множестве, но не содержатся во втором.\nРазность представлена оператором -, потому что по смыслу оператор похож на вычитание из арифметики:",[422,28594,28596],{"className":424,"code":28595,"language":396,"meta":426,"style":426},"visited_by_masha = {\"Paris\", \"London\"}\nvisited_by_kolya = {\"Moscow\", \"Paris\"}\nvisited_by_masha - visited_by_kolya  # {'London'}\nvisited_by_kolya - visited_by_masha  # {'Moscow'}\n",[428,28597,28598,28614,28630,28642],{"__ignoreMap":426},[431,28599,28600,28602,28604,28606,28608,28610,28612],{"class":433,"line":434},[431,28601,28463],{"class":441},[431,28603,1189],{"class":654},[431,28605,3005],{"class":441},[431,28607,28470],{"class":445},[431,28609,4846],{"class":441},[431,28611,28475],{"class":445},[431,28613,3236],{"class":441},[431,28615,28616,28618,28620,28622,28624,28626,28628],{"class":433,"line":452},[431,28617,28482],{"class":441},[431,28619,1189],{"class":654},[431,28621,3005],{"class":441},[431,28623,28489],{"class":445},[431,28625,4846],{"class":441},[431,28627,28470],{"class":445},[431,28629,3236],{"class":441},[431,28631,28632,28634,28636,28639],{"class":433,"line":578},[431,28633,28463],{"class":441},[431,28635,853],{"class":654},[431,28637,28638],{"class":441}," visited_by_kolya  ",[431,28640,28641],{"class":455},"# {'London'}\n",[431,28643,28644,28646,28648,28650],{"class":433,"line":584},[431,28645,28482],{"class":441},[431,28647,853],{"class":654},[431,28649,28504],{"class":441},[431,28651,28652],{"class":455},"# {'Moscow'}\n",[415,28654,28655,28656],{},"Так разность можно обозначить на схеме:\n",[15324,28657],{"alt":28584,"src":28658},"\u002Fimages\u002Fblog\u002Fpython\u002Fst19\u002Fimg3.png",[458,28660,28662],{"id":28661},"симметрическая-разность","Симметрическая разность",[415,28664,28665,8399,28667,28670],{},[800,28666,28662],{},[1355,28668,28669],{},"(symmetric difference)"," — множество, в которое входят элементы, присутствующие ЛИБО в первом, ЛИБО во втором оригинальном множестве:",[415,28672,28673],{},[15324,28674],{"alt":28662,"src":28675},"\u002Fimages\u002Fblog\u002Fpython\u002Fst19\u002Fimg4.png",[415,28677,28678,28679,28682,28683,3562],{},"По смыслу операция похожа на ",[800,28680,28681],{},"исключающее ИЛИ (xor)",", поэтому и представлена оператором ",[428,28684,28685],{},"^",[422,28687,28689],{"className":424,"code":28688,"language":396,"meta":426,"style":426},"visited_by_masha = {\"Paris\", \"London\"}\nvisited_by_kolya = {\"Moscow\", \"Paris\"}\nvisited_by_kolya ^ visited_by_masha  # {'London', 'Moscow'}\n",[428,28690,28691,28707,28723],{"__ignoreMap":426},[431,28692,28693,28695,28697,28699,28701,28703,28705],{"class":433,"line":434},[431,28694,28463],{"class":441},[431,28696,1189],{"class":654},[431,28698,3005],{"class":441},[431,28700,28470],{"class":445},[431,28702,4846],{"class":441},[431,28704,28475],{"class":445},[431,28706,3236],{"class":441},[431,28708,28709,28711,28713,28715,28717,28719,28721],{"class":433,"line":452},[431,28710,28482],{"class":441},[431,28712,1189],{"class":654},[431,28714,3005],{"class":441},[431,28716,28489],{"class":445},[431,28718,4846],{"class":441},[431,28720,28470],{"class":445},[431,28722,3236],{"class":441},[431,28724,28725,28727,28729,28731],{"class":433,"line":578},[431,28726,28482],{"class":441},[431,28728,28685],{"class":654},[431,28730,28504],{"class":441},[431,28732,28733],{"class":455},"# {'London', 'Moscow'}\n",[458,28735,28737],{"id":28736},"подмножества-и-надмножества","Подмножества и надмножества",[415,28739,28740,28741,28744,28745,28748],{},"Одно множество является ",[800,28742,28743],{},"подмножеством"," другого (subset), если все элементы первого входят во второе, но второе может содержать еще и другие элементы.\nВторое в этом случае является ",[800,28746,28747],{},"надмножеством"," для первого (superset):",[415,28750,28751],{},[15324,28752],{"alt":28737,"src":28753},"\u002Fimages\u002Fblog\u002Fpython\u002Fst19\u002Fimg5.png",[415,28755,28756,28757,3228,28760,3562],{},"При этом равные множества являются друг для друга одновременно и подмножествами и надмножествами.\nВ Python соотношение множеств можно проверить с помощью методов ",[428,28758,28759],{},"issubset",[428,28761,28762],{},"issuperset",[422,28764,28766],{"className":424,"code":28765,"language":396,"meta":426,"style":426},"a = {1, 2, 3, 4}\nb = {3, 4}\na.issubset(b) # False\n",[428,28767,28768,28792,28808],{"__ignoreMap":426},[431,28769,28770,28772,28774,28776,28778,28780,28782,28784,28786,28788,28790],{"class":433,"line":434},[431,28771,3193],{"class":441},[431,28773,1189],{"class":654},[431,28775,3005],{"class":441},[431,28777,1192],{"class":437},[431,28779,4846],{"class":441},[431,28781,651],{"class":437},[431,28783,4846],{"class":441},[431,28785,971],{"class":437},[431,28787,4846],{"class":441},[431,28789,762],{"class":437},[431,28791,3236],{"class":441},[431,28793,28794,28796,28798,28800,28802,28804,28806],{"class":433,"line":452},[431,28795,3203],{"class":441},[431,28797,1189],{"class":654},[431,28799,3005],{"class":441},[431,28801,971],{"class":437},[431,28803,4846],{"class":441},[431,28805,762],{"class":437},[431,28807,3236],{"class":441},[431,28809,28810,28813],{"class":433,"line":578},[431,28811,28812],{"class":441},"a.issubset(b) ",[431,28814,20020],{"class":455},[632,28816,28818],{"id":28817},"методы-объектов-множеств","Методы объектов множеств",[415,28820,28821],{},"Существуют операторы, которые позволяют различными способами комбинировать множества.\nЭти операторы максимально похожи на те, что применяются в теории множеств в математике.",[458,28823,28825],{"id":28824},"операции-над-множествами-как-методы","Операции над множествами как методы",[415,28827,28828],{},"С теорией множеств программисты обычно знакомы, хотя бы поверхностно. Поэтому множества нужно использовать в сочетании с операторами.\nОднако было бы неправильно умолчать, что у каждого оператора есть свой словесный метод-аналог. Познакомимся с этими методами-аналогами:",[422,28830,28832],{"className":424,"code":28831,"language":396,"meta":426,"style":426},"a.union(b)  # аналог \"a | b\"\na.intersection(b)  # аналог \"a & b\"\na.difference(b)  # аналог \"a - b\"\na.symmetric_difference(b)  # аналог \"a ^ b\"\n",[428,28833,28834,28842,28850,28858],{"__ignoreMap":426},[431,28835,28836,28839],{"class":433,"line":434},[431,28837,28838],{"class":441},"a.union(b)  ",[431,28840,28841],{"class":455},"# аналог \"a | b\"\n",[431,28843,28844,28847],{"class":433,"line":452},[431,28845,28846],{"class":441},"a.intersection(b)  ",[431,28848,28849],{"class":455},"# аналог \"a & b\"\n",[431,28851,28852,28855],{"class":433,"line":578},[431,28853,28854],{"class":441},"a.difference(b)  ",[431,28856,28857],{"class":455},"# аналог \"a - b\"\n",[431,28859,28860,28863],{"class":433,"line":584},[431,28861,28862],{"class":441},"a.symmetric_difference(b)  ",[431,28864,28865],{"class":455},"# аналог \"a ^ b\"\n",[458,28867,28869],{"id":28868},"обновление-множеств","Обновление множеств",[415,28871,28872,28873,28875],{},"Вспомним метод ",[428,28874,27051],{}," у словаря, который обновляет словарь «по месту» с помощью данных из другого словаря.\nТак вот, для множеств существует несколько таких update-методов:",[697,28877,28878,28881,28884,28887],{},[700,28879,28880],{},"difference_update",[700,28882,28883],{},"intersection_update",[700,28885,28886],{},"symmetric_difference_update",[700,28888,28889],{},"update\nРассмотрим их подробнее:",[1588,28891,28892],{},[700,28893,28894],{},"Метод difference_update работает похоже на difference. Он удаляет из связанного множества все элементы, которые входят в множество-аргумент:",[422,28896,28898],{"className":424,"code":28897,"language":396,"meta":426,"style":426},"a, b = {1, 2}, {2, 3}\na.difference_update(b)\nprint(a)  # {1}\n",[428,28899,28900,28926,28931],{"__ignoreMap":426},[431,28901,28902,28905,28907,28909,28911,28913,28915,28918,28920,28922,28924],{"class":433,"line":434},[431,28903,28904],{"class":441},"a, b ",[431,28906,1189],{"class":654},[431,28908,3005],{"class":441},[431,28910,1192],{"class":437},[431,28912,4846],{"class":441},[431,28914,651],{"class":437},[431,28916,28917],{"class":441},"}, {",[431,28919,651],{"class":437},[431,28921,4846],{"class":441},[431,28923,971],{"class":437},[431,28925,3236],{"class":441},[431,28927,28928],{"class":433,"line":452},[431,28929,28930],{"class":441},"a.difference_update(b)\n",[431,28932,28933,28935,28937],{"class":433,"line":578},[431,28934,438],{"class":437},[431,28936,19862],{"class":441},[431,28938,28939],{"class":455},"# {1}\n",[1588,28941,28942],{"start":452},[700,28943,28944],{},"Метод intersection_update и его изменяющий аналог intersection. Он оставляет в связанном множестве только те элементы, которые входят и в множество-аргумент:",[422,28946,28948],{"className":424,"code":28947,"language":396,"meta":426,"style":426},"a, b = {1, 2}, {2, 3}\na.intersection_update(b)\nprint(a)  # {1}\n",[428,28949,28950,28974,28979],{"__ignoreMap":426},[431,28951,28952,28954,28956,28958,28960,28962,28964,28966,28968,28970,28972],{"class":433,"line":434},[431,28953,28904],{"class":441},[431,28955,1189],{"class":654},[431,28957,3005],{"class":441},[431,28959,1192],{"class":437},[431,28961,4846],{"class":441},[431,28963,651],{"class":437},[431,28965,28917],{"class":441},[431,28967,651],{"class":437},[431,28969,4846],{"class":441},[431,28971,971],{"class":437},[431,28973,3236],{"class":441},[431,28975,28976],{"class":433,"line":452},[431,28977,28978],{"class":441},"a.intersection_update(b)\n",[431,28980,28981,28983,28985],{"class":433,"line":578},[431,28982,438],{"class":437},[431,28984,19862],{"class":441},[431,28986,28939],{"class":455},[1588,28988,28989],{"start":578},[700,28990,28991],{},"Метод symmetric_difference_update и его изменяющий аналог symmetric_difference.\nОн добавляет в связанное множество элементы, которые есть только в множестве-аргументе.\nТакже он удаляет элементы, которые есть в обоих множествах:",[422,28993,28995],{"className":424,"code":28994,"language":396,"meta":426,"style":426},"a, b = {1, 2}, {2, 3}\na.symmetric_difference_update(b)\nprint(a)  # {1, 3}\n",[428,28996,28997,29021,29026],{"__ignoreMap":426},[431,28998,28999,29001,29003,29005,29007,29009,29011,29013,29015,29017,29019],{"class":433,"line":434},[431,29000,28904],{"class":441},[431,29002,1189],{"class":654},[431,29004,3005],{"class":441},[431,29006,1192],{"class":437},[431,29008,4846],{"class":441},[431,29010,651],{"class":437},[431,29012,28917],{"class":441},[431,29014,651],{"class":437},[431,29016,4846],{"class":441},[431,29018,971],{"class":437},[431,29020,3236],{"class":441},[431,29022,29023],{"class":433,"line":452},[431,29024,29025],{"class":441},"a.symmetric_difference_update(b)\n",[431,29027,29028,29030,29032],{"class":433,"line":578},[431,29029,438],{"class":437},[431,29031,19862],{"class":441},[431,29033,29034],{"class":455},"# {1, 3}\n",[1588,29036,29037],{"start":584},[700,29038,29039],{},"Метод update и его изменяющий аналог union. Он дополняет связанное множество отсутствующими элементами из множества-аргумента:",[422,29041,29043],{"className":424,"code":29042,"language":396,"meta":426,"style":426},"a, b = {1, 2}, {2, 3}\na.update(b)\nprint(a)  # {1, 2, 3}\n",[428,29044,29045,29069,29074],{"__ignoreMap":426},[431,29046,29047,29049,29051,29053,29055,29057,29059,29061,29063,29065,29067],{"class":433,"line":434},[431,29048,28904],{"class":441},[431,29050,1189],{"class":654},[431,29052,3005],{"class":441},[431,29054,1192],{"class":437},[431,29056,4846],{"class":441},[431,29058,651],{"class":437},[431,29060,28917],{"class":441},[431,29062,651],{"class":437},[431,29064,4846],{"class":441},[431,29066,971],{"class":437},[431,29068,3236],{"class":441},[431,29070,29071],{"class":433,"line":452},[431,29072,29073],{"class":441},"a.update(b)\n",[431,29075,29076,29078,29080],{"class":433,"line":578},[431,29077,438],{"class":437},[431,29079,19862],{"class":441},[431,29081,27803],{"class":455},[415,29083,1849,29084,1853,29086,1857],{},[800,29085,1852],{},[800,29087,1856],{},[1859,29089],{},[1862,29091,29092],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}",{"title":426,"searchDepth":452,"depth":1244,"links":29094},[29095],{"id":27747,"depth":452,"text":27748,"children":29096},[29097,29100,29101,29102,29110],{"id":27757,"depth":578,"text":27758,"children":29098},[29099],{"id":27933,"depth":584,"text":27934},{"id":27990,"depth":578,"text":27991},{"id":28107,"depth":578,"text":28108},{"id":21174,"depth":578,"text":21175,"children":29103},[29104,29105,29106,29107,29108,29109],{"id":28242,"depth":584,"text":28243},{"id":28431,"depth":584,"text":28432},{"id":28510,"depth":584,"text":28511},{"id":28583,"depth":584,"text":28584},{"id":28661,"depth":584,"text":28662},{"id":28736,"depth":584,"text":28737},{"id":28817,"depth":578,"text":28818,"children":29111},[29112,29113],{"id":28824,"depth":584,"text":28825},{"id":28868,"depth":584,"text":28869},"2025-07-07","Синтаксис. Изменение множеств. Операции над множествами. Методы объектов множеств","images\u002Fblog\u002Fpython\u002Fst19\u002Fimg.png",{},{"title":230,"description":29115},"FU9yrk0iuCaNnrn-RzOijGiZxBBZv4yIaFqxQbl-IQk",{"id":29121,"title":238,"author":29122,"body":29124,"date":30472,"description":30473,"extension":1887,"image":30474,"meta":30475,"minRead":30476,"navigation":393,"num":2874,"path":239,"seo":30477,"stem":240,"__hash__":30478},"python\u002Fblog\u002Fpython\u002Fst20.md",{"name":402,"avatar":29123},{"src":404,"alt":405},{"type":407,"value":29125,"toc":30453},[29126,29129,29134,29141,29198,29201,29205,29208,29216,29219,29230,29240,29245,29248,29255,29269,29276,29294,29300,29360,29363,29382,29385,29392,29396,29399,29407,29423,29426,29501,29504,29507,29554,29560,29564,29567,29595,29598,29603,29617,29622,29640,29645,29665,29670,29694,29699,29722,29725,29763,29766,29771,29789,29794,29817,29822,29837,29840,29844,29847,29851,29854,29862,29865,29873,29876,29890,29893,29941,29944,29963,29966,29969,29976,29980,29983,29997,30000,30020,30027,30030,30104,30107,30146,30149,30152,30156,30159,30170,30177,30185,30188,30263,30266,30271,30275,30278,30286,30289,30296,30345,30352,30355,30363,30366,30370,30377,30385,30389,30392,30395,30398,30402,30411,30414,30417,30431,30436,30438,30442,30448,30450],[410,29127,238],{"id":29128},"хеш-таблицы",[29130,29131],"card-collapsible",{":isList":29132,"title":29133},"[\"Вы узнаете о хэш-таблицах как одной из базовых структур данных. Хеш-таблицы находят множество применений; В этой статье рассматриваются распространённые варианты использования.\",\"Вы изучите устройство хеш-таблиц: реализацию, хеш-функции и коллизии. Это поможет понять, как анализируется производительность хеш-таблицы.\"]","Из этой статьи вы узнаете",[415,29135,29136,29137,29140],{},"Представьте, что вы продавец в магазине. Когда клиент покупает товары, вы проверяете их цены по прайс-листу(по книге или таблице).\nЕсли записи не упорядочены по алфавиту и их очень много, то поиск, например, какого‑нибудь слова «персики» в каждой строке займёт слишком много времени.\nФактически, может получиться линейный поиск, где необходимо проверять каждую запись.\nЭто займёт времени: O(n).\nЕсли прайс-лист упорядочен по алфавиту, вы сможете воспользоваться бинарным поиском(",[1205,29138,29139],{"href":255},"что такое бинарный поиск?","),\nвремя выполнения которого составляет всего O(log n).\nПредположим вы можете посмотреть 10 записей за секунду. Вы знаете, что двоичный поиск работает очень быстро. Но сам процесс поиска — это каждый раз рутинная работа даже для отсортированного списка.\nПока осуществляется поиск — клиент ждёт. Гораздо удобнее было бы завести \"помощника\", который помнит все названия товаров и их цены.\nТогда ничего искать вообще не придётся: вы спрашиваете \"помощника\", а он мгновенно отвечает.\nПолучается что \"помощник\" может сообщать за время O(1) (почти мгновенно) цену любого товара. Соответственно он сработает ещё быстрее чем бинарный(двоичный) поиск.",[9256,29142,29143,29159],{},[9259,29144,29145],{},[9262,29146,29147,29150,29153,29156],{},[9265,29148,29149],{},"Кол-во элементов",[9265,29151,29152],{},"Простой поиск O(n)",[9265,29154,29155],{},"Бинарный поиск O(log n)",[9265,29157,29158],{},"\"Помощник\" O(1)",[9275,29160,29161,29174,29185],{},[9262,29162,29163,29165,29168,29171],{},[9280,29164,2249],{},[9280,29166,29167],{},"10 сек",[9280,29169,29170],{},"1 сек",[9280,29172,29173],{},"0.001 сек",[9262,29175,29176,29178,29181,29183],{},[9280,29177,27224],{},[9280,29179,29180],{},"1.6 мин",[9280,29182,29170],{},[9280,29184,29173],{},[9262,29186,29187,29190,29193,29196],{},[9280,29188,29189],{},"10000",[9280,29191,29192],{},"16.6 мин",[9280,29194,29195],{},"2 сек",[9280,29197,29173],{},[415,29199,29200],{},"Где взять такого помощника?\nОбратимся к структурам данных. Пока возможно вам известны две структуры данных: массивы и списки(о стеках речь не пойдёт, потому что в них нормальный поиск не возможен).\nПрайс-лист в магазине или книгу можно организовать в виде массива.\nНо каждый элемент такого прайс-листа или книги в массиве на самом деле состоит должен будет состоять из двух элементов: названия товара и цены.\nЕсли отсортировать массив по имени, вы сможете проводить по нему бинарный поиск для определения цены товара по его имени.\nЭто значит, что поиск будет выполняться за время O(log n). Но нам ведь нужен поиск или \"помощник\" который бы выдавал нам цену по имени практически мгновенно!\nВ этом нам помогут хеш-функция.",[632,29202,29204],{"id":29203},"хеш-функция","Хеш-функция",[415,29206,29207],{},"Хеш-функция представляет собой функцию, которая получает на вход строку и возвращает число.\nПо-научному говорят, что хеш-функция \"отображает строки на числа\".\nОднако, хеш-функция должна соответствовать некоторым требованиям.",[697,29209,29210,29213],{},[700,29211,29212],{},"Она должна быть последовательной. Допустим, вы передали ей строку \"яблоки\" и получили 5.\nЭто значит, что каждый раз в будущем передавая ей строку \"яблоки\", вы получите число 5. Без этого она бесполезна.",[700,29214,29215],{},"Разным словам должны соответствовать разные числа.\nНапример, хеш-функция, которая возвращает 1 для каждого полученного ею слова, никуда не годится.\nВ идеале каждое входное слово должно отображаться на своё число.",[415,29217,29218],{},"Зачем это нужно, чтобы хеш-функция связывала строки и числа? Это нужно, чтобы реализовать нашего \"помощника\".\nНачнём с пустого массива. Все цены будут храниться в этом массиве, передадим хеш-функции строку \"яблоки\".\nХеш-функция пусть вернёт нам значение \"5\". Сохраним цену яблок в элементе массива под индексом 5.\nДобавим хлеб. Передадим хеш-функции строку \"хлеб\". Получим число 3. Сохраним цену на хлеб в массиве под индексом 3 и т.д.\nПродолжать можно действовать так, и со временем весь массив будет заполнен ценами на товары.\nА теперь запрашиваете: сколько стоит \"хлеб\"?\nИскать в массиве при этом ничего не нужно. Нужно просто передать строку \"хлеб\" хеш-функции.\nРезультат скажет, что значение цены находится под индексом 3, мы цену оттуда и возьмём.\nПолучается, что хеш-функция всегда сообщает нам, где цена хранится. Такое решение работает потому что:",[697,29220,29221,29224,29227],{},[700,29222,29223],{},"Хеш функция неизменно связывает название с одним числом(индексом). Каждый раз, когда она вызывается для строки \"хлеб\",\nвы получаете от неё одно и то же число. При первом вызове этой функции вы узнаете, где следует сохранить цену товара,\nа при последующих вызовах она сообщает, где взять эту цену.",[700,29225,29226],{},"Хеш-функция связывает разные строки с разными числами. Для каждой строки получается своя позиция массива, в которой сохраняется цена товара.",[700,29228,29229],{},"Хеш-функция знает размер массива и должна возвращать только действительные индексы.\nТаким образом, если размер массива равен 20 элементам, хеш-функция не вернёт 100, потому что это значение не является действительным индексом.",[415,29231,29232,29233,29236,29237,2699],{},"Таким образом мы создали \"помощника\" по магазину который всегда знает цену по названию!\nСвязав воедино хеш-функцию и массив, мы получили структуру данных, которая называется ",[1355,29234,29235],{},"хеш-таблица",".\nХеш-таблица это первая структура данных, с которой связана дополнительная логика.\nМассивы и списки напрямую отображаются на адреса памяти, но хеш-таблицы устроены более умно.\nОни определяют место хранения элементов с помощью ",[1355,29238,29239],{},"хеш-функций",[8839,29241,29242],{},[415,29243,29244],{},"Выше мы только что рассмотрели идеальную хеш-функцию. Она связывает товар точно с отдельной позицией массива.\nВ реальности такого идеального однозначного сопоставления, скорее всего, не получится. Товарам придётся соседствовать.\nВ одной позиции будут находиться несколько товаров, а другие позиции останутся пустыми. Эту ситуацию мы обсудим ниже в разделе о коллизиях.\nЕщё взаимно-однозначное связывание называют инъективной функцией.",[415,29246,29247],{},"Вероятно хеш-таблицы станут самой полезной из сложных структур данных, с которой вы познакомитесь.\nОни также известны под другими названиями: \"ассоциативные массивы\", \"словари\", \"отображения\", \"хеш-карты\", или просто \"хеши\".\nПомните описание массивов и связанных списков? Обращение к элементу массива происходит мгновенно.\nА хеш-таблицы используют массивы для хранения данных, поэтому при обращении к элементам они не уступают массивам.",[415,29249,29250,29251,29254],{},"Ассоциативный массив — абстрактный тип данных, с помощью которого хранятся пары «ключ-значение».\nВ разных языках ему соответствуют разные типы данных.\nВ Python — это Dictionary, т.е. Словарь (",[1205,29252,29253],{"href":227},"что такое словарь Python","), в других языках:",[697,29256,29257,29260,29263,29266],{},[700,29258,29259],{},"Ruby — Hash",[700,29261,29262],{},"Lua — Table",[700,29264,29265],{},"JavaScript — Object",[700,29267,29268],{},"Elixir\u002FJava — Map",[415,29270,29271,29272,29275],{},"Ассоциативные массивы популярны в прикладном программировании.\nС их помощью удобно представлять составные данные, содержащие множество различных параметров.\nВ обычном индексированном массиве значения расположены по индексам, а значит его можно положить в память «как есть».\nС ассоциативными массивами все работает по-другому.\nУ них нет индексов, которые бы могли определить порядок — значит, и нет простого способа добраться до значений.\nДля реализации ассоциативных массивов часто используют специальную структуру данных — ",[800,29273,29274],{},"хеш-таблицу",".\nХеш-таблица позволяет организовать данные ассоциативного массива удобным для хранения способом.\nДля этого хеш-таблица использует индексированный массив и функцию для хеширования ключей.\nПри этом хеш-таблица — это не просто способ размещать данные в памяти, она включает в себя логику.\nПосмотрим, как ассоциативные массивы устроены внутри(они же хеш-таблицы).\nСкорее всего, вам никогда не придётся заниматься реализацией ассоциативных массивов или хеш-таблиц самостоятельно.\nВ любом приличном современном языке программирования высокого уровня существует их реализация.\nВ Python хеш-таблицы ещё называются словарями. Новая хеш-таблица задаётся пустыми фигурными скобками.\nРазберём подобный простой код на Python:",[422,29277,29279],{"className":424,"code":29278,"language":396,"meta":426,"style":426},"book = {} # book[\"key\"] = \"value\"\n",[428,29280,29281],{"__ignoreMap":426},[431,29282,29283,29286,29288,29291],{"class":433,"line":434},[431,29284,29285],{"class":441},"book ",[431,29287,1189],{"class":654},[431,29289,29290],{"class":441}," {} ",[431,29292,29293],{"class":455},"# book[\"key\"] = \"value\"\n",[415,29295,29296,29299],{},[428,29297,29298],{},"book"," – это новая хеш-таблица. Добавим в неё несколько цен:",[422,29301,29303],{"className":424,"code":29302,"language":396,"meta":426,"style":426},"book[\"яблоки\"] = 57.5\nbook[\"молоко\"] = 78.9\nbook[\"хлеб\"] = 52.5\nprint(book)\n# {'яблоки': 57.5, 'молоко': 78.9, 'хлеб': 52.5}\n",[428,29304,29305,29320,29334,29348,29355],{"__ignoreMap":426},[431,29306,29307,29310,29313,29315,29317],{"class":433,"line":434},[431,29308,29309],{"class":441},"book[",[431,29311,29312],{"class":445},"\"яблоки\"",[431,29314,4049],{"class":441},[431,29316,1189],{"class":654},[431,29318,29319],{"class":437}," 57.5\n",[431,29321,29322,29324,29327,29329,29331],{"class":433,"line":452},[431,29323,29309],{"class":441},[431,29325,29326],{"class":445},"\"молоко\"",[431,29328,4049],{"class":441},[431,29330,1189],{"class":654},[431,29332,29333],{"class":437}," 78.9\n",[431,29335,29336,29338,29341,29343,29345],{"class":433,"line":578},[431,29337,29309],{"class":441},[431,29339,29340],{"class":445},"\"хлеб\"",[431,29342,4049],{"class":441},[431,29344,1189],{"class":654},[431,29346,29347],{"class":437}," 52.5\n",[431,29349,29350,29352],{"class":433,"line":584},[431,29351,438],{"class":437},[431,29353,29354],{"class":441},"(book)\n",[431,29356,29357],{"class":433,"line":1244},[431,29358,29359],{"class":455},"# {'яблоки': 57.5, 'молоко': 78.9, 'хлеб': 52.5}\n",[415,29361,29362],{},"Пока всё просто! А теперь запросим цену для яблок.",[422,29364,29366],{"className":424,"code":29365,"language":396,"meta":426,"style":426},"print(book[\"яблоки\"]) # => 57.5 - цена\n",[428,29367,29368],{"__ignoreMap":426},[431,29369,29370,29372,29375,29377,29379],{"class":433,"line":434},[431,29371,438],{"class":437},[431,29373,29374],{"class":441},"(book[",[431,29376,29312],{"class":445},[431,29378,18021],{"class":441},[431,29380,29381],{"class":455},"# => 57.5 - цена\n",[415,29383,29384],{},"Хеш-таблица состоит из ключей и значений. В хеше book имена продуктов являются ключами, а цены – значениями.\nХеш-таблица связывает ключи со значениями.\nОчень важно, чтобы хеш-функции в хеш-таблицах были последовательными, то есть неизменно возвращали один и тот же результат для одинаковых входных данных.\nЕсли это условие будет нарушено, вы не сможете найти свой элемент после того, как он будет помещён в хеш-таблицу!",[29386,29387],"card-collapsible-num-answers",{":isAnswers":29388,":isList":29389,":startOl":1192,"isText":29390,"title":29391},"[\"Функция последовательна.\",\"Функция непоследовательна.\",\"Функция непоследовательна.\",\"Функция последовательна.\"]","[\"f(x) = 1 – возвращает 1 для любых входных значений\",\"f(x) = random.random() – возвращает случайное число\",\"f(x) = next_empty_slot() – возвращает индекс следующего пустого элемента в хеш-таблице\",\"f(x) = len(x) – возвращает длину полученной строки\"]","Какие из следующих функций являются последовательными?","УПРАЖНЕНИЯ",[632,29393,29395],{"id":29394},"что-такое-хеширование","Что такое хеширование",[415,29397,29398],{},"Любая операция внутри хеш-таблицы начинается с того, что ключ каким-то образом преобразуется в индекс обычного массива.\nДля получения индекса из ключа нужно выполнить два действия:",[697,29400,29401,29404],{},[700,29402,29403],{},"Найти хеш, то есть хэшировать ключ",[700,29405,29406],{},"Привести ключ к индексу — например, через остаток от деления",[415,29408,29409,29412,29413,29416,29417,9379,29420,2699],{},[800,29410,29411],{},"Хеширование"," — операция, которая преобразует любые входные данные в строку или число фиксированной длины.\nФункция, реализующая алгоритм преобразования, называется ",[1355,29414,29415],{},"«хеш-функцией»",".\nПри этом результат хеширования называют ",[1355,29418,29419],{},"«хешем»",[1355,29421,29422],{},"«хеш-суммой»",[415,29424,29425],{},"Наиболее известны CRC32, MD5, SHA и много других типов хеширования:",[422,29427,29429],{"className":424,"code":29428,"language":396,"meta":426,"style":426},"# В Python есть библиотека zlib, содержащая алгоритм хеширования crc32\n# Этот алгоритм удобен для наглядности\nimport zlib\n\n# Любые данные, которые мы хотим хешировать, представляются в виде байтовой строки\ndata = b\"Hello, python!\"\nhash = zlib.crc32(data)\n\n# Хеш всегда одинаковый для одних и тех же данных\nprint(hash)  # => 3159842700\n",[428,29430,29431,29436,29441,29448,29452,29457,29469,29479,29483,29488],{"__ignoreMap":426},[431,29432,29433],{"class":433,"line":434},[431,29434,29435],{"class":455},"# В Python есть библиотека zlib, содержащая алгоритм хеширования crc32\n",[431,29437,29438],{"class":433,"line":452},[431,29439,29440],{"class":455},"# Этот алгоритм удобен для наглядности\n",[431,29442,29443,29445],{"class":433,"line":578},[431,29444,5379],{"class":654},[431,29446,29447],{"class":441}," zlib\n",[431,29449,29450],{"class":433,"line":584},[431,29451,1662],{"emptyLinePlaceholder":393},[431,29453,29454],{"class":433,"line":1244},[431,29455,29456],{"class":455},"# Любые данные, которые мы хотим хешировать, представляются в виде байтовой строки\n",[431,29458,29459,29461,29463,29466],{"class":433,"line":1985},[431,29460,3499],{"class":441},[431,29462,1189],{"class":654},[431,29464,29465],{"class":654}," b",[431,29467,29468],{"class":445},"\"Hello, python!\"\n",[431,29470,29471,29474,29476],{"class":433,"line":2041},[431,29472,29473],{"class":437},"hash",[431,29475,2146],{"class":654},[431,29477,29478],{"class":441}," zlib.crc32(data)\n",[431,29480,29481],{"class":433,"line":4018},[431,29482,1662],{"emptyLinePlaceholder":393},[431,29484,29485],{"class":433,"line":4030},[431,29486,29487],{"class":455},"# Хеш всегда одинаковый для одних и тех же данных\n",[431,29489,29490,29492,29494,29496,29498],{"class":433,"line":4419},[431,29491,438],{"class":437},[431,29493,442],{"class":441},[431,29495,29473],{"class":437},[431,29497,526],{"class":441},[431,29499,29500],{"class":455},"# => 3159842700\n",[415,29502,29503],{},"С хешированием мы встречаемся в разработке.\nНапример, идентификатор commit в git d7834a94 — это хеш, полученный в результате хеширования данных \"коммита\".",[415,29505,29506],{},"При записи в хеш-таблицу сначала нужно получить хеш.\nЗатем его можно преобразовать в индекс массива — например, вычислить остаток от деления:",[422,29508,29510],{"className":424,"code":29509,"language":396,"meta":426,"style":426},"# Это делается для того, чтобы индексы не были слишком большими\n# Чем больше размер массива, тем больше памяти он занимает\nindex = abs(hash) % 1000  # по модулю\nprint(index)  # => 700\n",[428,29511,29512,29517,29522,29544],{"__ignoreMap":426},[431,29513,29514],{"class":433,"line":434},[431,29515,29516],{"class":455},"# Это делается для того, чтобы индексы не были слишком большими\n",[431,29518,29519],{"class":433,"line":452},[431,29520,29521],{"class":455},"# Чем больше размер массива, тем больше памяти он занимает\n",[431,29523,29524,29526,29528,29530,29532,29534,29536,29538,29541],{"class":433,"line":578},[431,29525,18485],{"class":441},[431,29527,1189],{"class":654},[431,29529,4683],{"class":437},[431,29531,442],{"class":441},[431,29533,29473],{"class":437},[431,29535,1014],{"class":441},[431,29537,8667],{"class":654},[431,29539,29540],{"class":437}," 1000",[431,29542,29543],{"class":455},"  # по модулю\n",[431,29545,29546,29548,29551],{"class":433,"line":584},[431,29547,438],{"class":437},[431,29549,29550],{"class":441},"(index)  ",[431,29552,29553],{"class":455},"# => 700\n",[415,29555,29556],{},[15324,29557],{"alt":29558,"src":29559},"Пример использования хеш-функции","\u002Fimages\u002Fblog\u002Fpython\u002Fst20\u002Fimg1.png",[458,29561,29563],{"id":29562},"как-хеширование-работает-изнутри","Как хеширование работает изнутри",[415,29565,29566],{},"Рассмотрим, как работает добавление нового значения в ассоциативный массив.\nНапомним, в Python он представлен типом данных Dictionary. Напишем такой код:",[422,29568,29570],{"className":424,"code":29569,"language":396,"meta":426,"style":426},"data = {}\ndata[\"key\"] = \"value\"\n",[428,29571,29572,29581],{"__ignoreMap":426},[431,29573,29574,29576,29578],{"class":433,"line":434},[431,29575,3499],{"class":441},[431,29577,1189],{"class":654},[431,29579,29580],{"class":441}," {}\n",[431,29582,29583,29585,29588,29590,29592],{"class":433,"line":452},[431,29584,3603],{"class":441},[431,29586,29587],{"class":445},"\"key\"",[431,29589,4049],{"class":441},[431,29591,1189],{"class":654},[431,29593,29594],{"class":445}," \"value\"\n",[415,29596,29597],{},"Такой простой код запускает целый сложный процесс.\nДля простоты рассмотрим его на Python, хотя в реальности все это происходит на более низком уровне.\nОпишем процесс хеширования без деталей и с упрощенным кодом.",[1588,29599,29600],{},[700,29601,29602],{},"Мы создаем ассоциативный массив. Внутри интерпретатора происходит инициализация индексированного массива:",[422,29604,29606],{"className":424,"code":29605,"language":396,"meta":426,"style":426},"internal = [] \n",[428,29607,29608],{"__ignoreMap":426},[431,29609,29610,29613,29615],{"class":433,"line":434},[431,29611,29612],{"class":441},"internal ",[431,29614,1189],{"class":654},[431,29616,21007],{"class":441},[1588,29618,29619],{"start":452},[700,29620,29621],{},"Далее мы присваиваем значение:",[422,29623,29625],{"className":424,"code":29624,"language":396,"meta":426,"style":426},"data['key'] = \"value\" \n",[428,29626,29627],{"__ignoreMap":426},[431,29628,29629,29631,29634,29636,29638],{"class":433,"line":434},[431,29630,3603],{"class":441},[431,29632,29633],{"class":445},"'key'",[431,29635,4049],{"class":441},[431,29637,1189],{"class":654},[431,29639,29594],{"class":445},[1588,29641,29642],{"start":578},[700,29643,29644],{},"Затем интерпретатор хэширует ключ. Результатом хеширования становится число:",[422,29646,29648],{"className":424,"code":29647,"language":396,"meta":426,"style":426},"hash = zlib.crc32(b'key') \n",[428,29649,29650],{"__ignoreMap":426},[431,29651,29652,29654,29656,29659,29661,29663],{"class":433,"line":434},[431,29653,29473],{"class":437},[431,29655,2146],{"class":654},[431,29657,29658],{"class":441}," zlib.crc32(",[431,29660,3233],{"class":654},[431,29662,29633],{"class":445},[431,29664,449],{"class":441},[1588,29666,29667],{"start":584},[700,29668,29669],{},"Далее интерпретатор берет число из предыдущего шага и преобразует его в индекс массива:",[422,29671,29673],{"className":424,"code":29672,"language":396,"meta":426,"style":426},"index = abs(hash) % 1000\n",[428,29674,29675],{"__ignoreMap":426},[431,29676,29677,29679,29681,29683,29685,29687,29689,29691],{"class":433,"line":434},[431,29678,18485],{"class":441},[431,29680,1189],{"class":654},[431,29682,4683],{"class":437},[431,29684,442],{"class":441},[431,29686,29473],{"class":437},[431,29688,1014],{"class":441},[431,29690,8667],{"class":654},[431,29692,29693],{"class":437}," 1000\n",[1588,29695,29696],{"start":1244},[700,29697,29698],{},"В конце интерпретатор ищет по индексу значение внутреннего индексированного массива и записывает его в еще один массив.\nПервым элементом нового массива становится ключ 'key', а вторым — значение 'value':",[422,29700,29702],{"className":424,"code":29701,"language":396,"meta":426,"style":426},"internal[index] = [\"key\", \"value\"] \n",[428,29703,29704],{"__ignoreMap":426},[431,29705,29706,29709,29711,29713,29715,29717,29720],{"class":433,"line":434},[431,29707,29708],{"class":441},"internal[index] ",[431,29710,1189],{"class":654},[431,29712,17401],{"class":441},[431,29714,29587],{"class":445},[431,29716,4846],{"class":441},[431,29718,29719],{"class":445},"\"value\"",[431,29721,3568],{"class":441},[415,29723,29724],{},"Теперь посмотрим, как работает чтение данных:",[422,29726,29728],{"className":424,"code":29727,"language":396,"meta":426,"style":426},"data = {}\ndata[\"key\"] = \"value\"\nprint(data[\"key\"])  # => \"value\"\n",[428,29729,29730,29738,29750],{"__ignoreMap":426},[431,29731,29732,29734,29736],{"class":433,"line":434},[431,29733,3499],{"class":441},[431,29735,1189],{"class":654},[431,29737,29580],{"class":441},[431,29739,29740,29742,29744,29746,29748],{"class":433,"line":452},[431,29741,3603],{"class":441},[431,29743,29587],{"class":445},[431,29745,4049],{"class":441},[431,29747,1189],{"class":654},[431,29749,29594],{"class":445},[431,29751,29752,29754,29756,29758,29760],{"class":433,"line":578},[431,29753,438],{"class":437},[431,29755,3511],{"class":441},[431,29757,29587],{"class":445},[431,29759,3305],{"class":441},[431,29761,29762],{"class":455},"# => \"value\"\n",[415,29764,29765],{},"Разберем, как этот код работает изнутри:",[1588,29767,29768],{},[700,29769,29770],{},"Интерпретатор хеширует ключ. Результатом хеширования становится число:",[422,29772,29773],{"className":424,"code":29647,"language":396,"meta":426,"style":426},[428,29774,29775],{"__ignoreMap":426},[431,29776,29777,29779,29781,29783,29785,29787],{"class":433,"line":434},[431,29778,29473],{"class":437},[431,29780,2146],{"class":654},[431,29782,29658],{"class":441},[431,29784,3233],{"class":654},[431,29786,29633],{"class":445},[431,29788,449],{"class":441},[1588,29790,29791],{"start":452},[700,29792,29793],{},"Число, полученное на предыдущем шаге, преобразуется в индекс массива:",[422,29795,29797],{"className":424,"code":29796,"language":396,"meta":426,"style":426},"index = abs(hash % 1000)\n",[428,29798,29799],{"__ignoreMap":426},[431,29800,29801,29803,29805,29807,29809,29811,29813,29815],{"class":433,"line":434},[431,29802,18485],{"class":441},[431,29804,1189],{"class":654},[431,29806,4683],{"class":437},[431,29808,442],{"class":441},[431,29810,29473],{"class":437},[431,29812,784],{"class":654},[431,29814,29540],{"class":437},[431,29816,449],{"class":441},[1588,29818,29819],{"start":578},[700,29820,29821],{},"Если индекс существует, то интерпретатор извлекает массив и возвращает его наружу:",[422,29823,29825],{"className":424,"code":29824,"language":396,"meta":426,"style":426},"return internal[index] # ['key', 'value']\n",[428,29826,29827],{"__ignoreMap":426},[431,29828,29829,29831,29834],{"class":433,"line":434},[431,29830,10507],{"class":654},[431,29832,29833],{"class":441}," internal[index] ",[431,29835,29836],{"class":455},"# ['key', 'value']\n",[415,29838,29839],{},"В следующем разделе приведены примеры использования хеш-таблиц.",[632,29841,29843],{"id":29842},"примеры-использования-хеш-таблиц","Примеры использования хеш-таблиц",[415,29845,29846],{},"Хеш-таблицы повсеместно используют на практике. Рассмотрим некоторые примеры.",[458,29848,29850],{"id":29849},"хеш-таблица-для-поиска","Хеш-таблица для поиска",[415,29852,29853],{},"В смартфоне есть удобная встроенная телефонная книга. С каждым именем связывается номер телефона.\nПредположим, вы хотите построить такую телефонную книгу. Имена людей в этой книге связываются с номерами.\nТелефонная книга должна поддерживать следующие функции:",[697,29855,29856,29859],{},[700,29857,29858],{},"добавление имени человека и номера телефона, связанного с этим именем;",[700,29860,29861],{},"получение номера телефона, связанного с введенным именем.",[415,29863,29864],{},"Такая задача идеально подходит для хеш-таблиц! Хеш-таблицы отлично работают, когда вы хотите:",[697,29866,29867,29870],{},[700,29868,29869],{},"создать связь, отображающую один объект на другой;",[700,29871,29872],{},"найти значение в списке.",[415,29874,29875],{},"Построить телефонную книгу, в общем-то, несложно. Начнём с создания хеш-таблицы:",[422,29877,29879],{"className":424,"code":29878,"language":396,"meta":426,"style":426},"phone_book = {}\n",[428,29880,29881],{"__ignoreMap":426},[431,29882,29883,29886,29888],{"class":433,"line":434},[431,29884,29885],{"class":441},"phone_book ",[431,29887,1189],{"class":654},[431,29889,29580],{"class":441},[415,29891,29892],{},"Добавим в телефонную книгу несколько номеров:",[422,29894,29896],{"className":424,"code":29895,"language":396,"meta":426,"style":426},"phone_book[\"Иван\"] = 8654329\nphone_book[\"Саша\"] = 8656654\nphone_book[\"Маша\"] = 8658321\n",[428,29897,29898,29913,29927],{"__ignoreMap":426},[431,29899,29900,29903,29906,29908,29910],{"class":433,"line":434},[431,29901,29902],{"class":441},"phone_book[",[431,29904,29905],{"class":445},"\"Иван\"",[431,29907,4049],{"class":441},[431,29909,1189],{"class":654},[431,29911,29912],{"class":437}," 8654329\n",[431,29914,29915,29917,29920,29922,29924],{"class":433,"line":452},[431,29916,29902],{"class":441},[431,29918,29919],{"class":445},"\"Саша\"",[431,29921,4049],{"class":441},[431,29923,1189],{"class":654},[431,29925,29926],{"class":437}," 8656654\n",[431,29928,29929,29931,29934,29936,29938],{"class":433,"line":578},[431,29930,29902],{"class":441},[431,29932,29933],{"class":445},"\"Маша\"",[431,29935,4049],{"class":441},[431,29937,1189],{"class":654},[431,29939,29940],{"class":437}," 8658321\n",[415,29942,29943],{},"Теперь предположим, что вы хотите найти номер телефона Ивана. Просто передайте ключ хешу:",[422,29945,29947],{"className":424,"code":29946,"language":396,"meta":426,"style":426},"print(phone_book[\"Иван\"]) # => 8654329\n",[428,29948,29949],{"__ignoreMap":426},[431,29950,29951,29953,29956,29958,29960],{"class":433,"line":434},[431,29952,438],{"class":437},[431,29954,29955],{"class":441},"(phone_book[",[431,29957,29905],{"class":445},[431,29959,18021],{"class":441},[431,29961,29962],{"class":455},"# => 8654329\n",[415,29964,29965],{},"Представьте, то же самое пришлось бы реализовывать через массив. Как бы вы это сделали?\nХеш-таблицы упрощают моделирование отношений между объектами.\nХеш-таблицы используются для поиска соответствий в гораздо большем масштабе.\nНапример, вы хотите перейти на веб-сайт – допустим, ashtana.ru\nВаш компьютер должен преобразовать символьное имя ashtana.ru в IP-адрес:\nashtana.ru — 216.198.79.1",[415,29967,29968],{},"Для любого веб-сайта его имя преобразуется в IP-адрес:\ngoogle.com — 142.250.185.238\ndzen.ru — 83.222.28.15\nvk.com — 87.240.137.164",[415,29970,29971,29972,29975],{},"Связать символьное имя с IP-адресом? Идеальная задача для хеш-таблиц! Этот процесс называется ",[1355,29973,29974],{},"преобразованием DNS",".\nХеш-таблицы — всего лишь один из способов реализации такой функциональности.\nНа компьютерах существует кэш DNS, в котором хранятся подобные сопоставления для недавно посещенных сайтов.",[458,29977,29979],{"id":29978},"исключение-дубликатов","Исключение дубликатов",[415,29981,29982],{},"Предположим, вы проводите голосование. Естественно, каждый голосующий может проголосовать только один раз.\nКак проверить, что он не голосовал повторно? Когда человек приходит голосовать, вы узнаёте его полное имя, а затем проверяете по списку уже проголосовавших.\nЕсли имя входит в список, значит, этот человек уже проголосовал! В противном случае вы добавляете имя в список и разрешаете ему проголосовать.\nДалее предположим, что желающих проголосовать много и список уже проголосовавших достаточно велик.\nКаждый раз, когда кто-то приходит голосовать, вы вынуждены просматривать этот гигантский список и проверять, голосовал ли человек или нет.\nОднако, существует более эффективное решение: воспользоваться хешем!\nСначала создадим хеш-таблицу для хранения информации об уже проголосовавших людях:",[422,29984,29986],{"className":424,"code":29985,"language":396,"meta":426,"style":426},"voted = {}\n",[428,29987,29988],{"__ignoreMap":426},[431,29989,29990,29993,29995],{"class":433,"line":434},[431,29991,29992],{"class":441},"voted ",[431,29994,1189],{"class":654},[431,29996,29580],{"class":441},[415,29998,29999],{},"Когда кто-то приходит голосовать, проверьте, присутствует ли его имя в хеше:",[422,30001,30003],{"className":424,"code":30002,"language":396,"meta":426,"style":426},"vote = \"Александр Сергеевич Пушкин\" in voted\n",[428,30004,30005],{"__ignoreMap":426},[431,30006,30007,30010,30012,30015,30017],{"class":433,"line":434},[431,30008,30009],{"class":441},"vote ",[431,30011,1189],{"class":654},[431,30013,30014],{"class":445}," \"Александр Сергеевич Пушкин\"",[431,30016,21531],{"class":654},[431,30018,30019],{"class":441}," voted\n",[415,30021,30022,30023,30026],{},"Переменная ",[428,30024,30025],{},"vote"," принимает значение True, если такой ключ \"Александр Сергеевич Пушкин\" есть в хеш-таблице.\nВ противном случае она принимает значение False. С помощью этой функции можно проверить, голосовал ли человек ранее или нет!",[415,30028,30029],{},"Примерный код может выглядеть так:",[422,30031,30033],{"className":424,"code":30032,"language":396,"meta":426,"style":426},"voted = {}\n\ndef check_voter(name):\n  if name in voted:\n    print(\"Уже голосовал!\")\n  else:\n    voted[name] = True\n    print(\"Допустить к голосованию!\")\n",[428,30034,30035,30043,30047,30056,30067,30078,30084,30093],{"__ignoreMap":426},[431,30036,30037,30039,30041],{"class":433,"line":434},[431,30038,29992],{"class":441},[431,30040,1189],{"class":654},[431,30042,29580],{"class":441},[431,30044,30045],{"class":433,"line":452},[431,30046,1662],{"emptyLinePlaceholder":393},[431,30048,30049,30051,30054],{"class":433,"line":578},[431,30050,6330],{"class":654},[431,30052,30053],{"class":6333}," check_voter",[431,30055,13557],{"class":441},[431,30057,30058,30060,30062,30064],{"class":433,"line":584},[431,30059,20480],{"class":654},[431,30061,9800],{"class":441},[431,30063,14421],{"class":654},[431,30065,30066],{"class":441}," voted:\n",[431,30068,30069,30071,30073,30076],{"class":433,"line":1244},[431,30070,6357],{"class":437},[431,30072,442],{"class":441},[431,30074,30075],{"class":445},"\"Уже голосовал!\"",[431,30077,449],{"class":441},[431,30079,30080,30082],{"class":433,"line":1985},[431,30081,21994],{"class":654},[431,30083,8102],{"class":441},[431,30085,30086,30089,30091],{"class":433,"line":2041},[431,30087,30088],{"class":441},"    voted[name] ",[431,30090,1189],{"class":654},[431,30092,10188],{"class":437},[431,30094,30095,30097,30099,30102],{"class":433,"line":4018},[431,30096,6357],{"class":437},[431,30098,442],{"class":441},[431,30100,30101],{"class":445},"\"Допустить к голосованию!\"",[431,30103,449],{"class":441},[415,30105,30106],{},"Протестируем на нескольких примерах:",[422,30108,30110],{"className":424,"code":30109,"language":396,"meta":426,"style":426},"check_voted(\"Иван\") # Допустить к голосованию!\ncheck_voted(\"Алесандр\") # Допустить к голосованию!\ncheck_voted(\"Иван\") # Уже голосовал!\n",[428,30111,30112,30124,30135],{"__ignoreMap":426},[431,30113,30114,30117,30119,30121],{"class":433,"line":434},[431,30115,30116],{"class":441},"check_voted(",[431,30118,29905],{"class":445},[431,30120,1014],{"class":441},[431,30122,30123],{"class":455},"# Допустить к голосованию!\n",[431,30125,30126,30128,30131,30133],{"class":433,"line":452},[431,30127,30116],{"class":441},[431,30129,30130],{"class":445},"\"Алесандр\"",[431,30132,1014],{"class":441},[431,30134,30123],{"class":455},[431,30136,30137,30139,30141,30143],{"class":433,"line":578},[431,30138,30116],{"class":441},[431,30140,29905],{"class":445},[431,30142,1014],{"class":441},[431,30144,30145],{"class":455},"# Уже голосовал!\n",[415,30147,30148],{},"Когда Иван голосует первый раз, программа разрешает ему проголосовать. Потом приходит Александр, который также допускается к голосованию.\nНо вдруг снова приходит Иван, чтобы проголосовать снова! И на этот раз у него ничего не получится!",[415,30150,30151],{},"Если бы имена проголосовавших хранились в списке, то выполнение функции со временем замедлилось бы, потому что функции пришлось бы проводить простой поиск по всему списку.\nНо имена хранятся в хеш-таблице, а она почти мгновенно сообщает, присутствует ли человек в списке голосовавших или нет.\nПроверка дубликатов происходит очень быстро!",[458,30153,30155],{"id":30154},"использование-хеш-таблицы-как-кэша","Использование хеш-таблицы как кэша",[415,30157,30158],{},"Последний пример: кэширование. Если вы создаёте веб-сайт, то вероятно, уже слышали о пользе кэширования.\nОбщая идея кэширования такова: допустим, вы заходите на сайт.",[1588,30160,30161,30164,30167],{},[700,30162,30163],{},"Вы обращаетесь с запросом к серверу;",[700,30165,30166],{},"Сервер ненадолго задумывается, генерирует веб-страницу и отправляет её вам;",[700,30168,30169],{},"Вы получаете и просматриваете веб-страницу.",[415,30171,30172,30173,30176],{},"Например, VK сервер может собирать информацию о действиях всех ваших друзей, чтобы представить её вам.\nНа то, чтобы собрать всю информацию и представить её вам требуется пара секунд.\nСервер просто заранее сам вычисляет, запоминает, а когда вы делаете запрос просто выдаёт готовый ответ.\nТак работает механизм кэширования. Сайт просто запоминает данные заранее, и вместо того чтобы их пересчитывать, выдаёт сразу ответ пользователю.\nТакой механизм как ",[1355,30174,30175],{},"кэширование"," обладает следующими преимуществами:",[697,30178,30179,30182],{},[700,30180,30181],{},"Вы получаете документ, например веб-страницу, намного быстрее, как и в том случае, когда вы заранее запомнили ответ на вопрос;",[700,30183,30184],{},"Серверу сайта с механизмом кэширования приходится выполнять меньше работы при очередном одинаковом запросе от пользователей.",[415,30186,30187],{},"Когда вы посещаете сайт у которого настроено кэширование, сервер сайта сначала проверяет, хранится ли страница в кэше.\nВот примерный псевдокод на Python как это может быть:",[422,30189,30191],{"className":424,"code":30190,"language":396,"meta":426,"style":426},"cache = {}\ndef get_page(url):\n  if url in cache:\n    return cache[url]\n  else:\n    data = get_data_from_server(url)\n    cache[url] = data\n    return data\n",[428,30192,30193,30202,30212,30224,30231,30237,30247,30257],{"__ignoreMap":426},[431,30194,30195,30198,30200],{"class":433,"line":434},[431,30196,30197],{"class":441},"cache ",[431,30199,1189],{"class":654},[431,30201,29580],{"class":441},[431,30203,30204,30206,30209],{"class":433,"line":452},[431,30205,6330],{"class":654},[431,30207,30208],{"class":6333}," get_page",[431,30210,30211],{"class":441},"(url):\n",[431,30213,30214,30216,30219,30221],{"class":433,"line":578},[431,30215,20480],{"class":654},[431,30217,30218],{"class":441}," url ",[431,30220,14421],{"class":654},[431,30222,30223],{"class":441}," cache:\n",[431,30225,30226,30228],{"class":433,"line":584},[431,30227,6599],{"class":654},[431,30229,30230],{"class":441}," cache[url]\n",[431,30232,30233,30235],{"class":433,"line":1244},[431,30234,21994],{"class":654},[431,30236,8102],{"class":441},[431,30238,30239,30242,30244],{"class":433,"line":1985},[431,30240,30241],{"class":441},"    data ",[431,30243,1189],{"class":654},[431,30245,30246],{"class":441}," get_data_from_server(url)\n",[431,30248,30249,30252,30254],{"class":433,"line":2041},[431,30250,30251],{"class":441},"    cache[url] ",[431,30253,1189],{"class":654},[431,30255,30256],{"class":441}," data\n",[431,30258,30259,30261],{"class":433,"line":4018},[431,30260,6599],{"class":654},[431,30262,30256],{"class":441},[415,30264,30265],{},"Такой сервер выполняет работу только в том случае, если URL не хранится в кэше. Однако перед тем, как возвращать данные, вы сохраняете их в кэше.\nКогда пользователь в следующий раз запросит тот же URL-адрес, данные(хорошо бы ещё проверять при условии, что они не изменились!) отправляются пользователю из кэша(вместо вычислений на сервере).",[29130,30267],{":isList":30268,"title":30269,"isText":30270},"[\"Моделирование отношений между объектами;\",\"Устранение дубликатов;\",\"Кэширование\u002Fзапоминание данных вместо выполнения работы на сервере.\"]","ШПАРГАЛКА","Хеши хорошо подходят для решения следующих задач",[632,30272,30274],{"id":30273},"коллизии","Коллизии",[415,30276,30277],{},"Прежде чем понять какое быстродействие у хеш-таблиц, необходимо понять, что такое коллизия.\nКлючом в ассоциативном массиве или хеш-таблицы может быть абсолютно любая строка, любой длины и содержания.\nНо здесь есть одно противоречие:",[697,30279,30280,30283],{},[700,30281,30282],{},"Все возможные ключи — это бесконечное множество;",[700,30284,30285],{},"В качестве результата хеш-функция выдает строку фиксированной длины, то есть все выходные значения — это конечное множество.",[415,30287,30288],{},"Из этого факта следует, что не для всех входных данных найдется уникальный хеш.\nНа каком-то этапе могут появиться дубли: под одним хешем будут лежать несколько разных значений.",[415,30290,30291,30292,30295],{},"Такую ситуацию принято называть ",[1355,30293,30294],{},"коллизией",". Есть несколько способов разрешения коллизий.\nКаждому способу соответствует свой тип хеш-таблицы:",[422,30297,30299],{"className":424,"code":30298,"language":396,"meta":426,"style":426},"# Пример коллизии\n# Хеш-функция возвращает одинаковый хеш для разных строчных данных\nimport zlib\nzlib.crc32(b\"aaaaa0.462031558722291\")  # 1938556049\nzlib.crc32(b\"aaaaa0.0585754039730588\")  # 1938556049\n",[428,30300,30301,30306,30311,30317,30332],{"__ignoreMap":426},[431,30302,30303],{"class":433,"line":434},[431,30304,30305],{"class":455},"# Пример коллизии\n",[431,30307,30308],{"class":433,"line":452},[431,30309,30310],{"class":455},"# Хеш-функция возвращает одинаковый хеш для разных строчных данных\n",[431,30312,30313,30315],{"class":433,"line":578},[431,30314,5379],{"class":654},[431,30316,29447],{"class":441},[431,30318,30319,30322,30324,30327,30329],{"class":433,"line":584},[431,30320,30321],{"class":441},"zlib.crc32(",[431,30323,3233],{"class":654},[431,30325,30326],{"class":445},"\"aaaaa0.462031558722291\"",[431,30328,526],{"class":441},[431,30330,30331],{"class":455},"# 1938556049\n",[431,30333,30334,30336,30338,30341,30343],{"class":433,"line":1244},[431,30335,30321],{"class":441},[431,30337,3233],{"class":654},[431,30339,30340],{"class":445},"\"aaaaa0.0585754039730588\"",[431,30342,526],{"class":441},[431,30344,30331],{"class":455},[415,30346,30347,30348,30351],{},"Простейший способ разрешения коллизий — это ",[1355,30349,30350],{},"открытая адресация",".\nОна предполагает последовательное перемещение по слотам хеш-таблицы в поисках первого свободного слота, куда значение будет записано.",[415,30353,30354],{},"Второй простейший способ разрешения коллизий выглядит так: если несколько \"ключей\" хеш-таблицы отображаются после хеш-функции на один элемент, то по этому адресу сначала создаётся связанный список, а затем оба элемента по которым происходит коллизия сохраняются в этот список.\nНапример, у нас в хеш-таблице строки \"апельсины\" и \"яблоки\", отображаются на один элемент после работы хш-функции, тогда в элементе хеш-таблицы создаётся связанный список.\nЕсли в дальнейшем потребуется узнать цену \"апельсинов\" или \"яблок\", работа пойдёт чуть медленнее так как провести поиск необходимо будет ещё и по связанному списку, чтобы найти уже в нём цену \"апельсинов\" или \"яблок\".\nЕсли связанный список мал, это не так страшно – поиск будет ограничен тремя или четырьмя элементами.\nНо если после работы хеш-функции все данные окажутся в одном связанном списке, то ситуация не лучше той, когда все элементы сразу бы хранились в связанном списке.\nИз этого следуют два вывода:",[697,30356,30357,30360],{},[700,30358,30359],{},"выбор хеш-функции действительно очень важен. В идеале хеш-функция должна распределять ключи по всему хешу – равномерно;",[700,30361,30362],{},"если связанные списки становятся слишком длинными, работа с хеш-таблицей сильно замедляется.",[415,30364,30365],{},"Хеш-функции играют важнейшую роль! Хорошая хеш-функция создаёт минимальное количество коллизий! Как выбрать хорошую хеш-функцию?",[632,30367,30369],{"id":30368},"быстродействие","Быстродействие",[415,30371,30372,30373,30376],{},"В среднем хеш-таблицы выполняют любые операции за время O(1). Время O(1) называется ",[1355,30374,30375],{},"постоянным временем выполнения",".\nЭто время означает, что операции выполняются почти мгновенно, само время выполнения зависит только от того как его выдаст исполнитель операции и является постоянным независимо от размера хеш-таблицы.\nПри любом размере хеш-таблицы — 1 элемент или 1 миллиард элементов — выборка данных займёт одинаковое время.\nЕщё как пример постоянного времени выполнения: выборка элемента из массива по индексу.\nПри сравнении хеш-таблицы с массивами и списками получается, что хорошие хеш-таблицы не уступают в скорости массивам при получении данных.\nА при вставке и удалении они также быстры как связанные списки! Получается что они берут лучшее из этих обеих структур!\nНо в худшем же случае они медленно выполняют все операции! Поэтому важно избегать худших случаев при работе с хеш-таблицами.\nА для этого следует избегать коллизий. Для предотвращения коллизий необходимы:",[697,30378,30379,30382],{},[700,30380,30381],{},"Хорошая хеш-функция;",[700,30383,30384],{},"Низкий коэффициент заполнения хеш-таблицы.",[458,30386,30388],{"id":30387},"коэффициент-заполнения","Коэффициент заполнения",[415,30390,30391],{},"Коэффициент заполнения хеш-таблицы вычисляется по простой формуле: количество элементов в таблице разделить на общее всех элементов.",[415,30393,30394],{},"Хеш-таблицы используют массив для хранения данных, поэтому для вычисления коэффициента заполнения можно подсчитать количество заполненных элементов в массиве(количество элементов в массиве разделить на размер массива).",[415,30396,30397],{},"Предположим, в хеш-таблице нужно сохранить цены 100 товаров и хеш-таблица состоит из 100 элементов.\nВ лучшем случае каждому товару будет выделен отдельный элемент.\nКоэффициент заполнения этой хеш-таблицы тогда будет равен 1.\nА если хеш-таблица состоит всего из 50 элементов?\nТогда её коэффициент заполнения будет равен 2.\nВыделить под каждый товар отдельный элемент ни при каких условиях не удастся, потому что элементов попросту не хватит.\nКоэффициент заполнения больше 1 означает, что количество элементов превышает количество свободных для них мест.\nС ростом коэффициента заполнения размер хеш-таблицы нужно изменить. Хеш-таблицу необходимо расширить.\nРасширение начинается с создания массива большего размера. Обычно в таком случае создаётся массив вдвое большего размера.\nЗатем все элементы необходимо заново вставить в новую хеш-таблицу через её же хеш-функцию.\nС меньшим коэффициентом заполнения число коллизий также уменьшается!\nХорошее приближённое правило: расширять хеш-таблицу если коэффициент заполнения приближается к 0.7.\nНо ведь на изменение размеров может уйти много времени и и вычислительных ресурсов? Да, и поэтому изменение размера не должно происходить часто!\nВ среднем же хеш-таблицы работают за время O(1) даже с изменением размеров.",[458,30399,30401],{"id":30400},"хорошая-хеш-функция","Хорошая хеш-функция",[415,30403,30404,30405,30410],{},"Вот мы и добрались до финального понимания хорошей хеш-функции!\nХорошая хеш-функция должна обеспечивать равномерное распределение значений в хеш-таблице!\nПлохая хеш-функция создаёт скопления и порождает множество коллизий!\nКакую же хеш-функцию считать хорошей? Опять спросите вы.\nДумаю, нам никогда не придётся об этом беспокоиться — пусть об этом думают умные люди в тёмных кабинет Google, Yandex и т.п. компаний.\nЕсли вам действительно интересно, рассмотрите фукнцию например, ",[1205,30406,30409],{"href":30407,"rel":30408},"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fcityhash",[1209],"CityHash",". Именно её использует Google Abseil.\nAbseil — это набор библиотек C++ с открытым исходным кодом, созданных на основе самых фундаментальных элементов внутренней кодовой базы Google.\nAbseil лежит в основе кода, который пишут в Google, поэтому если в ней используется такая хеш-функция как CityHash, можно быть уверенным, что это функция как минимум неплоха.\nСмело применяйте её для своей хеш-таблицы!",[415,30412,30413],{},"Очень важно, чтобы хеш-функция обеспечивала хорошее распределение! Она должна распределять значения как можно шире!\nХудший случай — хеш-функция, которая отображает все входные строки на одну позицию в хеш-таблице!",[415,30415,30416],{},"Предположим, имеются четыре хеш-функции, которые получают строки.",[1588,30418,30419,30422,30425,30428],{},[700,30420,30421],{},"Функция возвращает 1 для любого входного значения.",[700,30423,30424],{},"Функция возвращает длину строки в качестве ключа хеш-таблицы.",[700,30426,30427],{},"Функция возвращает первый символ строки в качестве индекса. Таким образом, все строки, начинающиеся с \"а\", хешируются в одну позицию.",[700,30429,30430],{},"Функция сначала ставит в соответствие каждой букве простое число: a = 1, b = 2, c = 3 и т.д. Для строки хеш-функцией далее становится остаток от деления суммы всех значений на размер хеша. Например, если размер хеша равен 10, то для строки \"age\" будет вычислен индекс или ключ (1 + 7 + 5) % 10 = 13 % 10 = 3.",[29386,30432],{":isAnswers":30433,":isList":30434,":startOl":856,"isText":30435,"title":29391},"[\"Хеш-функции 3 и 4 обеспечивают лучшее распределение чем 1 и 2.\",\"Хеш-функции 2 и 4 обеспечивают лучшее распределении чем 1 и 3.\",\"Хеш-функции 2, 3, 4 обеспечивают лучшее распредление чем 1.\"]","[\"Телефонная книга, в которой ключами являются имена, а значениями – номера телефонов. Задан следующий список имён: Иван, Пётр, Нина, Павел.\",\"Связь размера батареек с напряжением. Размеры батареек: A, AA, AAA, AAAA.\",\"Связь названий книг с именами авторов. Названия книг: \\\"Мышь\\\", \\\"Весёлый дом\\\", \\\"Хранитель\\\"\"]","В каком из примеров четырёх хеш-функций описанных выше будет хорошее распределение? Считайте что, хеш-таблица содержит 10 элементов.",[458,30437],{"id":426},[29130,30439],{":isList":30440,"title":30269,"isText":30441},"[\"Хеш-таблица создаётся объединением хеш-функции с массивом;\",\"Коллизии максимально нежелательны. Необходимо сводить количество коллизий с помощью хорошей хеш-фукнции к минимуму;\",\"Хеш-таблицы обеспечивают очень быстрое выполнение поиска, вставки и удаления;\",\"Хеш-таблицы хорошо подходят для моделирования отношений между объектами;\",\"Как только коэффициент заполнения хеш-таблицы превышает 0.7, пора изменять размер хеш-таблицы;\",\"Хеш-таблицы можно применять для кэширования данных;\",\"Хеш-таблицы хорошо подходят для обнаружения дубликатов.\"]","Хеш-таблицы чрезвычайно полезны, потому что они обеспечивают высокую скорость операций и позволяют по-разному моделировать данные.",[415,30443,1849,30444,1853,30446,1857],{},[800,30445,1852],{},[800,30447,1856],{},[1859,30449],{},[1862,30451,30452],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":426,"searchDepth":452,"depth":1244,"links":30454},[30455],{"id":29128,"depth":452,"text":238,"children":30456},[30457,30458,30461,30466,30467],{"id":29203,"depth":578,"text":29204},{"id":29394,"depth":578,"text":29395,"children":30459},[30460],{"id":29562,"depth":584,"text":29563},{"id":29842,"depth":578,"text":29843,"children":30462},[30463,30464,30465],{"id":29849,"depth":584,"text":29850},{"id":29978,"depth":584,"text":29979},{"id":30154,"depth":584,"text":30155},{"id":30273,"depth":578,"text":30274},{"id":30368,"depth":578,"text":30369,"children":30468},[30469,30470,30471],{"id":30387,"depth":584,"text":30388},{"id":30400,"depth":584,"text":30401},{"id":426,"depth":584,"text":426},"2025-12-11","Как работает хеш‑функция. Устройство и практическое применение хеш‑таблиц. Коллизии в хеш-таблицах и их разрешение. Производительность и примеры хеш-функций.","images\u002Fblog\u002Fpython\u002Fst20\u002Fimg.png",{},41,{"title":238,"description":30473},"O0W80aPXY3n-O3ctCtAuUEkgCg6QKakO1v8kQE142CQ",{"id":30480,"title":242,"author":30481,"body":30483,"date":30944,"description":30488,"extension":1887,"image":30945,"meta":30946,"minRead":1985,"navigation":393,"num":12887,"path":243,"seo":30947,"stem":244,"__hash__":30948},"python\u002Fblog\u002Fpython\u002Fst21.md",{"name":402,"avatar":30482},{"src":404,"alt":405},{"type":407,"value":30484,"toc":30941},[30485,30489,30494,30497,30514,30517,30520,30523,30526,30533,30794,30797,30929,30936,30938],[410,30486,30488],{"id":30487},"решето-эратосфена-алгоритм-определения-простых-чисел","Решето Эратосфена - алгоритм определения простых чисел",[415,30490,30491,30493],{},[800,30492,242],{}," – это алгоритм нахождения простых чисел до заданного натурального числа путем постепенного отсеивания составных чисел. Образно говоря, через решето Эратосфена в процессе его тряски проскакивают составные числа, а простые остаются в решете.",[415,30495,30496],{},"Чтобы понять данный алгоритм, вспомним, что числа являются простыми, если делятся только на единицу и самих себя. Первое простое число - это 2, второе простое число - это 3. Теперь начнем рассуждать:",[1588,30498,30499,30502,30505,30508,30511],{},[700,30500,30501],{},"Все четные числа, кроме двойки – составные, т. е. не являются простыми, так как делятся не только на себя и единицу, а также еще на 2.",[700,30503,30504],{},"Все числа кратные трем, кроме самой тройки – составные, так как делятся не только на самих себя и единицу, а также еще на 3.",[700,30506,30507],{},"Число 4 уже выбыло из игры, так как делится на 2.",[700,30509,30510],{},"Число 5 простое, так как его не делит ни один простой делитель, стоящий до него.",[700,30512,30513],{},"Если число не делится ни на одно простое число, стоящее до него, значит оно не будет делиться ни на одно сложное число, стоящее до него.",[415,30515,30516],{},"Последний пункт вытекает из того, что сложные числа всегда можно представить как произведение простых. Поэтому если одно сложное число делится на другое сложное, то первое должно делиться на делители второго. Например, 12 делится на 6, делителями которого являются 2 и 3. Число 12 делится и на 2, и на 3.",[415,30518,30519],{},"Алгоритм Эратосфена как раз заключается в последовательной проверке делимости чисел на предстоящие простые числа. Сначала берется первое простое и из ряда натуральных чисел высеиваются все кратные ему. Затем берется следующее простое и отсеиваются все кратные ему и так далее.",[415,30521,30522],{},"При реализации алгоритма Эратосфена на языке программирования есть некоторая сложность. Допустим, мы помещаем натуральные числа до заданного числа N в массив. Далее в процессе выполнения алгоритма будем заменять обнаруженные сложные числа нулями. После выполнения алгоритма те ячейки массива, которые не содержат нули, содержат простые числа, которые выводятся на экран.",[415,30524,30525],{},"Однако индексация массива начинается с нуля, а простые числа начинаются с двойки. Эта проблема решаема, но добавляет сложности в код. Поскольку алгоритм Эратосфена не такой уж простой, легче пренебречь началом и взять массив от 0 до N. Здесь важнее индексы, чем значения элементов. Значениями могут быть логические True, обозначающее простое число, и False, обозначающее сложное число.",[415,30527,30528,30529,30532],{},"В данном примере ",[800,30530,30531],{},"реализации алгоритма Эратосфена на языке программирования Python"," список заполняется числами от 0 до N включительно так, что индексы элементов совпадают с их значениями. Далее все непростые числа заменяются нулями:",[422,30534,30536],{"className":424,"code":30535,"language":396,"meta":426,"style":426},"N = int(input())\n\n# Создается список из значений от 0 до N включительно\nprimes = [i for i in range(N + 1)]\n\n# Вторым элементом списка является единица, которую\n# не считают простым числом. Забиваем ее нулем\nprimes[1] = 0\n\n# Начинаем с 3-го элемента\ni = 2\nwhile i \u003C= N:\n    # Если значение текущей ячейки до этого не было обнулено,\n    # значит в этой ячейке содержится простое число\n    if primes[i] != 0:\n        # Первое кратное ему будет в два раза больше\n        j = i + i\n        while j \u003C= N:\n            # и это число составное,\n            # поэтому заменяем его нулем\n            primes[j] = 0\n            # переходим к следующему числу,\n            # которое кратно i (оно на i больше)\n            j = j + i\n    i += 1\n\n# Избавляемся от всех нулей в списке\nprimes = [i for i in primes if i != 0]\nprint(primes)\n",[428,30537,30538,30555,30559,30564,30592,30596,30601,30606,30619,30623,30628,30636,30647,30652,30657,30670,30675,30688,30700,30705,30710,30719,30724,30729,30742,30750,30754,30759,30786],{"__ignoreMap":426},[431,30539,30540,30543,30545,30547,30549,30552],{"class":433,"line":434},[431,30541,30542],{"class":441},"N ",[431,30544,1189],{"class":654},[431,30546,4312],{"class":437},[431,30548,442],{"class":441},[431,30550,30551],{"class":437},"input",[431,30553,30554],{"class":441},"())\n",[431,30556,30557],{"class":433,"line":452},[431,30558,1662],{"emptyLinePlaceholder":393},[431,30560,30561],{"class":433,"line":578},[431,30562,30563],{"class":455},"# Создается список из значений от 0 до N включительно\n",[431,30565,30566,30569,30571,30574,30576,30578,30580,30582,30585,30587,30589],{"class":433,"line":584},[431,30567,30568],{"class":441},"primes ",[431,30570,1189],{"class":654},[431,30572,30573],{"class":441}," [i ",[431,30575,14329],{"class":654},[431,30577,12664],{"class":441},[431,30579,14421],{"class":654},[431,30581,14424],{"class":437},[431,30583,30584],{"class":441},"(N ",[431,30586,802],{"class":654},[431,30588,1032],{"class":437},[431,30590,30591],{"class":441},")]\n",[431,30593,30594],{"class":433,"line":1244},[431,30595,1662],{"emptyLinePlaceholder":393},[431,30597,30598],{"class":433,"line":1985},[431,30599,30600],{"class":455},"# Вторым элементом списка является единица, которую\n",[431,30602,30603],{"class":433,"line":2041},[431,30604,30605],{"class":455},"# не считают простым числом. Забиваем ее нулем\n",[431,30607,30608,30611,30613,30615,30617],{"class":433,"line":4018},[431,30609,30610],{"class":441},"primes[",[431,30612,1192],{"class":437},[431,30614,4049],{"class":441},[431,30616,1189],{"class":654},[431,30618,3459],{"class":437},[431,30620,30621],{"class":433,"line":4030},[431,30622,1662],{"emptyLinePlaceholder":393},[431,30624,30625],{"class":433,"line":4419},[431,30626,30627],{"class":455},"# Начинаем с 3-го элемента\n",[431,30629,30630,30632,30634],{"class":433,"line":4436},[431,30631,3454],{"class":441},[431,30633,1189],{"class":654},[431,30635,658],{"class":437},[431,30637,30638,30640,30642,30644],{"class":433,"line":4446},[431,30639,12737],{"class":654},[431,30641,12664],{"class":441},[431,30643,12667],{"class":654},[431,30645,30646],{"class":441}," N:\n",[431,30648,30649],{"class":433,"line":4451},[431,30650,30651],{"class":455},"    # Если значение текущей ячейки до этого не было обнулено,\n",[431,30653,30654],{"class":433,"line":4086},[431,30655,30656],{"class":455},"    # значит в этой ячейке содержится простое число\n",[431,30658,30659,30661,30664,30666,30668],{"class":433,"line":4477},[431,30660,10438],{"class":654},[431,30662,30663],{"class":441}," primes[i] ",[431,30665,10686],{"class":654},[431,30667,9744],{"class":437},[431,30669,8102],{"class":441},[431,30671,30672],{"class":433,"line":4482},[431,30673,30674],{"class":455},"        # Первое кратное ему будет в два раза больше\n",[431,30676,30677,30680,30682,30684,30686],{"class":433,"line":4488},[431,30678,30679],{"class":441},"        j ",[431,30681,1189],{"class":654},[431,30683,12664],{"class":441},[431,30685,802],{"class":654},[431,30687,14375],{"class":441},[431,30689,30690,30693,30696,30698],{"class":433,"line":4505},[431,30691,30692],{"class":654},"        while",[431,30694,30695],{"class":441}," j ",[431,30697,12667],{"class":654},[431,30699,30646],{"class":441},[431,30701,30702],{"class":433,"line":12871},[431,30703,30704],{"class":455},"            # и это число составное,\n",[431,30706,30707],{"class":433,"line":2874},[431,30708,30709],{"class":455},"            # поэтому заменяем его нулем\n",[431,30711,30712,30715,30717],{"class":433,"line":12887},[431,30713,30714],{"class":441},"            primes[j] ",[431,30716,1189],{"class":654},[431,30718,3459],{"class":437},[431,30720,30721],{"class":433,"line":12892},[431,30722,30723],{"class":455},"            # переходим к следующему числу,\n",[431,30725,30726],{"class":433,"line":12898},[431,30727,30728],{"class":455},"            # которое кратно i (оно на i больше)\n",[431,30730,30731,30734,30736,30738,30740],{"class":433,"line":12904},[431,30732,30733],{"class":441},"            j ",[431,30735,1189],{"class":654},[431,30737,30695],{"class":441},[431,30739,802],{"class":654},[431,30741,14375],{"class":441},[431,30743,30744,30746,30748],{"class":433,"line":8382},[431,30745,12653],{"class":441},[431,30747,12563],{"class":654},[431,30749,3916],{"class":437},[431,30751,30752],{"class":433,"line":25829},[431,30753,1662],{"emptyLinePlaceholder":393},[431,30755,30756],{"class":433,"line":25838},[431,30757,30758],{"class":455},"# Избавляемся от всех нулей в списке\n",[431,30760,30761,30763,30765,30767,30769,30771,30773,30776,30778,30780,30782,30784],{"class":433,"line":1890},[431,30762,30568],{"class":441},[431,30764,1189],{"class":654},[431,30766,30573],{"class":441},[431,30768,14329],{"class":654},[431,30770,12664],{"class":441},[431,30772,14421],{"class":654},[431,30774,30775],{"class":441}," primes ",[431,30777,10399],{"class":654},[431,30779,12664],{"class":441},[431,30781,10686],{"class":654},[431,30783,9744],{"class":437},[431,30785,3568],{"class":441},[431,30787,30789,30791],{"class":433,"line":30788},29,[431,30790,438],{"class":437},[431,30792,30793],{"class":441},"(primes)\n",[415,30795,30796],{},"Пример выполнения:",[422,30798,30800],{"className":424,"code":30799,"language":396,"meta":426,"style":426},"100\n[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]\n",[428,30801,30802,30806],{"__ignoreMap":426},[431,30803,30804],{"class":433,"line":434},[431,30805,4673],{"class":437},[431,30807,30808,30810,30812,30814,30816,30818,30820,30822,30824,30826,30828,30830,30832,30834,30837,30839,30842,30844,30847,30849,30852,30854,30857,30859,30862,30864,30867,30869,30872,30874,30877,30879,30882,30884,30887,30889,30892,30894,30897,30899,30902,30904,30907,30909,30912,30914,30917,30919,30922,30924,30927],{"class":433,"line":452},[431,30809,19914],{"class":441},[431,30811,651],{"class":437},[431,30813,4846],{"class":441},[431,30815,971],{"class":437},[431,30817,4846],{"class":441},[431,30819,856],{"class":437},[431,30821,4846],{"class":441},[431,30823,781],{"class":437},[431,30825,4846],{"class":441},[431,30827,9573],{"class":437},[431,30829,4846],{"class":441},[431,30831,16889],{"class":437},[431,30833,4846],{"class":441},[431,30835,30836],{"class":437},"17",[431,30838,4846],{"class":441},[431,30840,30841],{"class":437},"19",[431,30843,4846],{"class":441},[431,30845,30846],{"class":437},"23",[431,30848,4846],{"class":441},[431,30850,30851],{"class":437},"29",[431,30853,4846],{"class":441},[431,30855,30856],{"class":437},"31",[431,30858,4846],{"class":441},[431,30860,30861],{"class":437},"37",[431,30863,4846],{"class":441},[431,30865,30866],{"class":437},"41",[431,30868,4846],{"class":441},[431,30870,30871],{"class":437},"43",[431,30873,4846],{"class":441},[431,30875,30876],{"class":437},"47",[431,30878,4846],{"class":441},[431,30880,30881],{"class":437},"53",[431,30883,4846],{"class":441},[431,30885,30886],{"class":437},"59",[431,30888,4846],{"class":441},[431,30890,30891],{"class":437},"61",[431,30893,4846],{"class":441},[431,30895,30896],{"class":437},"67",[431,30898,4846],{"class":441},[431,30900,30901],{"class":437},"71",[431,30903,4846],{"class":441},[431,30905,30906],{"class":437},"73",[431,30908,4846],{"class":441},[431,30910,30911],{"class":437},"79",[431,30913,4846],{"class":441},[431,30915,30916],{"class":437},"83",[431,30918,4846],{"class":441},[431,30920,30921],{"class":437},"89",[431,30923,4846],{"class":441},[431,30925,30926],{"class":437},"97",[431,30928,3568],{"class":441},[415,30930,30931,30932,1853,30934,1857],{},"Попробуйте сами запустить код в окне ниже с интерпретатором Python и повторите примеры из статьи чтобы самим увидеть и понять как всё это работает. Для этого в ячейке с кодом нажмите клавиши на клавиатуре ",[800,30933,1852],{},[800,30935,1856],{},[1859,30937],{},[1862,30939,30940],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":30942},[30943],{"id":30487,"depth":452,"text":30488},"2024-10-15","images\u002Fblog\u002Fpython\u002Fst21\u002Fimg.png",{},{"title":242,"description":30488},"SM2J5UQu3HutrCufQ-TtHutjoOayGACsdNzoSvtpJE0",{"id":30950,"title":246,"author":30951,"body":30953,"date":30944,"description":32121,"extension":1887,"image":32122,"meta":32123,"minRead":4030,"navigation":393,"num":12892,"path":247,"seo":32124,"stem":248,"__hash__":32125},"python\u002Fblog\u002Fpython\u002Fst22.md",{"name":402,"avatar":30952},{"src":404,"alt":405},{"type":407,"value":30954,"toc":32111},[30955,30959,30962,30969,30972,30975,30978,30981,30985,30989,30992,31285,31290,31294,31297,31681,31686,31690,31693,32090,32095,32100,32106,32108],[410,30956,30958],{"id":30957},"многоразрядные-целые-числа-задачи-длинной-арифметики","Многоразрядные целые числа, задачи длинной арифметики",[415,30960,30961],{},"Многоразрядные целые числа, или числа большой длины, используются для представления и работы с очень большими числами, которые не могут быть представлены использованием обычных типов данных, таких как int или long. В общем случае, числа большой длины могут иметь произвольное количество разрядов и могут быть положительными или отрицательными.",[415,30963,30964,30965,30968],{},"Данные числа представляются в виде массива или списка цифр, где каждый элемент массива или элемент списка представляет один разряд числа. Например, число 123456789 будет представлено ",[800,30966,30967],{},"в виде массива [1, 2, 3, 4, 5, 6, 7, 8, 9]."," Каждая цифра представлена отдельным элементом, что позволяет представлять числа любой длины.",[632,30970,246],{"id":30971},"длинная-арифметика",[415,30973,30974],{},"Длинная арифметика обеспечивает возможность выполнения математических операций с числами большой длины, например, сложение, вычитание, умножение, деление, возведение в степень и извлечение корня. Операции выполняются по разрядам числа, начиная с самого младшего разряда и двигаясь в старшие разряды. При выполнении операций, для учета переносов и заёмов используются алгоритмы, полагающиеся на основные математические свойства чисел.",[415,30976,30977],{},"Задачи длинной арифметики широко используются в различных областях, включая криптографию, вычислительную математику, анализ данных, обработку изображений и большие вычисления. Они позволяют работать с очень большими числами требующие точности и точных результатов, а также обеспечивают возможность работы с числами, которые не могут быть представлены в ограниченных типах данных.",[415,30979,30980],{},"Важно отметить, что задачи длинной арифметики могут быть вычислительно сложными из-за большого количества операций, которые необходимо выполнить для каждой операции. Поэтому эффективные алгоритмы и структуры данных используются для оптимизации производительности операций с числами большой длины.",[632,30982,30984],{"id":30983},"примеры-задач-реализации-вычислений-с-многоразрядными-числами","Примеры задач реализации вычислений с многоразрядными числами",[458,30986,30988],{"id":30987},"задача-1","Задача 1",[415,30990,30991],{},"Напишите код программы на Python. Реализуйте функцию для сложения двух многоразрядных чисел, представленных в виде строк.",[422,30993,30995],{"className":424,"code":30994,"language":396,"meta":426,"style":426},"def add_multidigit_numbers(num1, num2):\n    carry = 0\n    result = []\n    \n    # Выравнивание длины чисел, добавление нулей в начало\n    if len(num1) > len(num2):\n        num2 = num2.zfill(len(num1))\n    else:\n        num1 = num1.zfill(len(num2))\n    \n    # Сложение цифр справа налево\n    for i in range(len(num1) - 1, -1, -1):\n        digit_sum = int(num1[i]) + int(num2[i]) + carry\n        digit = digit_sum % 10\n        carry = digit_sum \u002F\u002F 10\n        result.insert(0, str(digit))\n    \n    # Добавление остатка\n    if carry:\n        result.insert(0, str(carry))\n  \n    return \"\".join(result)\n    \nnum1 = \"123456789\"\nnum2 = \"987654321\"\nsum = add_multidigit_numbers(num1, num2)\nprint(sum) # Выводит \"1111111110\"\n",[428,30996,30997,31007,31016,31024,31029,31034,31050,31065,31071,31086,31090,31095,31129,31153,31168,31181,31195,31199,31204,31211,31224,31229,31239,31243,31253,31263,31272],{"__ignoreMap":426},[431,30998,30999,31001,31004],{"class":433,"line":434},[431,31000,6330],{"class":654},[431,31002,31003],{"class":6333}," add_multidigit_numbers",[431,31005,31006],{"class":441},"(num1, num2):\n",[431,31008,31009,31012,31014],{"class":433,"line":452},[431,31010,31011],{"class":441},"    carry ",[431,31013,1189],{"class":654},[431,31015,3459],{"class":437},[431,31017,31018,31020,31022],{"class":433,"line":578},[431,31019,6796],{"class":441},[431,31021,1189],{"class":654},[431,31023,21007],{"class":441},[431,31025,31026],{"class":433,"line":584},[431,31027,31028],{"class":441},"    \n",[431,31030,31031],{"class":433,"line":1244},[431,31032,31033],{"class":455},"    # Выравнивание длины чисел, добавление нулей в начало\n",[431,31035,31036,31038,31040,31043,31045,31047],{"class":433,"line":1985},[431,31037,10438],{"class":654},[431,31039,4804],{"class":437},[431,31041,31042],{"class":441},"(num1) ",[431,31044,8883],{"class":654},[431,31046,4804],{"class":437},[431,31048,31049],{"class":441},"(num2):\n",[431,31051,31052,31055,31057,31060,31062],{"class":433,"line":2041},[431,31053,31054],{"class":441},"        num2 ",[431,31056,1189],{"class":654},[431,31058,31059],{"class":441}," num2.zfill(",[431,31061,5205],{"class":437},[431,31063,31064],{"class":441},"(num1))\n",[431,31066,31067,31069],{"class":433,"line":4018},[431,31068,10575],{"class":654},[431,31070,8102],{"class":441},[431,31072,31073,31076,31078,31081,31083],{"class":433,"line":4030},[431,31074,31075],{"class":441},"        num1 ",[431,31077,1189],{"class":654},[431,31079,31080],{"class":441}," num1.zfill(",[431,31082,5205],{"class":437},[431,31084,31085],{"class":441},"(num2))\n",[431,31087,31088],{"class":433,"line":4419},[431,31089,31028],{"class":441},[431,31091,31092],{"class":433,"line":4436},[431,31093,31094],{"class":455},"    # Сложение цифр справа налево\n",[431,31096,31097,31099,31101,31103,31105,31107,31109,31111,31113,31115,31117,31119,31121,31123,31125,31127],{"class":433,"line":4446},[431,31098,14745],{"class":654},[431,31100,12664],{"class":441},[431,31102,14421],{"class":654},[431,31104,14424],{"class":437},[431,31106,442],{"class":441},[431,31108,5205],{"class":437},[431,31110,31042],{"class":441},[431,31112,853],{"class":654},[431,31114,1032],{"class":437},[431,31116,4846],{"class":441},[431,31118,853],{"class":654},[431,31120,1192],{"class":437},[431,31122,4846],{"class":441},[431,31124,853],{"class":654},[431,31126,1192],{"class":437},[431,31128,7381],{"class":441},[431,31130,31131,31134,31136,31138,31141,31143,31145,31148,31150],{"class":433,"line":4451},[431,31132,31133],{"class":441},"        digit_sum ",[431,31135,1189],{"class":654},[431,31137,4312],{"class":437},[431,31139,31140],{"class":441},"(num1[i]) ",[431,31142,802],{"class":654},[431,31144,4312],{"class":437},[431,31146,31147],{"class":441},"(num2[i]) ",[431,31149,802],{"class":654},[431,31151,31152],{"class":441}," carry\n",[431,31154,31155,31158,31160,31163,31165],{"class":433,"line":4086},[431,31156,31157],{"class":441},"        digit ",[431,31159,1189],{"class":654},[431,31161,31162],{"class":441}," digit_sum ",[431,31164,8667],{"class":654},[431,31166,31167],{"class":437}," 10\n",[431,31169,31170,31173,31175,31177,31179],{"class":433,"line":4477},[431,31171,31172],{"class":441},"        carry ",[431,31174,1189],{"class":654},[431,31176,31162],{"class":441},[431,31178,16854],{"class":654},[431,31180,31167],{"class":437},[431,31182,31183,31186,31188,31190,31192],{"class":433,"line":4482},[431,31184,31185],{"class":441},"        result.insert(",[431,31187,3302],{"class":437},[431,31189,4846],{"class":441},[431,31191,8089],{"class":437},[431,31193,31194],{"class":441},"(digit))\n",[431,31196,31197],{"class":433,"line":4488},[431,31198,31028],{"class":441},[431,31200,31201],{"class":433,"line":4505},[431,31202,31203],{"class":455},"    # Добавление остатка\n",[431,31205,31206,31208],{"class":433,"line":12871},[431,31207,10438],{"class":654},[431,31209,31210],{"class":441}," carry:\n",[431,31212,31213,31215,31217,31219,31221],{"class":433,"line":2874},[431,31214,31185],{"class":441},[431,31216,3302],{"class":437},[431,31218,4846],{"class":441},[431,31220,8089],{"class":437},[431,31222,31223],{"class":441},"(carry))\n",[431,31225,31226],{"class":433,"line":12887},[431,31227,31228],{"class":441},"  \n",[431,31230,31231,31233,31236],{"class":433,"line":12892},[431,31232,6599],{"class":654},[431,31234,31235],{"class":445}," \"\"",[431,31237,31238],{"class":441},".join(result)\n",[431,31240,31241],{"class":433,"line":12898},[431,31242,31028],{"class":441},[431,31244,31245,31248,31250],{"class":433,"line":12904},[431,31246,31247],{"class":441},"num1 ",[431,31249,1189],{"class":654},[431,31251,31252],{"class":445}," \"123456789\"\n",[431,31254,31255,31258,31260],{"class":433,"line":8382},[431,31256,31257],{"class":441},"num2 ",[431,31259,1189],{"class":654},[431,31261,31262],{"class":445}," \"987654321\"\n",[431,31264,31265,31267,31269],{"class":433,"line":25829},[431,31266,13265],{"class":437},[431,31268,2146],{"class":654},[431,31270,31271],{"class":441}," add_multidigit_numbers(num1, num2)\n",[431,31273,31274,31276,31278,31280,31282],{"class":433,"line":25838},[431,31275,438],{"class":437},[431,31277,442],{"class":441},[431,31279,13265],{"class":437},[431,31281,1014],{"class":441},[431,31283,31284],{"class":455},"# Выводит \"1111111110\"\n",[415,31286,31287],{},[1355,31288,31289],{},"В этом примере функция add_multidigit_numbers принимает две строки, представляющие два многоразрядных числа. Затем функция выполняет сложение чисел, используя столбиковый метод, и возвращает результат в виде строки.",[458,31291,31293],{"id":31292},"задача-2","Задача 2.",[415,31295,31296],{},"Пусть у нас есть два многоразрядных числа, представленных в виде списков, где каждый элемент списка представляет одну разрядную цифру числа. Например, первое число может быть представлено списком [9, 8, 7, 6, 5, 4, 3, 2, 1], а второе число — списком [1, 2, 3, 4, 5, 6, 7, 8, 9]. Необходимо реализовать функцию, которая будет складывать эти два многоразрядных числа и возвращать результат в виде нового списка.",[422,31298,31300],{"className":424,"code":31299,"language":396,"meta":426,"style":426},"def add_numbers(num1, num2):\n    # Реверсируем списки, чтобы выполнять сложение разрядов справа налево\n    num1 = num1[::-1]\n    num2 = num2[::-1]\n\n    # Создаём результирующий список с нулевыми значениями\n    result = [0] * max(len(num1), len(num2))\n\n    carry = 0  # Переменная для хранения переноса\n\n    for i in range(len(result)):\n        digit_sum = carry  # Прибавляем перенос к текущему разряду\n        if i \u003C len(num1):\n            digit_sum += num1[i]\n        if i \u003C len(num2):\n            digit_sum += num2[i]\n\n        result[i] = digit_sum % 10  # Записываем остаток от суммы в текущий разряд\n\n        carry = digit_sum \u002F\u002F 10  # Вычисляем перенос для следующего разряда\n\n    if carry > 0:\n        result.append(carry)  # Если остался неиспользованный перенос, добавляем его в конец списка\n\n    return result[::-1]  # Инвертируем список и возвращаем результат\n\n\n# Пример использования\nnum1 = [9, 8, 7, 6, 5, 4, 3, 2, 1]\nnum2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]\nresult = add_numbers(num1, num2)\nprint(result)  # Выводит [1, 1, 1, 1, 1, 1, 1, 1, 1, 0]\n",[428,31301,31302,31311,31316,31332,31348,31352,31357,31384,31388,31399,31403,31420,31432,31445,31455,31467,31476,31480,31496,31500,31515,31519,31532,31540,31544,31560,31564,31568,31573,31617,31662,31672],{"__ignoreMap":426},[431,31303,31304,31306,31309],{"class":433,"line":434},[431,31305,6330],{"class":654},[431,31307,31308],{"class":6333}," add_numbers",[431,31310,31006],{"class":441},[431,31312,31313],{"class":433,"line":452},[431,31314,31315],{"class":455},"    # Реверсируем списки, чтобы выполнять сложение разрядов справа налево\n",[431,31317,31318,31321,31323,31326,31328,31330],{"class":433,"line":578},[431,31319,31320],{"class":441},"    num1 ",[431,31322,1189],{"class":654},[431,31324,31325],{"class":441}," num1[::",[431,31327,853],{"class":654},[431,31329,1192],{"class":437},[431,31331,3568],{"class":441},[431,31333,31334,31337,31339,31342,31344,31346],{"class":433,"line":584},[431,31335,31336],{"class":441},"    num2 ",[431,31338,1189],{"class":654},[431,31340,31341],{"class":441}," num2[::",[431,31343,853],{"class":654},[431,31345,1192],{"class":437},[431,31347,3568],{"class":441},[431,31349,31350],{"class":433,"line":1244},[431,31351,1662],{"emptyLinePlaceholder":393},[431,31353,31354],{"class":433,"line":1985},[431,31355,31356],{"class":455},"    # Создаём результирующий список с нулевыми значениями\n",[431,31358,31359,31361,31363,31365,31367,31369,31371,31373,31375,31377,31380,31382],{"class":433,"line":2041},[431,31360,6796],{"class":441},[431,31362,1189],{"class":654},[431,31364,17401],{"class":441},[431,31366,3302],{"class":437},[431,31368,4049],{"class":441},[431,31370,1357],{"class":654},[431,31372,20572],{"class":437},[431,31374,442],{"class":441},[431,31376,5205],{"class":437},[431,31378,31379],{"class":441},"(num1), ",[431,31381,5205],{"class":437},[431,31383,31085],{"class":441},[431,31385,31386],{"class":433,"line":4018},[431,31387,1662],{"emptyLinePlaceholder":393},[431,31389,31390,31392,31394,31396],{"class":433,"line":4030},[431,31391,31011],{"class":441},[431,31393,1189],{"class":654},[431,31395,9744],{"class":437},[431,31397,31398],{"class":455},"  # Переменная для хранения переноса\n",[431,31400,31401],{"class":433,"line":4419},[431,31402,1662],{"emptyLinePlaceholder":393},[431,31404,31405,31407,31409,31411,31413,31415,31417],{"class":433,"line":4436},[431,31406,14745],{"class":654},[431,31408,12664],{"class":441},[431,31410,14421],{"class":654},[431,31412,14424],{"class":437},[431,31414,442],{"class":441},[431,31416,5205],{"class":437},[431,31418,31419],{"class":441},"(result)):\n",[431,31421,31422,31424,31426,31429],{"class":433,"line":4446},[431,31423,31133],{"class":441},[431,31425,1189],{"class":654},[431,31427,31428],{"class":441}," carry  ",[431,31430,31431],{"class":455},"# Прибавляем перенос к текущему разряду\n",[431,31433,31434,31436,31438,31440,31442],{"class":433,"line":4451},[431,31435,11471],{"class":654},[431,31437,12664],{"class":441},[431,31439,8521],{"class":654},[431,31441,4804],{"class":437},[431,31443,31444],{"class":441},"(num1):\n",[431,31446,31447,31450,31452],{"class":433,"line":4086},[431,31448,31449],{"class":441},"            digit_sum ",[431,31451,12563],{"class":654},[431,31453,31454],{"class":441}," num1[i]\n",[431,31456,31457,31459,31461,31463,31465],{"class":433,"line":4477},[431,31458,11471],{"class":654},[431,31460,12664],{"class":441},[431,31462,8521],{"class":654},[431,31464,4804],{"class":437},[431,31466,31049],{"class":441},[431,31468,31469,31471,31473],{"class":433,"line":4482},[431,31470,31449],{"class":441},[431,31472,12563],{"class":654},[431,31474,31475],{"class":441}," num2[i]\n",[431,31477,31478],{"class":433,"line":4488},[431,31479,1662],{"emptyLinePlaceholder":393},[431,31481,31482,31485,31487,31489,31491,31493],{"class":433,"line":4505},[431,31483,31484],{"class":441},"        result[i] ",[431,31486,1189],{"class":654},[431,31488,31162],{"class":441},[431,31490,8667],{"class":654},[431,31492,2254],{"class":437},[431,31494,31495],{"class":455},"  # Записываем остаток от суммы в текущий разряд\n",[431,31497,31498],{"class":433,"line":12871},[431,31499,1662],{"emptyLinePlaceholder":393},[431,31501,31502,31504,31506,31508,31510,31512],{"class":433,"line":2874},[431,31503,31172],{"class":441},[431,31505,1189],{"class":654},[431,31507,31162],{"class":441},[431,31509,16854],{"class":654},[431,31511,2254],{"class":437},[431,31513,31514],{"class":455},"  # Вычисляем перенос для следующего разряда\n",[431,31516,31517],{"class":433,"line":12887},[431,31518,1662],{"emptyLinePlaceholder":393},[431,31520,31521,31523,31526,31528,31530],{"class":433,"line":12892},[431,31522,10438],{"class":654},[431,31524,31525],{"class":441}," carry ",[431,31527,8883],{"class":654},[431,31529,9744],{"class":437},[431,31531,8102],{"class":441},[431,31533,31534,31537],{"class":433,"line":12898},[431,31535,31536],{"class":441},"        result.append(carry)  ",[431,31538,31539],{"class":455},"# Если остался неиспользованный перенос, добавляем его в конец списка\n",[431,31541,31542],{"class":433,"line":12904},[431,31543,1662],{"emptyLinePlaceholder":393},[431,31545,31546,31548,31551,31553,31555,31557],{"class":433,"line":8382},[431,31547,6599],{"class":654},[431,31549,31550],{"class":441}," result[::",[431,31552,853],{"class":654},[431,31554,1192],{"class":437},[431,31556,3612],{"class":441},[431,31558,31559],{"class":455},"# Инвертируем список и возвращаем результат\n",[431,31561,31562],{"class":433,"line":25829},[431,31563,1662],{"emptyLinePlaceholder":393},[431,31565,31566],{"class":433,"line":25838},[431,31567,1662],{"emptyLinePlaceholder":393},[431,31569,31570],{"class":433,"line":1890},[431,31571,31572],{"class":455},"# Пример использования\n",[431,31574,31575,31577,31579,31581,31583,31585,31587,31589,31591,31593,31595,31597,31599,31601,31603,31605,31607,31609,31611,31613,31615],{"class":433,"line":30788},[431,31576,31247],{"class":441},[431,31578,1189],{"class":654},[431,31580,17401],{"class":441},[431,31582,3357],{"class":437},[431,31584,4846],{"class":441},[431,31586,1021],{"class":437},[431,31588,4846],{"class":441},[431,31590,781],{"class":437},[431,31592,4846],{"class":441},[431,31594,742],{"class":437},[431,31596,4846],{"class":441},[431,31598,856],{"class":437},[431,31600,4846],{"class":441},[431,31602,762],{"class":437},[431,31604,4846],{"class":441},[431,31606,971],{"class":437},[431,31608,4846],{"class":441},[431,31610,651],{"class":437},[431,31612,4846],{"class":441},[431,31614,1192],{"class":437},[431,31616,3568],{"class":441},[431,31618,31620,31622,31624,31626,31628,31630,31632,31634,31636,31638,31640,31642,31644,31646,31648,31650,31652,31654,31656,31658,31660],{"class":433,"line":31619},30,[431,31621,31257],{"class":441},[431,31623,1189],{"class":654},[431,31625,17401],{"class":441},[431,31627,1192],{"class":437},[431,31629,4846],{"class":441},[431,31631,651],{"class":437},[431,31633,4846],{"class":441},[431,31635,971],{"class":437},[431,31637,4846],{"class":441},[431,31639,762],{"class":437},[431,31641,4846],{"class":441},[431,31643,856],{"class":437},[431,31645,4846],{"class":441},[431,31647,742],{"class":437},[431,31649,4846],{"class":441},[431,31651,781],{"class":437},[431,31653,4846],{"class":441},[431,31655,1021],{"class":437},[431,31657,4846],{"class":441},[431,31659,3357],{"class":437},[431,31661,3568],{"class":441},[431,31663,31665,31667,31669],{"class":433,"line":31664},31,[431,31666,4799],{"class":441},[431,31668,1189],{"class":654},[431,31670,31671],{"class":441}," add_numbers(num1, num2)\n",[431,31673,31674,31676,31678],{"class":433,"line":15016},[431,31675,438],{"class":437},[431,31677,4817],{"class":441},[431,31679,31680],{"class":455},"# Выводит [1, 1, 1, 1, 1, 1, 1, 1, 1, 0]\n",[415,31682,31683],{},[1355,31684,31685],{},"В данной реализации мы проходимся по спискам num1 и num2, складывая разряды и учитывая переносы. Результат записываем в новый список result, который затем инвертируется и возвращается как результат. В данном примере, результат сложения чисел [9, 8, 7, 6, 5, 4, 3, 2, 1] и [1, 2, 3, 4, 5, 6, 7, 8, 9] будет [1, 1, 1, 1, 1, 1, 1, 1, 1, 0].",[458,31687,31689],{"id":31688},"задача-3","Задача 3",[415,31691,31692],{},"Напиши код программы. Есть две строки, представляющие два многоразрядных числа. Затем функция выполняет вычитание чисел, используя столбиковый метод, и возвращает результат в виде строки.",[422,31694,31696],{"className":424,"code":31695,"language":396,"meta":426,"style":426},"def subtract_strings(num1, num2):\n    # Проверяем, какое число больше\n    if len(num1) \u003C len(num2):\n        num1, num2 = num2, num1\n\n    # Добавляем нули в начале строки, чтобы оба числа имели одинаковую длину\n    num2 = num2.zfill(len(num1))\n\n    # Преобразуем строки в списки цифр\n    digits1 = [int(d) for d in num1]\n    digits2 = [int(d) for d in num2]\n\n    # Выполняем вычитание\n    result = []\n    carry = 0\n    for i in range(len(digits1)-1, -1, -1):\n        diff = digits1[i] - digits2[i] - carry\n\n        if diff \u003C 0:\n            diff += 10\n            carry = 1\n        else:\n            carry = 0\n\n        result.insert(0, str(diff))\n\n    # Удаляем ведущие нули\n    while result[0] == '0' and len(result) > 1:\n        result.pop(0)\n\n    # Возвращаем результат в виде строки\n    return ''.join(result)\n\n\n# Пример использования\nnum1 = input(\"Введите первое число: \")\nnum2 = input(\"Введите второе число: \")\nresult = subtract_strings(num1, num2)\nprint(\"Результат вычитания:\", result)\n",[428,31697,31698,31707,31712,31726,31736,31740,31745,31757,31761,31766,31790,31812,31816,31821,31829,31837,31872,31891,31895,31908,31917,31926,31932,31940,31944,31957,31961,31966,31994,32003,32007,32012,32020,32025,32030,32035,32051,32067,32077],{"__ignoreMap":426},[431,31699,31700,31702,31705],{"class":433,"line":434},[431,31701,6330],{"class":654},[431,31703,31704],{"class":6333}," subtract_strings",[431,31706,31006],{"class":441},[431,31708,31709],{"class":433,"line":452},[431,31710,31711],{"class":455},"    # Проверяем, какое число больше\n",[431,31713,31714,31716,31718,31720,31722,31724],{"class":433,"line":578},[431,31715,10438],{"class":654},[431,31717,4804],{"class":437},[431,31719,31042],{"class":441},[431,31721,8521],{"class":654},[431,31723,4804],{"class":437},[431,31725,31049],{"class":441},[431,31727,31728,31731,31733],{"class":433,"line":584},[431,31729,31730],{"class":441},"        num1, num2 ",[431,31732,1189],{"class":654},[431,31734,31735],{"class":441}," num2, num1\n",[431,31737,31738],{"class":433,"line":1244},[431,31739,1662],{"emptyLinePlaceholder":393},[431,31741,31742],{"class":433,"line":1985},[431,31743,31744],{"class":455},"    # Добавляем нули в начале строки, чтобы оба числа имели одинаковую длину\n",[431,31746,31747,31749,31751,31753,31755],{"class":433,"line":2041},[431,31748,31336],{"class":441},[431,31750,1189],{"class":654},[431,31752,31059],{"class":441},[431,31754,5205],{"class":437},[431,31756,31064],{"class":441},[431,31758,31759],{"class":433,"line":4018},[431,31760,1662],{"emptyLinePlaceholder":393},[431,31762,31763],{"class":433,"line":4030},[431,31764,31765],{"class":455},"    # Преобразуем строки в списки цифр\n",[431,31767,31768,31771,31773,31775,31777,31780,31782,31785,31787],{"class":433,"line":4419},[431,31769,31770],{"class":441},"    digits1 ",[431,31772,1189],{"class":654},[431,31774,17401],{"class":441},[431,31776,2266],{"class":437},[431,31778,31779],{"class":441},"(d) ",[431,31781,14329],{"class":654},[431,31783,31784],{"class":441}," d ",[431,31786,14421],{"class":654},[431,31788,31789],{"class":441}," num1]\n",[431,31791,31792,31795,31797,31799,31801,31803,31805,31807,31809],{"class":433,"line":4436},[431,31793,31794],{"class":441},"    digits2 ",[431,31796,1189],{"class":654},[431,31798,17401],{"class":441},[431,31800,2266],{"class":437},[431,31802,31779],{"class":441},[431,31804,14329],{"class":654},[431,31806,31784],{"class":441},[431,31808,14421],{"class":654},[431,31810,31811],{"class":441}," num2]\n",[431,31813,31814],{"class":433,"line":4446},[431,31815,1662],{"emptyLinePlaceholder":393},[431,31817,31818],{"class":433,"line":4451},[431,31819,31820],{"class":455},"    # Выполняем вычитание\n",[431,31822,31823,31825,31827],{"class":433,"line":4086},[431,31824,6796],{"class":441},[431,31826,1189],{"class":654},[431,31828,21007],{"class":441},[431,31830,31831,31833,31835],{"class":433,"line":4477},[431,31832,31011],{"class":441},[431,31834,1189],{"class":654},[431,31836,3459],{"class":437},[431,31838,31839,31841,31843,31845,31847,31849,31851,31854,31856,31858,31860,31862,31864,31866,31868,31870],{"class":433,"line":4482},[431,31840,14745],{"class":654},[431,31842,12664],{"class":441},[431,31844,14421],{"class":654},[431,31846,14424],{"class":437},[431,31848,442],{"class":441},[431,31850,5205],{"class":437},[431,31852,31853],{"class":441},"(digits1)",[431,31855,853],{"class":654},[431,31857,1192],{"class":437},[431,31859,4846],{"class":441},[431,31861,853],{"class":654},[431,31863,1192],{"class":437},[431,31865,4846],{"class":441},[431,31867,853],{"class":654},[431,31869,1192],{"class":437},[431,31871,7381],{"class":441},[431,31873,31874,31877,31879,31882,31884,31887,31889],{"class":433,"line":4488},[431,31875,31876],{"class":441},"        diff ",[431,31878,1189],{"class":654},[431,31880,31881],{"class":441}," digits1[i] ",[431,31883,853],{"class":654},[431,31885,31886],{"class":441}," digits2[i] ",[431,31888,853],{"class":654},[431,31890,31152],{"class":441},[431,31892,31893],{"class":433,"line":4505},[431,31894,1662],{"emptyLinePlaceholder":393},[431,31896,31897,31899,31902,31904,31906],{"class":433,"line":12871},[431,31898,11471],{"class":654},[431,31900,31901],{"class":441}," diff ",[431,31903,8521],{"class":654},[431,31905,9744],{"class":437},[431,31907,8102],{"class":441},[431,31909,31910,31913,31915],{"class":433,"line":2874},[431,31911,31912],{"class":441},"            diff ",[431,31914,12563],{"class":654},[431,31916,31167],{"class":437},[431,31918,31919,31922,31924],{"class":433,"line":12887},[431,31920,31921],{"class":441},"            carry ",[431,31923,1189],{"class":654},[431,31925,3916],{"class":437},[431,31927,31928,31930],{"class":433,"line":12892},[431,31929,24030],{"class":654},[431,31931,8102],{"class":441},[431,31933,31934,31936,31938],{"class":433,"line":12898},[431,31935,31921],{"class":441},[431,31937,1189],{"class":654},[431,31939,3459],{"class":437},[431,31941,31942],{"class":433,"line":12904},[431,31943,1662],{"emptyLinePlaceholder":393},[431,31945,31946,31948,31950,31952,31954],{"class":433,"line":8382},[431,31947,31185],{"class":441},[431,31949,3302],{"class":437},[431,31951,4846],{"class":441},[431,31953,8089],{"class":437},[431,31955,31956],{"class":441},"(diff))\n",[431,31958,31959],{"class":433,"line":25829},[431,31960,1662],{"emptyLinePlaceholder":393},[431,31962,31963],{"class":433,"line":25838},[431,31964,31965],{"class":455},"    # Удаляем ведущие нули\n",[431,31967,31968,31970,31973,31975,31977,31979,31982,31984,31986,31988,31990,31992],{"class":433,"line":1890},[431,31969,12537],{"class":654},[431,31971,31972],{"class":441}," result[",[431,31974,3302],{"class":437},[431,31976,4049],{"class":441},[431,31978,8409],{"class":654},[431,31980,31981],{"class":445}," '0'",[431,31983,8889],{"class":654},[431,31985,4804],{"class":437},[431,31987,14809],{"class":441},[431,31989,8883],{"class":654},[431,31991,1032],{"class":437},[431,31993,8102],{"class":441},[431,31995,31996,31999,32001],{"class":433,"line":30788},[431,31997,31998],{"class":441},"        result.pop(",[431,32000,3302],{"class":437},[431,32002,449],{"class":441},[431,32004,32005],{"class":433,"line":31619},[431,32006,1662],{"emptyLinePlaceholder":393},[431,32008,32009],{"class":433,"line":31664},[431,32010,32011],{"class":455},"    # Возвращаем результат в виде строки\n",[431,32013,32014,32016,32018],{"class":433,"line":15016},[431,32015,6599],{"class":654},[431,32017,9644],{"class":445},[431,32019,31238],{"class":441},[431,32021,32023],{"class":433,"line":32022},33,[431,32024,1662],{"emptyLinePlaceholder":393},[431,32026,32028],{"class":433,"line":32027},34,[431,32029,1662],{"emptyLinePlaceholder":393},[431,32031,32033],{"class":433,"line":32032},35,[431,32034,31572],{"class":455},[431,32036,32038,32040,32042,32044,32046,32049],{"class":433,"line":32037},36,[431,32039,31247],{"class":441},[431,32041,1189],{"class":654},[431,32043,11984],{"class":437},[431,32045,442],{"class":441},[431,32047,32048],{"class":445},"\"Введите первое число: \"",[431,32050,449],{"class":441},[431,32052,32054,32056,32058,32060,32062,32065],{"class":433,"line":32053},37,[431,32055,31257],{"class":441},[431,32057,1189],{"class":654},[431,32059,11984],{"class":437},[431,32061,442],{"class":441},[431,32063,32064],{"class":445},"\"Введите второе число: \"",[431,32066,449],{"class":441},[431,32068,32070,32072,32074],{"class":433,"line":32069},38,[431,32071,4799],{"class":441},[431,32073,1189],{"class":654},[431,32075,32076],{"class":441}," subtract_strings(num1, num2)\n",[431,32078,32080,32082,32084,32087],{"class":433,"line":32079},39,[431,32081,438],{"class":437},[431,32083,442],{"class":441},[431,32085,32086],{"class":445},"\"Результат вычитания:\"",[431,32088,32089],{"class":441},", result)\n",[415,32091,32092],{},[1355,32093,32094],{},"Вы можете запустить этот код, введя два многоразрядных числа, и программа вернет результат их вычитания с использованием столбикового метода.",[415,32096,32097],{},[1355,32098,32099],{},"p.s. Можно также реализовать умножение или деление, но с делением ещё добавится тип float и нужно будет следить за остатком.",[415,32101,30931,32102,1853,32104,1857],{},[800,32103,1852],{},[800,32105,1856],{},[1859,32107],{},[1862,32109,32110],{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":32112},[32113],{"id":30957,"depth":452,"text":30958,"children":32114},[32115,32116],{"id":30971,"depth":578,"text":246},{"id":30983,"depth":578,"text":30984,"children":32117},[32118,32119,32120],{"id":30987,"depth":584,"text":30988},{"id":31292,"depth":584,"text":31293},{"id":31688,"depth":584,"text":31689},"Многоразрядные целые числа. Задачи длинной арифметики","images\u002Fblog\u002Fpython\u002Fst22\u002Fimg.png",{},{"title":246,"description":32121},"XFp6NzFe2ZM7DGLZ0riZuzzCcta_FChpRW6g7bhyTfQ",{"id":32127,"title":250,"author":32128,"body":32130,"date":33693,"description":33694,"extension":1887,"image":33695,"meta":33696,"minRead":4436,"navigation":393,"num":12898,"path":251,"seo":33697,"stem":252,"__hash__":33698},"python\u002Fblog\u002Fpython\u002Fst23.md",{"name":402,"avatar":32129},{"src":404,"alt":405},{"type":407,"value":32131,"toc":33685},[32132,32136,32139,32142,32146,32149,32245,32269,32272,32308,32315,32318,32487,32490,32497,32500,32504,32507,32510,32563,32566,32658,32668,32674,32730,32740,32905,32914,32924,33013,33016,33074,33077,33081,33084,33087,33168,33171,33252,33255,33405,33412,33667,33671,33674,33680,33682],[410,32133,32135],{"id":32134},"декораторы","Декораторы",[415,32137,32138],{},"В программировании часто возникают задачи, когда нужно добавить поведение к уже существующим функциям или классам. Например, логирование, проверку входных данных или замер времени выполнения функции. В таких случаях использование декораторов может значительно упростить решение задачи.",[415,32140,32141],{},"В этом уроке мы рассмотрим, что такое декораторы и как их использовать, чтобы добавлять дополнительную функциональность к существующим функциям.",[632,32143,32145],{"id":32144},"что-такое-декораторы","Что такое декораторы",[415,32147,32148],{},"Ранее мы рассматривали как можно \"запомнить\" передаваемые значения в функцию с помощью замыканий. Напомним как выглядит синтаксис:",[422,32150,32152],{"className":424,"code":32151,"language":396,"meta":426,"style":426},"def outer(arg1):\n    def inner(arg2):\n        return arg1 + arg2\n    return inner\n\ntwo_add = outer(2)\ntwo_add(1) # 3\ntwo_add(3) # 5\ntwo_add(5) # 7\n",[428,32153,32154,32164,32175,32187,32194,32198,32212,32223,32234],{"__ignoreMap":426},[431,32155,32156,32158,32161],{"class":433,"line":434},[431,32157,6330],{"class":654},[431,32159,32160],{"class":6333}," outer",[431,32162,32163],{"class":441},"(arg1):\n",[431,32165,32166,32169,32172],{"class":433,"line":452},[431,32167,32168],{"class":654},"    def",[431,32170,32171],{"class":6333}," inner",[431,32173,32174],{"class":441},"(arg2):\n",[431,32176,32177,32179,32182,32184],{"class":433,"line":578},[431,32178,10453],{"class":654},[431,32180,32181],{"class":441}," arg1 ",[431,32183,802],{"class":654},[431,32185,32186],{"class":441}," arg2\n",[431,32188,32189,32191],{"class":433,"line":584},[431,32190,6599],{"class":654},[431,32192,32193],{"class":441}," inner\n",[431,32195,32196],{"class":433,"line":1244},[431,32197,1662],{"emptyLinePlaceholder":393},[431,32199,32200,32203,32205,32208,32210],{"class":433,"line":1985},[431,32201,32202],{"class":441},"two_add ",[431,32204,1189],{"class":654},[431,32206,32207],{"class":441}," outer(",[431,32209,651],{"class":437},[431,32211,449],{"class":441},[431,32213,32214,32217,32219,32221],{"class":433,"line":2041},[431,32215,32216],{"class":441},"two_add(",[431,32218,1192],{"class":437},[431,32220,1014],{"class":441},[431,32222,5340],{"class":455},[431,32224,32225,32227,32229,32231],{"class":433,"line":4018},[431,32226,32216],{"class":441},[431,32228,971],{"class":437},[431,32230,1014],{"class":441},[431,32232,32233],{"class":455},"# 5\n",[431,32235,32236,32238,32240,32242],{"class":433,"line":4030},[431,32237,32216],{"class":441},[431,32239,856],{"class":437},[431,32241,1014],{"class":441},[431,32243,32244],{"class":455},"# 7\n",[415,32246,32247,32248,32251,32252,32255,32256,32259,32260,32263,32264,3228,32266,2699],{},"В этом примере мы создаем функцию ",[800,32249,32250],{},"outer()",", которая принимает аргумент ",[800,32253,32254],{},"arg1"," и возвращает внутреннюю функцию ",[800,32257,32258],{},"inner()",". Внутренняя функция принимает аргумент ",[800,32261,32262],{},"arg2"," и возвращает сумму ",[800,32265,32254],{},[800,32267,32268],{},"agr2",[415,32270,32271],{},"Может запутать одновременное определение функции и возврат ее же. Но если мы вспомним, что определение функции это присваивание функции имени переменной, а также, что функции это данные, то пример можно представить как:",[422,32273,32275],{"className":424,"code":32274,"language":396,"meta":426,"style":426},"def outer(arg1):\n    inner = lambda arg2: arg1 + arg2\n    return inner\n",[428,32276,32277,32285,32302],{"__ignoreMap":426},[431,32278,32279,32281,32283],{"class":433,"line":434},[431,32280,6330],{"class":654},[431,32282,32160],{"class":6333},[431,32284,32163],{"class":441},[431,32286,32287,32290,32292,32295,32298,32300],{"class":433,"line":452},[431,32288,32289],{"class":441},"    inner ",[431,32291,1189],{"class":654},[431,32293,32294],{"class":654}," lambda",[431,32296,32297],{"class":441}," arg2: arg1 ",[431,32299,802],{"class":654},[431,32301,32186],{"class":441},[431,32303,32304,32306],{"class":433,"line":578},[431,32305,6599],{"class":654},[431,32307,32193],{"class":441},[415,32309,32310,32311,32314],{},"Мы заменили именованную функцию лямбдой, и теперь присваивание ничем не отличается, как если бы мы присвоили переменной ",[800,32312,32313],{},"inner"," число или строку.",[415,32316,32317],{},"Но если функции всего лишь данные, то можно ли их также \"запоминать\" в замыканиях?",[422,32319,32321],{"className":424,"code":32320,"language":396,"meta":426,"style":426},"def outer(func):\n    def inner(arg):\n        print('func = ', func)\n        print('arg = ', arg)\n        return func(arg)\n    return inner\n\ndef square(x):\n    return x ** 2\n\nprinter = outer(square)\n\nprinter(1) # 1\n# => func =  \u003Cfunction square at 0x75e04623a7a0>\n# => arg =  1\n\nprinter(2) # 4\n# => func =  \u003Cfunction square at 0x75e04623a7a0>\n# => arg =  2\n\nprinter(4) # 16\n# => func =  \u003Cfunction square at 0x75e04623a7a0>\n# => arg =  4\n",[428,32322,32323,32332,32341,32353,32365,32372,32378,32382,32391,32401,32405,32415,32419,32430,32435,32440,32444,32454,32458,32463,32467,32478,32482],{"__ignoreMap":426},[431,32324,32325,32327,32329],{"class":433,"line":434},[431,32326,6330],{"class":654},[431,32328,32160],{"class":6333},[431,32330,32331],{"class":441},"(func):\n",[431,32333,32334,32336,32338],{"class":433,"line":452},[431,32335,32168],{"class":654},[431,32337,32171],{"class":6333},[431,32339,32340],{"class":441},"(arg):\n",[431,32342,32343,32345,32347,32350],{"class":433,"line":578},[431,32344,11353],{"class":437},[431,32346,442],{"class":441},[431,32348,32349],{"class":445},"'func = '",[431,32351,32352],{"class":441},", func)\n",[431,32354,32355,32357,32359,32362],{"class":433,"line":584},[431,32356,11353],{"class":437},[431,32358,442],{"class":441},[431,32360,32361],{"class":445},"'arg = '",[431,32363,32364],{"class":441},", arg)\n",[431,32366,32367,32369],{"class":433,"line":1244},[431,32368,10453],{"class":654},[431,32370,32371],{"class":441}," func(arg)\n",[431,32373,32374,32376],{"class":433,"line":1985},[431,32375,6599],{"class":654},[431,32377,32193],{"class":441},[431,32379,32380],{"class":433,"line":2041},[431,32381,1662],{"emptyLinePlaceholder":393},[431,32383,32384,32386,32389],{"class":433,"line":4018},[431,32385,6330],{"class":654},[431,32387,32388],{"class":6333}," square",[431,32390,15768],{"class":441},[431,32392,32393,32395,32397,32399],{"class":433,"line":4030},[431,32394,6599],{"class":654},[431,32396,7388],{"class":441},[431,32398,7391],{"class":654},[431,32400,658],{"class":437},[431,32402,32403],{"class":433,"line":4419},[431,32404,1662],{"emptyLinePlaceholder":393},[431,32406,32407,32410,32412],{"class":433,"line":4436},[431,32408,32409],{"class":441},"printer ",[431,32411,1189],{"class":654},[431,32413,32414],{"class":441}," outer(square)\n",[431,32416,32417],{"class":433,"line":4446},[431,32418,1662],{"emptyLinePlaceholder":393},[431,32420,32421,32424,32426,32428],{"class":433,"line":4451},[431,32422,32423],{"class":441},"printer(",[431,32425,1192],{"class":437},[431,32427,1014],{"class":441},[431,32429,13119],{"class":455},[431,32431,32432],{"class":433,"line":4086},[431,32433,32434],{"class":455},"# => func =  \u003Cfunction square at 0x75e04623a7a0>\n",[431,32436,32437],{"class":433,"line":4477},[431,32438,32439],{"class":455},"# => arg =  1\n",[431,32441,32442],{"class":433,"line":4482},[431,32443,1662],{"emptyLinePlaceholder":393},[431,32445,32446,32448,32450,32452],{"class":433,"line":4488},[431,32447,32423],{"class":441},[431,32449,651],{"class":437},[431,32451,1014],{"class":441},[431,32453,7774],{"class":455},[431,32455,32456],{"class":433,"line":4505},[431,32457,32434],{"class":455},[431,32459,32460],{"class":433,"line":12871},[431,32461,32462],{"class":455},"# => arg =  2\n",[431,32464,32465],{"class":433,"line":2874},[431,32466,1662],{"emptyLinePlaceholder":393},[431,32468,32469,32471,32473,32475],{"class":433,"line":12887},[431,32470,32423],{"class":441},[431,32472,762],{"class":437},[431,32474,1014],{"class":441},[431,32476,32477],{"class":455},"# 16\n",[431,32479,32480],{"class":433,"line":12892},[431,32481,32434],{"class":455},[431,32483,32484],{"class":433,"line":12898},[431,32485,32486],{"class":455},"# => arg =  4\n",[415,32488,32489],{},"Остановимся и разберем пример выше. В нем мы создаем замыкание, но теперь, вместо числа в замыкание передается функция. Внутренняя функция запомнила переданную в нее и может использовать внутри. Осталось лишь передать аргументы и вызвать замкнутую функцию с ними. В дополнение, мы смогли распечатать переданную функцию и ее аргументы, при этом код самой функции square() мы не меняли.",[415,32491,32492,32493,32496],{},"Функции выше называются декораторами. ",[1355,32494,32495],{},"Декораторы в Python"," — это функции, которые принимают другую функцию в качестве аргумента, добавляют к ней дополнительную функциональность и возвращают функцию с измененным поведением. Декораторы позволяют изменять поведение функций и классов с помощью добавления или изменения их функциональности без изменения самого кода.",[415,32498,32499],{},"Также, как вы могли заметить, декораторы это частный случай функции высшего порядка (принимаем функцию) и использования замыкания вместе.",[632,32501,32503],{"id":32502},"использование-декораторов","Использование декораторов",[415,32505,32506],{},"Декораторы используются в Python повсеместно: для логирования, кеширования, добавления нового функционала, используются в тестовых и веб-фреймворках.",[415,32508,32509],{},"Предположим, что у нас есть функция, которая суммирует числа:",[422,32511,32513],{"className":424,"code":32512,"language":396,"meta":426,"style":426},"def sum(*nums):\n    result = 0\n    for num in nums:\n        result += num\n    return result\n",[428,32514,32515,32528,32536,32548,32557],{"__ignoreMap":426},[431,32516,32517,32519,32521,32523,32525],{"class":433,"line":434},[431,32518,6330],{"class":654},[431,32520,13212],{"class":437},[431,32522,442],{"class":441},[431,32524,1357],{"class":654},[431,32526,32527],{"class":441},"nums):\n",[431,32529,32530,32532,32534],{"class":433,"line":452},[431,32531,6796],{"class":441},[431,32533,1189],{"class":654},[431,32535,3459],{"class":437},[431,32537,32538,32540,32543,32545],{"class":433,"line":578},[431,32539,14745],{"class":654},[431,32541,32542],{"class":441}," num ",[431,32544,14421],{"class":654},[431,32546,32547],{"class":441}," nums:\n",[431,32549,32550,32552,32554],{"class":433,"line":584},[431,32551,13429],{"class":441},[431,32553,12563],{"class":654},[431,32555,32556],{"class":441}," num\n",[431,32558,32559,32561],{"class":433,"line":1244},[431,32560,6599],{"class":654},[431,32562,6812],{"class":441},[415,32564,32565],{},"Создадим декоратор, который добавит к этой функции функциональность для отладки:",[422,32567,32569],{"className":424,"code":32568,"language":396,"meta":426,"style":426},"def debug_decorator(func):\n    # внутреннюю функцию принято называть wrapper - обертка\n    def wrapper(*args, **kwargs):\n        print(\"Args:\", args, kwargs)\n        result = func(*args, **kwargs)\n        print(\"Result:\", result)\n        return result\n    return wrapper\n",[428,32570,32571,32580,32585,32604,32616,32634,32645,32651],{"__ignoreMap":426},[431,32572,32573,32575,32578],{"class":433,"line":434},[431,32574,6330],{"class":654},[431,32576,32577],{"class":6333}," debug_decorator",[431,32579,32331],{"class":441},[431,32581,32582],{"class":433,"line":452},[431,32583,32584],{"class":455},"    # внутреннюю функцию принято называть wrapper - обертка\n",[431,32586,32587,32589,32592,32594,32596,32599,32601],{"class":433,"line":578},[431,32588,32168],{"class":654},[431,32590,32591],{"class":6333}," wrapper",[431,32593,442],{"class":441},[431,32595,1357],{"class":654},[431,32597,32598],{"class":441},"args, ",[431,32600,7391],{"class":654},[431,32602,32603],{"class":441},"kwargs):\n",[431,32605,32606,32608,32610,32613],{"class":433,"line":584},[431,32607,11353],{"class":437},[431,32609,442],{"class":441},[431,32611,32612],{"class":445},"\"Args:\"",[431,32614,32615],{"class":441},", args, kwargs)\n",[431,32617,32618,32620,32622,32625,32627,32629,32631],{"class":433,"line":1244},[431,32619,13429],{"class":441},[431,32621,1189],{"class":654},[431,32623,32624],{"class":441}," func(",[431,32626,1357],{"class":654},[431,32628,32598],{"class":441},[431,32630,7391],{"class":654},[431,32632,32633],{"class":441},"kwargs)\n",[431,32635,32636,32638,32640,32643],{"class":433,"line":1985},[431,32637,11353],{"class":437},[431,32639,442],{"class":441},[431,32641,32642],{"class":445},"\"Result:\"",[431,32644,32089],{"class":441},[431,32646,32647,32649],{"class":433,"line":2041},[431,32648,10453],{"class":654},[431,32650,6812],{"class":441},[431,32652,32653,32655],{"class":433,"line":4018},[431,32654,6599],{"class":654},[431,32656,32657],{"class":441}," wrapper\n",[415,32659,32660,32661,3228,32664,32667],{},"Этот декоратор принимает функцию в качестве аргумента и возвращает новую функцию-обертку, которая добавляет отладочные сообщения в процесс выполнения исходной функции. Заметьте, что внутренняя функция принимает сразу все аргументы с помощью ",[800,32662,32663],{},"*args",[800,32665,32666],{},"**kwargs",". Так мы можем создавать \"всеядные\" обертки.",[415,32669,32670,32671,3562],{},"Применим этот декоратор к функции ",[800,32672,32673],{},"sum()",[422,32675,32677],{"className":424,"code":32676,"language":396,"meta":426,"style":426},"debugged_sum = debug_decorator(sum)\n\ndebugged_sum(1, 2, 3) # 6\n\n# => Args: (1, 2, 3) {}\n# => Result: 6\n",[428,32678,32679,32693,32697,32716,32720,32725],{"__ignoreMap":426},[431,32680,32681,32684,32686,32689,32691],{"class":433,"line":434},[431,32682,32683],{"class":441},"debugged_sum ",[431,32685,1189],{"class":654},[431,32687,32688],{"class":441}," debug_decorator(",[431,32690,13265],{"class":437},[431,32692,449],{"class":441},[431,32694,32695],{"class":433,"line":452},[431,32696,1662],{"emptyLinePlaceholder":393},[431,32698,32699,32702,32704,32706,32708,32710,32712,32714],{"class":433,"line":578},[431,32700,32701],{"class":441},"debugged_sum(",[431,32703,1192],{"class":437},[431,32705,4846],{"class":441},[431,32707,651],{"class":437},[431,32709,4846],{"class":441},[431,32711,971],{"class":437},[431,32713,1014],{"class":441},[431,32715,5314],{"class":455},[431,32717,32718],{"class":433,"line":584},[431,32719,1662],{"emptyLinePlaceholder":393},[431,32721,32722],{"class":433,"line":1244},[431,32723,32724],{"class":455},"# => Args: (1, 2, 3) {}\n",[431,32726,32727],{"class":433,"line":1985},[431,32728,32729],{"class":455},"# => Result: 6\n",[415,32731,32732,32733,32736,32737,32739],{},"Проблема в коде выше, что теперь функция называется ",[800,32734,32735],{},"debugged_sum()",", и нужно будет изменить весь код, что использовал ",[800,32738,32673],{},". Но ведь имя функции это всего лишь имя переменной, и мы можем перезаписать новую, декорированную функцию в ту же переменную.",[422,32741,32743],{"className":424,"code":32742,"language":396,"meta":426,"style":426},"sum = debug_decorator(sum)\n\nsum(1, 2, 3) # 6\n# => Args: (1, 2, 3) {}\n# => Result: 6\n\ndef sum_odd_numbers(nums):\n    odd = []\n    for num in nums:\n        if num % 2 != 0:\n            odd.append(num)\n    return sum(*odd)\n\nnumbers = [1, 2, 3, 4, 5]\nsum_odd_numbers(numbers) # 9\n# => Args: (1, 3, 5) {}\n# => Result: 9\n",[428,32744,32745,32757,32761,32781,32785,32789,32793,32803,32812,32822,32838,32843,32856,32860,32888,32895,32900],{"__ignoreMap":426},[431,32746,32747,32749,32751,32753,32755],{"class":433,"line":434},[431,32748,13265],{"class":437},[431,32750,2146],{"class":654},[431,32752,32688],{"class":441},[431,32754,13265],{"class":437},[431,32756,449],{"class":441},[431,32758,32759],{"class":433,"line":452},[431,32760,1662],{"emptyLinePlaceholder":393},[431,32762,32763,32765,32767,32769,32771,32773,32775,32777,32779],{"class":433,"line":578},[431,32764,13265],{"class":437},[431,32766,442],{"class":441},[431,32768,1192],{"class":437},[431,32770,4846],{"class":441},[431,32772,651],{"class":437},[431,32774,4846],{"class":441},[431,32776,971],{"class":437},[431,32778,1014],{"class":441},[431,32780,5314],{"class":455},[431,32782,32783],{"class":433,"line":584},[431,32784,32724],{"class":455},[431,32786,32787],{"class":433,"line":1244},[431,32788,32729],{"class":455},[431,32790,32791],{"class":433,"line":1985},[431,32792,1662],{"emptyLinePlaceholder":393},[431,32794,32795,32797,32800],{"class":433,"line":2041},[431,32796,6330],{"class":654},[431,32798,32799],{"class":6333}," sum_odd_numbers",[431,32801,32802],{"class":441},"(nums):\n",[431,32804,32805,32808,32810],{"class":433,"line":4018},[431,32806,32807],{"class":441},"    odd ",[431,32809,1189],{"class":654},[431,32811,21007],{"class":441},[431,32813,32814,32816,32818,32820],{"class":433,"line":4030},[431,32815,14745],{"class":654},[431,32817,32542],{"class":441},[431,32819,14421],{"class":654},[431,32821,32547],{"class":441},[431,32823,32824,32826,32828,32830,32832,32834,32836],{"class":433,"line":4419},[431,32825,11471],{"class":654},[431,32827,32542],{"class":441},[431,32829,8667],{"class":654},[431,32831,689],{"class":437},[431,32833,8482],{"class":654},[431,32835,9744],{"class":437},[431,32837,8102],{"class":441},[431,32839,32840],{"class":433,"line":4436},[431,32841,32842],{"class":441},"            odd.append(num)\n",[431,32844,32845,32847,32849,32851,32853],{"class":433,"line":4446},[431,32846,6599],{"class":654},[431,32848,13212],{"class":437},[431,32850,442],{"class":441},[431,32852,1357],{"class":654},[431,32854,32855],{"class":441},"odd)\n",[431,32857,32858],{"class":433,"line":4451},[431,32859,1662],{"emptyLinePlaceholder":393},[431,32861,32862,32864,32866,32868,32870,32872,32874,32876,32878,32880,32882,32884,32886],{"class":433,"line":4086},[431,32863,19577],{"class":441},[431,32865,1189],{"class":654},[431,32867,17401],{"class":441},[431,32869,1192],{"class":437},[431,32871,4846],{"class":441},[431,32873,651],{"class":437},[431,32875,4846],{"class":441},[431,32877,971],{"class":437},[431,32879,4846],{"class":441},[431,32881,762],{"class":437},[431,32883,4846],{"class":441},[431,32885,856],{"class":437},[431,32887,3568],{"class":441},[431,32889,32890,32893],{"class":433,"line":4477},[431,32891,32892],{"class":441},"sum_odd_numbers(numbers) ",[431,32894,4982],{"class":455},[431,32896,32897],{"class":433,"line":4482},[431,32898,32899],{"class":455},"# => Args: (1, 3, 5) {}\n",[431,32901,32902],{"class":433,"line":4488},[431,32903,32904],{"class":455},"# => Result: 9\n",[415,32906,32907,32908,32910,32911,32913],{},"Теперь функция ",[800,32909,32673],{}," будет выполняться с дополнительными отладочными сообщениями. А также весь код, использующий функцию ",[800,32912,32673],{}," будет использовать новую функцию.",[415,32915,32916,32917,32920,32921],{},"Чтобы не добавлять запись вида ",[800,32918,32919],{},"func = decorator(func)"," каждый раз, в Python добавили синтаксический сахар - ",[800,32922,32923],{},"@decorator",[422,32925,32927],{"className":424,"code":32926,"language":396,"meta":426,"style":426},"# декоратор нужно добавить над определением функции, которую хотим декорировать\n@debug_decorator\ndef sum(*nums):\n    result = 0\n    for num in nums:\n        result += num\n    return result\n\nsum(1, 2) # 3\n# => Args: (1, 2) {}\n# => Result: 3\n",[428,32928,32929,32934,32939,32951,32959,32969,32977,32983,32987,33003,33008],{"__ignoreMap":426},[431,32930,32931],{"class":433,"line":434},[431,32932,32933],{"class":455},"# декоратор нужно добавить над определением функции, которую хотим декорировать\n",[431,32935,32936],{"class":433,"line":452},[431,32937,32938],{"class":6333},"@debug_decorator\n",[431,32940,32941,32943,32945,32947,32949],{"class":433,"line":578},[431,32942,6330],{"class":654},[431,32944,13212],{"class":437},[431,32946,442],{"class":441},[431,32948,1357],{"class":654},[431,32950,32527],{"class":441},[431,32952,32953,32955,32957],{"class":433,"line":584},[431,32954,6796],{"class":441},[431,32956,1189],{"class":654},[431,32958,3459],{"class":437},[431,32960,32961,32963,32965,32967],{"class":433,"line":1244},[431,32962,14745],{"class":654},[431,32964,32542],{"class":441},[431,32966,14421],{"class":654},[431,32968,32547],{"class":441},[431,32970,32971,32973,32975],{"class":433,"line":1985},[431,32972,13429],{"class":441},[431,32974,12563],{"class":654},[431,32976,32556],{"class":441},[431,32978,32979,32981],{"class":433,"line":2041},[431,32980,6599],{"class":654},[431,32982,6812],{"class":441},[431,32984,32985],{"class":433,"line":4018},[431,32986,1662],{"emptyLinePlaceholder":393},[431,32988,32989,32991,32993,32995,32997,32999,33001],{"class":433,"line":4030},[431,32990,13265],{"class":437},[431,32992,442],{"class":441},[431,32994,1192],{"class":437},[431,32996,4846],{"class":441},[431,32998,651],{"class":437},[431,33000,1014],{"class":441},[431,33002,5340],{"class":455},[431,33004,33005],{"class":433,"line":4419},[431,33006,33007],{"class":455},"# => Args: (1, 2) {}\n",[431,33009,33010],{"class":433,"line":4436},[431,33011,33012],{"class":455},"# => Result: 3\n",[415,33014,33015],{},"Также мы можем создавать несколько декораторов для одной функции, которые будут применяться последовательно:",[422,33017,33019],{"className":424,"code":33018,"language":396,"meta":426,"style":426},"@debug_decorator\n@time_decorator\ndef sum(*nums):\n    result = 0\n    for num in nums:\n        result += num\n    return result\n",[428,33020,33021,33025,33030,33042,33050,33060,33068],{"__ignoreMap":426},[431,33022,33023],{"class":433,"line":434},[431,33024,32938],{"class":6333},[431,33026,33027],{"class":433,"line":452},[431,33028,33029],{"class":6333},"@time_decorator\n",[431,33031,33032,33034,33036,33038,33040],{"class":433,"line":578},[431,33033,6330],{"class":654},[431,33035,13212],{"class":437},[431,33037,442],{"class":441},[431,33039,1357],{"class":654},[431,33041,32527],{"class":441},[431,33043,33044,33046,33048],{"class":433,"line":584},[431,33045,6796],{"class":441},[431,33047,1189],{"class":654},[431,33049,3459],{"class":437},[431,33051,33052,33054,33056,33058],{"class":433,"line":1244},[431,33053,14745],{"class":654},[431,33055,32542],{"class":441},[431,33057,14421],{"class":654},[431,33059,32547],{"class":441},[431,33061,33062,33064,33066],{"class":433,"line":1985},[431,33063,13429],{"class":441},[431,33065,12563],{"class":654},[431,33067,32556],{"class":441},[431,33069,33070,33072],{"class":433,"line":2041},[431,33071,6599],{"class":654},[431,33073,6812],{"class":441},[415,33075,33076],{},"В этом примере сначала применится декоратор времени выполнения, а затем отладочный декоратор.",[632,33078,33080],{"id":33079},"декораторы-с-параметрами","Декораторы с параметрами",[415,33082,33083],{},"Что если мы хотели бы вызывать обернутую функцию с разными настройками? Для этого нам понадобятся декораторы с параметрами.",[415,33085,33086],{},"Общий синтаксис декоратора с параметрами выглядит так:",[422,33088,33090],{"className":424,"code":33089,"language":396,"meta":426,"style":426},"def decorator_with_params(param1, param2, ...):\n    def actual_decorator(func):\n        def wrapper(*args, **kwargs):\n            # Здесь можем использовать param1, param2, ...\n            result = func(*args, **kwargs)\n            return result\n        return wrapper\n    return actual_decorator\n",[428,33091,33092,33102,33111,33128,33133,33149,33155,33161],{"__ignoreMap":426},[431,33093,33094,33096,33099],{"class":433,"line":434},[431,33095,6330],{"class":654},[431,33097,33098],{"class":6333}," decorator_with_params",[431,33100,33101],{"class":441},"(param1, param2, ...):\n",[431,33103,33104,33106,33109],{"class":433,"line":452},[431,33105,32168],{"class":654},[431,33107,33108],{"class":6333}," actual_decorator",[431,33110,32331],{"class":441},[431,33112,33113,33116,33118,33120,33122,33124,33126],{"class":433,"line":578},[431,33114,33115],{"class":654},"        def",[431,33117,32591],{"class":6333},[431,33119,442],{"class":441},[431,33121,1357],{"class":654},[431,33123,32598],{"class":441},[431,33125,7391],{"class":654},[431,33127,32603],{"class":441},[431,33129,33130],{"class":433,"line":584},[431,33131,33132],{"class":455},"            # Здесь можем использовать param1, param2, ...\n",[431,33134,33135,33137,33139,33141,33143,33145,33147],{"class":433,"line":1244},[431,33136,11835],{"class":441},[431,33138,1189],{"class":654},[431,33140,32624],{"class":441},[431,33142,1357],{"class":654},[431,33144,32598],{"class":441},[431,33146,7391],{"class":654},[431,33148,32633],{"class":441},[431,33150,33151,33153],{"class":433,"line":1985},[431,33152,11924],{"class":654},[431,33154,6812],{"class":441},[431,33156,33157,33159],{"class":433,"line":2041},[431,33158,10453],{"class":654},[431,33160,32657],{"class":441},[431,33162,33163,33165],{"class":433,"line":4018},[431,33164,6599],{"class":654},[431,33166,33167],{"class":441}," actual_decorator\n",[415,33169,33170],{},"К обычному декоратору мы добавляем еще один слой с параметрами. И, конечно, в качестве параметров мы можем передавать другие функции:",[422,33172,33174],{"className":424,"code":33173,"language":396,"meta":426,"style":426},"def filter_by(key):\n    def inner(func):\n        def wrapper(*args):\n            args = key(args)\n            print('filtered args = ', args)\n            return func(*args)\n        return wrapper\n    return inner\n",[428,33175,33176,33186,33194,33207,33217,33229,33240,33246],{"__ignoreMap":426},[431,33177,33178,33180,33183],{"class":433,"line":434},[431,33179,6330],{"class":654},[431,33181,33182],{"class":6333}," filter_by",[431,33184,33185],{"class":441},"(key):\n",[431,33187,33188,33190,33192],{"class":433,"line":452},[431,33189,32168],{"class":654},[431,33191,32171],{"class":6333},[431,33193,32331],{"class":441},[431,33195,33196,33198,33200,33202,33204],{"class":433,"line":578},[431,33197,33115],{"class":654},[431,33199,32591],{"class":6333},[431,33201,442],{"class":441},[431,33203,1357],{"class":654},[431,33205,33206],{"class":441},"args):\n",[431,33208,33209,33212,33214],{"class":433,"line":584},[431,33210,33211],{"class":441},"            args ",[431,33213,1189],{"class":654},[431,33215,33216],{"class":441}," key(args)\n",[431,33218,33219,33221,33223,33226],{"class":433,"line":1244},[431,33220,11484],{"class":437},[431,33222,442],{"class":441},[431,33224,33225],{"class":445},"'filtered args = '",[431,33227,33228],{"class":441},", args)\n",[431,33230,33231,33233,33235,33237],{"class":433,"line":1985},[431,33232,11924],{"class":654},[431,33234,32624],{"class":441},[431,33236,1357],{"class":654},[431,33238,33239],{"class":441},"args)\n",[431,33241,33242,33244],{"class":433,"line":2041},[431,33243,10453],{"class":654},[431,33245,32657],{"class":441},[431,33247,33248,33250],{"class":433,"line":4018},[431,33249,6599],{"class":654},[431,33251,32193],{"class":441},[415,33253,33254],{},"И даже функции с собственными параметрами, используя замыкания:",[422,33256,33258],{"className":424,"code":33257,"language":396,"meta":426,"style":426},"def odd(numbers):\n    result = []\n    for num in numbers:\n        if num % 2 == 1:\n            result.append(num)\n    return result\n\n@filter_by(odd)\ndef sum(*nums):\n    result = 0\n    for num in nums:\n        result += num\n    return result\n\nsum(3, 4, 5, 6) # 8\n# => filtered args =  [3, 5]\n",[428,33259,33260,33269,33277,33288,33304,33309,33315,33319,33327,33339,33347,33357,33365,33371,33375,33400],{"__ignoreMap":426},[431,33261,33262,33264,33267],{"class":433,"line":434},[431,33263,6330],{"class":654},[431,33265,33266],{"class":6333}," odd",[431,33268,19626],{"class":441},[431,33270,33271,33273,33275],{"class":433,"line":452},[431,33272,6796],{"class":441},[431,33274,1189],{"class":654},[431,33276,21007],{"class":441},[431,33278,33279,33281,33283,33285],{"class":433,"line":578},[431,33280,14745],{"class":654},[431,33282,32542],{"class":441},[431,33284,14421],{"class":654},[431,33286,33287],{"class":441}," numbers:\n",[431,33289,33290,33292,33294,33296,33298,33300,33302],{"class":433,"line":584},[431,33291,11471],{"class":654},[431,33293,32542],{"class":441},[431,33295,8667],{"class":654},[431,33297,689],{"class":437},[431,33299,8711],{"class":654},[431,33301,1032],{"class":437},[431,33303,8102],{"class":441},[431,33305,33306],{"class":433,"line":1244},[431,33307,33308],{"class":441},"            result.append(num)\n",[431,33310,33311,33313],{"class":433,"line":1985},[431,33312,6599],{"class":654},[431,33314,6812],{"class":441},[431,33316,33317],{"class":433,"line":2041},[431,33318,1662],{"emptyLinePlaceholder":393},[431,33320,33321,33324],{"class":433,"line":4018},[431,33322,33323],{"class":6333},"@filter_by",[431,33325,33326],{"class":441},"(odd)\n",[431,33328,33329,33331,33333,33335,33337],{"class":433,"line":4030},[431,33330,6330],{"class":654},[431,33332,13212],{"class":437},[431,33334,442],{"class":441},[431,33336,1357],{"class":654},[431,33338,32527],{"class":441},[431,33340,33341,33343,33345],{"class":433,"line":4419},[431,33342,6796],{"class":441},[431,33344,1189],{"class":654},[431,33346,3459],{"class":437},[431,33348,33349,33351,33353,33355],{"class":433,"line":4436},[431,33350,14745],{"class":654},[431,33352,32542],{"class":441},[431,33354,14421],{"class":654},[431,33356,32547],{"class":441},[431,33358,33359,33361,33363],{"class":433,"line":4446},[431,33360,13429],{"class":441},[431,33362,12563],{"class":654},[431,33364,32556],{"class":441},[431,33366,33367,33369],{"class":433,"line":4451},[431,33368,6599],{"class":654},[431,33370,6812],{"class":441},[431,33372,33373],{"class":433,"line":4086},[431,33374,1662],{"emptyLinePlaceholder":393},[431,33376,33377,33379,33381,33383,33385,33387,33389,33391,33393,33395,33397],{"class":433,"line":4477},[431,33378,13265],{"class":437},[431,33380,442],{"class":441},[431,33382,971],{"class":437},[431,33384,4846],{"class":441},[431,33386,762],{"class":437},[431,33388,4846],{"class":441},[431,33390,856],{"class":437},[431,33392,4846],{"class":441},[431,33394,742],{"class":437},[431,33396,1014],{"class":441},[431,33398,33399],{"class":455},"# 8\n",[431,33401,33402],{"class":433,"line":4482},[431,33403,33404],{"class":455},"# => filtered args =  [3, 5]\n",[415,33406,33407,33408,33411],{},"Декоратор ",[800,33409,33410],{},"filter_by()"," принимает функцию фильтрации key(), затем применяет ее к аргументам обернутой функции, и вызывает обернутую функцию с новыми аргументами.",[422,33413,33415],{"className":424,"code":33414,"language":396,"meta":426,"style":426},"def less_than(max):\n    def inner(numbers):\n        result = []\n        for num in numbers:\n            if num \u003C max:\n                result.append(num)\n        return result\n    return inner\n\n@filter_by(less_than(5))\ndef sum(*nums):\n    result = 0\n    for num in nums:\n        result += num\n    return result\n\nsum(3, 4, 5, 6) # 7\n# => filtered args =  [3, 4]\n\n@filter_by(less_than(3))\ndef sum(*nums):\n    result = 0\n    for num in nums:\n        result += num\n    return result\n\nsum(3, 4, 5, 6) # 0\n# => filtered args =  []\n",[428,33416,33417,33427,33435,33443,33454,33467,33472,33478,33484,33488,33499,33511,33519,33529,33537,33543,33547,33571,33576,33580,33590,33602,33610,33620,33628,33634,33638,33662],{"__ignoreMap":426},[431,33418,33419,33421,33424],{"class":433,"line":434},[431,33420,6330],{"class":654},[431,33422,33423],{"class":6333}," less_than",[431,33425,33426],{"class":441},"(max):\n",[431,33428,33429,33431,33433],{"class":433,"line":452},[431,33430,32168],{"class":654},[431,33432,32171],{"class":6333},[431,33434,19626],{"class":441},[431,33436,33437,33439,33441],{"class":433,"line":578},[431,33438,13429],{"class":441},[431,33440,1189],{"class":654},[431,33442,21007],{"class":441},[431,33444,33445,33448,33450,33452],{"class":433,"line":584},[431,33446,33447],{"class":654},"        for",[431,33449,32542],{"class":441},[431,33451,14421],{"class":654},[431,33453,33287],{"class":441},[431,33455,33456,33459,33461,33463,33465],{"class":433,"line":1244},[431,33457,33458],{"class":654},"            if",[431,33460,32542],{"class":441},[431,33462,8521],{"class":654},[431,33464,20572],{"class":437},[431,33466,8102],{"class":441},[431,33468,33469],{"class":433,"line":1985},[431,33470,33471],{"class":441},"                result.append(num)\n",[431,33473,33474,33476],{"class":433,"line":2041},[431,33475,10453],{"class":654},[431,33477,6812],{"class":441},[431,33479,33480,33482],{"class":433,"line":4018},[431,33481,6599],{"class":654},[431,33483,32193],{"class":441},[431,33485,33486],{"class":433,"line":4030},[431,33487,1662],{"emptyLinePlaceholder":393},[431,33489,33490,33492,33495,33497],{"class":433,"line":4419},[431,33491,33323],{"class":6333},[431,33493,33494],{"class":441},"(less_than(",[431,33496,856],{"class":437},[431,33498,6157],{"class":441},[431,33500,33501,33503,33505,33507,33509],{"class":433,"line":4436},[431,33502,6330],{"class":654},[431,33504,13212],{"class":437},[431,33506,442],{"class":441},[431,33508,1357],{"class":654},[431,33510,32527],{"class":441},[431,33512,33513,33515,33517],{"class":433,"line":4446},[431,33514,6796],{"class":441},[431,33516,1189],{"class":654},[431,33518,3459],{"class":437},[431,33520,33521,33523,33525,33527],{"class":433,"line":4451},[431,33522,14745],{"class":654},[431,33524,32542],{"class":441},[431,33526,14421],{"class":654},[431,33528,32547],{"class":441},[431,33530,33531,33533,33535],{"class":433,"line":4086},[431,33532,13429],{"class":441},[431,33534,12563],{"class":654},[431,33536,32556],{"class":441},[431,33538,33539,33541],{"class":433,"line":4477},[431,33540,6599],{"class":654},[431,33542,6812],{"class":441},[431,33544,33545],{"class":433,"line":4482},[431,33546,1662],{"emptyLinePlaceholder":393},[431,33548,33549,33551,33553,33555,33557,33559,33561,33563,33565,33567,33569],{"class":433,"line":4488},[431,33550,13265],{"class":437},[431,33552,442],{"class":441},[431,33554,971],{"class":437},[431,33556,4846],{"class":441},[431,33558,762],{"class":437},[431,33560,4846],{"class":441},[431,33562,856],{"class":437},[431,33564,4846],{"class":441},[431,33566,742],{"class":437},[431,33568,1014],{"class":441},[431,33570,32244],{"class":455},[431,33572,33573],{"class":433,"line":4505},[431,33574,33575],{"class":455},"# => filtered args =  [3, 4]\n",[431,33577,33578],{"class":433,"line":12871},[431,33579,1662],{"emptyLinePlaceholder":393},[431,33581,33582,33584,33586,33588],{"class":433,"line":2874},[431,33583,33323],{"class":6333},[431,33585,33494],{"class":441},[431,33587,971],{"class":437},[431,33589,6157],{"class":441},[431,33591,33592,33594,33596,33598,33600],{"class":433,"line":12887},[431,33593,6330],{"class":654},[431,33595,13212],{"class":437},[431,33597,442],{"class":441},[431,33599,1357],{"class":654},[431,33601,32527],{"class":441},[431,33603,33604,33606,33608],{"class":433,"line":12892},[431,33605,6796],{"class":441},[431,33607,1189],{"class":654},[431,33609,3459],{"class":437},[431,33611,33612,33614,33616,33618],{"class":433,"line":12898},[431,33613,14745],{"class":654},[431,33615,32542],{"class":441},[431,33617,14421],{"class":654},[431,33619,32547],{"class":441},[431,33621,33622,33624,33626],{"class":433,"line":12904},[431,33623,13429],{"class":441},[431,33625,12563],{"class":654},[431,33627,32556],{"class":441},[431,33629,33630,33632],{"class":433,"line":8382},[431,33631,6599],{"class":654},[431,33633,6812],{"class":441},[431,33635,33636],{"class":433,"line":25829},[431,33637,1662],{"emptyLinePlaceholder":393},[431,33639,33640,33642,33644,33646,33648,33650,33652,33654,33656,33658,33660],{"class":433,"line":25838},[431,33641,13265],{"class":437},[431,33643,442],{"class":441},[431,33645,971],{"class":437},[431,33647,4846],{"class":441},[431,33649,762],{"class":437},[431,33651,4846],{"class":441},[431,33653,856],{"class":437},[431,33655,4846],{"class":441},[431,33657,742],{"class":437},[431,33659,1014],{"class":441},[431,33661,13922],{"class":455},[431,33663,33664],{"class":433,"line":1890},[431,33665,33666],{"class":455},"# => filtered args =  []\n",[632,33668,33670],{"id":33669},"выводы","Выводы",[415,33672,33673],{},"Мы изучили декораторы, мощный механизм для расширения функций.\nСуществует большое количество готовых декораторов, доступных в стандартной библиотеке Python и других библиотеках.\nНекоторые из них позволяют кэшировать результаты функций, обеспечивать авторизацию и безопасность, профилировать код, проверять типы данных и многое другое.",[415,33675,30931,33676,1853,33678,1857],{},[800,33677,1852],{},[800,33679,1856],{},[1859,33681],{},[1862,33683,33684],{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}",{"title":426,"searchDepth":452,"depth":1244,"links":33686},[33687],{"id":32134,"depth":452,"text":32135,"children":33688},[33689,33690,33691,33692],{"id":32144,"depth":578,"text":32145},{"id":32502,"depth":578,"text":32503},{"id":33079,"depth":578,"text":33080},{"id":33669,"depth":578,"text":33670},"2024-12-04","Что такое декораторы функций и как их использовать","images\u002Fblog\u002Fpython\u002Fst23\u002Fimg.png",{},{"title":250,"description":33694},"i-rdfcRzc3i_lrY-JV7S1UKNvc-CBHwE5OX3bTNHnTI",{"id":33700,"title":254,"author":33701,"body":33703,"date":35298,"description":35299,"extension":1887,"image":35300,"meta":35301,"minRead":15016,"navigation":393,"num":12904,"path":255,"seo":35302,"stem":256,"__hash__":35303},"python\u002Fblog\u002Fpython\u002Fst24.md",{"name":402,"avatar":33702},{"src":404,"alt":405},{"type":407,"value":33704,"toc":35280},[33705,33708,33711,33715,33729,33732,33735,33746,33749,33752,33756,33764,33771,33780,33786,33789,33792,33798,33801,33900,34135,34431,34436,34439,34444,34451,34481,34487,34490,34524,34527,34557,34560,34563,34741,34744,34815,34822,34824,34827,34832,34837,34842,34846,34850,34853,34875,34879,34882,34886,34889,34892,34895,34898,34945,34948,34951,34957,34960,34963,34967,34970,34976,34979,34984,34987,34990,34994,34997,35124,35128,35131,35140,35145,35149,35152,35169,35172,35175,35178,35183,35186,35200,35205,35209,35212,35215,35257,35266,35271,35274,35277],[410,33706,254],{"id":33707},"знакомство-с-алгоритмами",[29130,33709],{":isList":33710,"title":29133},"[\"Вы познакомитесь с первым алгоритмом поиска(бинарный поиск).\",\"Вы узнаете, как описывается время выполнения алгоритма концепцией \\\"О-большое\\\".\"]",[632,33712,33714],{"id":33713},"введение","Введение",[415,33716,33717,33722,33723,33728],{},[800,33718,33719],{},[1355,33720,33721],{},"Алгоритмом"," называется набор инструкций для выполнения некоторой задачи.\nВ принципе любой работающий фрагмент программного кода можно назвать алгоритмом. В данной статье рассмотрим алгоритм двоичного или ",[800,33724,33725],{},[1355,33726,33727],{},"бинарного поиска",".\nДанный алгоритм например позволяет сократить количество необходимых операций поиска с 1 миллиарда до 30!\nВот ещё некоторые примеры применения алгоритмов.\nУстройства GPS используют алгоритмы из теории графов. При помощи методов динамического программирования можно создать алгоритм для игры в шашки.",[415,33730,33731],{},"Чтобы понять эффективность тех или иных алгоритмов – нужно научится сравнивать их сильные и слабые стороны.\nНапример, из каких соображений выбирать между быстрой сортировкой и сортировкой слиянием?\nЧто использовать — словарь или список?\nДаже выбор другой структуры, а иногда и другого языка программирования может оказать сильное влияние на конечный результат решения задачи.",[415,33733,33734],{},"Зачем изучать алгоритмы? Чтобы освоить эффективные методы решения задач, которые вам сейчас, возможно, неизвестны.\nЗная методы применения алгоритмов и сами алгоритмы вы сможете например:",[697,33736,33737,33740,33743],{},[700,33738,33739],{},"Создавая видеоигры написать систему на базе искусственного интеллекта, моделирующую действия пользователя с применением алгоритмов из теории графов;",[700,33741,33742],{},"Создавать рекомендательные системы по алгоритму k ближайших соседей;",[700,33744,33745],{},"Некоторые задачи не решить за разумное время! Зная алгоритмы NP-полноты, вы сможете идентифицировать такие задачи и построить решения для получения приближенного ответа.",[415,33747,33748],{},"Если сказать шире, то к концу изучения наиболее часто применяемых алгоритмов вы сможете воспользоваться знаниями, чтобы изучать более специализированные алгоритмы из области искусственного интеллекта, баз данных и т.п.",[415,33750,33751],{},"Чтобы было проще понимать тему алгоритмов необходимо знать базовую алгебру, а также вам необходимо владеть уверенно хотя бы одним языком программирования.\nЕсли такие знания у вас есть, то можно приступать!",[632,33753,33755],{"id":33754},"бинарный-поиск","Бинарный поиск",[415,33757,33758,33759,2699],{},"Допустим, вы ищите фамилию человека в телефонном справочнике(книге).\nОна начинается на букву \"М\" и можно конечно начать искать с самого начала и идти по каждой странице, пока не доберётесь до буквы \"М\".\nНо для ускорения поиска лучше раскрыть справочник на середине(буква \"М\" как раз должна находится где-то ближе к середине книги).\nТеперь допустим что вы вводите свои данные на каком нибудь сайте(в ВК например).\nПри этом сайту необходимо будет проверить, есть ли у вас учётная запись. Например, вы выбрали себе ник(имя пользователя) \"karlmarks\".\nСайт может начать с буквы \"a\" и проверять все логины подряд, но разумнее будет опять же начать с середины.\nПеред нами задача поиска. И во всех этих случаях можно применить один алгоритм: ",[800,33760,33761],{},[1355,33762,33763],{},"бинарный(двоичный) поиск",[415,33765,33766,33770],{},[1355,33767,33768],{},[800,33769,33755],{}," — это алгоритм: на входе которого должен быть отсортированный список всех элементов поиска, а на выходе мы должны получить номер(индекс) искомого элемента из этого же списка(или же ничего если элемент не будет найден).",[415,33772,33773,33774,33779],{},"Рассмотрим пример. Вы должны отгадать моё число от 1 до 100. При каждой попытке я буду давать один из трёх ответов: \"много\", \"мало\" или \"угадано\".\nДопустим, вы начинаете перебирать все варианты подряд: 1,2,3,4,5,... Это пример простого поиска(или даже \"тупого\").\nПри каждой догадке исключается только одно число. Если я загадал число 48, то, чтобы добраться до него, потребуется 48 попыток(или 52 если идти с конца 100, 99, 98, ...)!\nТут то и может прийти на помощь бинарный поиск. Сразу начнём с середины — с 50. - \"Много\". Но вы исключили сразу половину чисел. Теперь вы знаете что числа больше 50(50-100) будут больше загаданного.\nСледующая попытка алгоритма: 25. - \"Мало\". На этот раз \"недолёт\". Но вы снова исключили половину оставшихся чисел! Получается что, ",[800,33775,33776],{},[1355,33777,33778],{},"с бинарным поиском каждый отбрасывается половина диапазона!","\nСледующим будет число: 38(посередине между 25 и 50) и т.д. Пока не будет найдено загаданное число.\nПопробуем определить точнее, сколько чисел будет исключаться каждый раз?",[415,33781,33782],{},[15324,33783],{"alt":33784,"src":33785},"Пример использования бинарного поиска","\u002Fimages\u002Fblog\u002Fpython\u002Fst24\u002Fimg1.png",[415,33787,33788],{},"И так получается что, какое бы число я не загадал от 1 до 100, с помощью алгоритма бинарного поиска, вы отгадаете его точно за 7 попыток.",[415,33790,33791],{},"Выполните простое упражнение: вы ищите слово в словаре с 200000 словами. Как вы думаете, сколько попыток вам понадобится в худшем случае?\nПри простом поиске может потребоваться до 200000 попыток, если вы начала сначала, а искомое слово находится на самом последнем месте.\nНо если вы использовали бинарный поиск, то количество слов сокращается вдвое, пока не останется только одно искомое слово.",[415,33793,33794],{},[15324,33795],{"alt":33796,"src":33797},"Пример 2 использования бинарного поиска","\u002Fimages\u002Fblog\u002Fpython\u002Fst24\u002Fimg2.png",[415,33799,33800],{},"Итак, бинарный поиск отнимет всего 18 шагов!",[415,33802,33803,33804,33807,33808,33896,33897,33899],{},"В общем случае для списка из ",[1355,33805,33806],{},"n"," элементов бинарный поиск выполняется за ",[33809,33810,33814],"mjx-container",{"className":33811,"jax":33813},[33812],"MathJax","SVG",[33815,33816,33824,33848],"svg",{"style":33817,"xmlns":33818,"width":33819,"height":33820,"role":15324,"focusable":33821,"viewBox":33822,"xmlnsXLink":33823},"vertical-align: -0.464ex;","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","5.196ex","2.034ex","false","0 -694 2296.6 899","http:\u002F\u002Fwww.w3.org\u002F1999\u002Fxlink",[33825,33826,33827,33832,33836,33840,33844],"defs",{},[33828,33829],"path",{"id":33830,"d":33831},"MJX-1-TEX-I-1D459","M117 59Q117 26 142 26Q179 26 205 131Q211 151 215 152Q217 153 225 153H229Q238 153 241 153T246 151T248 144Q247 138 245 128T234 90T214 43T183 6T137 -11Q101 -11 70 11T38 85Q38 97 39 102L104 360Q167 615 167 623Q167 626 166 628T162 632T157 634T149 635T141 636T132 637T122 637Q112 637 109 637T101 638T95 641T94 647Q94 649 96 661Q101 680 107 682T179 688Q194 689 213 690T243 693T254 694Q266 694 266 686Q266 675 193 386T118 83Q118 81 118 75T117 65V59Z",[33828,33833],{"id":33834,"d":33835},"MJX-1-TEX-I-1D45C","M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z",[33828,33837],{"id":33838,"d":33839},"MJX-1-TEX-I-1D454","M311 43Q296 30 267 15T206 0Q143 0 105 45T66 160Q66 265 143 353T314 442Q361 442 401 394L404 398Q406 401 409 404T418 412T431 419T447 422Q461 422 470 413T480 394Q480 379 423 152T363 -80Q345 -134 286 -169T151 -205Q10 -205 10 -137Q10 -111 28 -91T74 -71Q89 -71 102 -80T116 -111Q116 -121 114 -130T107 -144T99 -154T92 -162L90 -164H91Q101 -167 151 -167Q189 -167 211 -155Q234 -144 254 -122T282 -75Q288 -56 298 -13Q311 35 311 43ZM384 328L380 339Q377 350 375 354T369 368T359 382T346 393T328 402T306 405Q262 405 221 352Q191 313 171 233T151 117Q151 38 213 38Q269 38 323 108L331 118L384 328Z",[33828,33841],{"id":33842,"d":33843},"MJX-1-TEX-N-32","M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z",[33828,33845],{"id":33846,"d":33847},"MJX-1-TEX-I-1D45B","M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z",[33849,33850,33853],"g",{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},"currentColor","scale(1,-1)",[33849,33854,33856,33864,33871,33889],{"dataMmlNode":33855},"math",[33849,33857,33859],{"dataMmlNode":33858},"mi",[33860,33861],"use",{"dataC":33862,"xLinkHref":33863},"1D459","#MJX-1-TEX-I-1D459",[33849,33865,33867],{"dataMmlNode":33858,"transform":33866},"translate(298,0)",[33860,33868],{"dataC":33869,"xLinkHref":33870},"1D45C","#MJX-1-TEX-I-1D45C",[33849,33872,33875,33881],{"dataMmlNode":33873,"transform":33874},"msub","translate(783,0)",[33849,33876,33877],{"dataMmlNode":33858},[33860,33878],{"dataC":33879,"xLinkHref":33880},"1D454","#MJX-1-TEX-I-1D454",[33849,33882,33885],{"dataMmlNode":33883,"transform":33884},"mn","translate(510,-150) scale(0.707)",[33860,33886],{"dataC":33887,"xLinkHref":33888},"32","#MJX-1-TEX-N-32",[33849,33890,33892],{"dataMmlNode":33858,"transform":33891},"translate(1696.6,0)",[33860,33893],{"dataC":33894,"xLinkHref":33895},"1D45B","#MJX-1-TEX-I-1D45B"," шагов, тогда как простой поиск будет выполнен за ",[1355,33898,33806],{}," шагов.",[8839,33901,33902],{},[415,33903,33904,33905,34014,34015,34017,34018,34068,34069,34134],{},"Логарифм — обратная операция возведению в степень. ",[33809,33906,33908],{"className":33907,"jax":33813},[33812],[33815,33909,33913,33932],{"style":33817,"xmlns":33818,"width":33910,"height":33911,"role":15324,"focusable":33821,"viewBox":33912,"xmlnsXLink":33823},"17.251ex","2.161ex","0 -750 7625.1 955",[33825,33914,33915,33918,33921,33924,33928],{},[33828,33916],{"id":33917,"d":33831},"MJX-2-TEX-I-1D459",[33828,33919],{"id":33920,"d":33835},"MJX-2-TEX-I-1D45C",[33828,33922],{"id":33923,"d":33839},"MJX-2-TEX-I-1D454",[33828,33925],{"id":33926,"d":33927},"MJX-2-TEX-N-31","M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z",[33828,33929],{"id":33930,"d":33931},"MJX-2-TEX-N-30","M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z",[33849,33933,33934],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,33935,33936,33941,33946,33966,33976,33984,33990,33995,34000,34005],{"dataMmlNode":33855},[33849,33937,33938],{"dataMmlNode":33858},[33860,33939],{"dataC":33862,"xLinkHref":33940},"#MJX-2-TEX-I-1D459",[33849,33942,33943],{"dataMmlNode":33858,"transform":33866},[33860,33944],{"dataC":33869,"xLinkHref":33945},"#MJX-2-TEX-I-1D45C",[33849,33947,33948,33953],{"dataMmlNode":33873,"transform":33874},[33849,33949,33950],{"dataMmlNode":33858},[33860,33951],{"dataC":33879,"xLinkHref":33952},"#MJX-2-TEX-I-1D454",[33849,33954,33957],{"dataMmlNode":33955,"transform":33884,"dataMjxTexclass":33956},"TeXAtom","ORD",[33849,33958,33959,33962],{"dataMmlNode":33883},[33860,33960],{"dataC":30856,"xLinkHref":33961},"#MJX-2-TEX-N-31",[33860,33963],{"dataC":19593,"xLinkHref":33964,"transform":33965},"#MJX-2-TEX-N-30","translate(500,0)",[33849,33967,33969,33971,33973],{"dataMmlNode":33883,"transform":33968},"translate(2050.1,0)",[33860,33970],{"dataC":30856,"xLinkHref":33961},[33860,33972],{"dataC":19593,"xLinkHref":33964,"transform":33965},[33860,33974],{"dataC":19593,"xLinkHref":33964,"transform":33975},"translate(1000,0)",[33849,33977,33979],{"dataMmlNode":33858,"transform":33978},"translate(3550.1,0)",[7859,33980,27658],{"dataVariant":33981,"transform":33852,"font-size":33982,"font-family":33983,"font-style":33981},"italic","884px","serif",[33849,33985,33987],{"dataMmlNode":33858,"transform":33986},"translate(4150.1,0)",[7859,33988,33989],{"dataVariant":33981,"transform":33852,"font-size":33982,"font-family":33983,"font-style":33981},"л",[33849,33991,33993],{"dataMmlNode":33858,"transform":33992},"translate(4750.1,0)",[7859,33994,27658],{"dataVariant":33981,"transform":33852,"font-size":33982,"font-family":33983,"font-style":33981},[33849,33996,33998],{"dataMmlNode":33858,"transform":33997},"translate(5350.1,0)",[33860,33999],{"dataC":33862,"xLinkHref":33940},[33849,34001,34003],{"dataMmlNode":33858,"transform":34002},"translate(5648.1,0)",[33860,34004],{"dataC":33879,"xLinkHref":33952},[33849,34006,34008,34010,34012],{"dataMmlNode":33883,"transform":34007},"translate(6125.1,0)",[33860,34009],{"dataC":30856,"xLinkHref":33961},[33860,34011],{"dataC":19593,"xLinkHref":33964,"transform":33965},[33860,34013],{"dataC":19593,"xLinkHref":33964,"transform":33975}," это означает, сколько раз нужно перемножить число 10, чтобы получить число 100. ",[1518,34016],{},"\nКогда я буду писать ",[33809,34019,34021],{"className":34020,"jax":33813},[33812],[33815,34022,34027,34042],{"style":34023,"xmlns":33818,"width":34024,"height":34025,"role":15324,"focusable":33821,"viewBox":34026,"xmlnsXLink":33823},"vertical-align: -0.05ex;","5.038ex","1.62ex","0 -694 2227 716",[33825,34028,34029,34032,34036,34039],{},[33828,34030],{"id":34031,"d":33831},"MJX-3-TEX-I-1D459",[33828,34033],{"id":34034,"d":34035},"MJX-3-TEX-I-1D44F","M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z",[33828,34037],{"id":34038,"d":33927},"MJX-3-TEX-N-31",[33828,34040],{"id":34041,"d":33931},"MJX-3-TEX-N-30",[33849,34043,34044],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,34045,34046,34051,34057],{"dataMmlNode":33855},[33849,34047,34048],{"dataMmlNode":33858},[33860,34049],{"dataC":33862,"xLinkHref":34050},"#MJX-3-TEX-I-1D459",[33849,34052,34053],{"dataMmlNode":33858,"transform":33866},[33860,34054],{"dataC":34055,"xLinkHref":34056},"1D44F","#MJX-3-TEX-I-1D44F",[33849,34058,34060,34063,34066],{"dataMmlNode":33883,"transform":34059},"translate(727,0)",[33860,34061],{"dataC":30856,"xLinkHref":34062},"#MJX-3-TEX-N-31",[33860,34064],{"dataC":19593,"xLinkHref":34065,"transform":33965},"#MJX-3-TEX-N-30",[33860,34067],{"dataC":19593,"xLinkHref":34065,"transform":33975}," я буду иметь в виду ",[33809,34070,34072],{"className":34071,"jax":33813},[33812],[33815,34073,34076,34096],{"style":33817,"xmlns":33818,"width":34074,"height":33820,"role":15324,"focusable":33821,"viewBox":34075,"xmlnsXLink":33823},"7.232ex","0 -694 3196.6 899",[33825,34077,34078,34081,34084,34087,34090,34093],{},[33828,34079],{"id":34080,"d":33831},"MJX-4-TEX-I-1D459",[33828,34082],{"id":34083,"d":33835},"MJX-4-TEX-I-1D45C",[33828,34085],{"id":34086,"d":33839},"MJX-4-TEX-I-1D454",[33828,34088],{"id":34089,"d":33843},"MJX-4-TEX-N-32",[33828,34091],{"id":34092,"d":33927},"MJX-4-TEX-N-31",[33828,34094],{"id":34095,"d":33931},"MJX-4-TEX-N-30",[33849,34097,34098],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,34099,34100,34105,34110,34124],{"dataMmlNode":33855},[33849,34101,34102],{"dataMmlNode":33858},[33860,34103],{"dataC":33862,"xLinkHref":34104},"#MJX-4-TEX-I-1D459",[33849,34106,34107],{"dataMmlNode":33858,"transform":33866},[33860,34108],{"dataC":33869,"xLinkHref":34109},"#MJX-4-TEX-I-1D45C",[33849,34111,34112,34117],{"dataMmlNode":33873,"transform":33874},[33849,34113,34114],{"dataMmlNode":33858},[33860,34115],{"dataC":33879,"xLinkHref":34116},"#MJX-4-TEX-I-1D454",[33849,34118,34119],{"dataMmlNode":33955,"transform":33884,"dataMjxTexclass":33956},[33849,34120,34121],{"dataMmlNode":33883},[33860,34122],{"dataC":33887,"xLinkHref":34123},"#MJX-4-TEX-N-32",[33849,34125,34126,34129,34132],{"dataMmlNode":33883,"transform":33891},[33860,34127],{"dataC":30856,"xLinkHref":34128},"#MJX-4-TEX-N-31",[33860,34130],{"dataC":19593,"xLinkHref":34131,"transform":33965},"#MJX-4-TEX-N-30",[33860,34133],{"dataC":19593,"xLinkHref":34131,"transform":33975}," это означает, сколько раз нужно перемножить число 2, чтобы получить 100.",[415,34136,34137,34138,34218,34219,34280,34281,34218,34367,34430],{},"Итак, мы получили закономерность. Для списка из 8 чисел максимально может потребоваться 8 проверок.\nДля того же списка с применением алгоритма бинарного поиска потребуется: ",[33809,34139,34141],{"className":34140,"jax":33813},[33812],[33815,34142,34145,34171],{"style":33817,"xmlns":33818,"width":34143,"height":33820,"role":15324,"focusable":33821,"viewBox":34144,"xmlnsXLink":33823},"9.118ex","0 -694 4030.1 899",[33825,34146,34147,34150,34153,34156,34159,34163,34167],{},[33828,34148],{"id":34149,"d":33831},"MJX-5-TEX-I-1D459",[33828,34151],{"id":34152,"d":33835},"MJX-5-TEX-I-1D45C",[33828,34154],{"id":34155,"d":33839},"MJX-5-TEX-I-1D454",[33828,34157],{"id":34158,"d":33843},"MJX-5-TEX-N-32",[33828,34160],{"id":34161,"d":34162},"MJX-5-TEX-N-38","M70 417T70 494T124 618T248 666Q319 666 374 624T429 515Q429 485 418 459T392 417T361 389T335 371T324 363L338 354Q352 344 366 334T382 323Q457 264 457 174Q457 95 399 37T249 -22Q159 -22 101 29T43 155Q43 263 172 335L154 348Q133 361 127 368Q70 417 70 494ZM286 386L292 390Q298 394 301 396T311 403T323 413T334 425T345 438T355 454T364 471T369 491T371 513Q371 556 342 586T275 624Q268 625 242 625Q201 625 165 599T128 534Q128 511 141 492T167 463T217 431Q224 426 228 424L286 386ZM250 21Q308 21 350 55T392 137Q392 154 387 169T375 194T353 216T330 234T301 253T274 270Q260 279 244 289T218 306L210 311Q204 311 181 294T133 239T107 157Q107 98 150 60T250 21Z",[33828,34164],{"id":34165,"d":34166},"MJX-5-TEX-N-3D","M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z",[33828,34168],{"id":34169,"d":34170},"MJX-5-TEX-N-33","M127 463Q100 463 85 480T69 524Q69 579 117 622T233 665Q268 665 277 664Q351 652 390 611T430 522Q430 470 396 421T302 350L299 348Q299 347 308 345T337 336T375 315Q457 262 457 175Q457 96 395 37T238 -22Q158 -22 100 21T42 130Q42 158 60 175T105 193Q133 193 151 175T169 130Q169 119 166 110T159 94T148 82T136 74T126 70T118 67L114 66Q165 21 238 21Q293 21 321 74Q338 107 338 175V195Q338 290 274 322Q259 328 213 329L171 330L168 332Q166 335 166 348Q166 366 174 366Q202 366 232 371Q266 376 294 413T322 525V533Q322 590 287 612Q265 626 240 626Q208 626 181 615T143 592T132 580H135Q138 579 143 578T153 573T165 566T175 555T183 540T186 520Q186 498 172 481T127 463Z",[33849,34172,34173],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,34174,34175,34180,34185,34199,34204,34212],{"dataMmlNode":33855},[33849,34176,34177],{"dataMmlNode":33858},[33860,34178],{"dataC":33862,"xLinkHref":34179},"#MJX-5-TEX-I-1D459",[33849,34181,34182],{"dataMmlNode":33858,"transform":33866},[33860,34183],{"dataC":33869,"xLinkHref":34184},"#MJX-5-TEX-I-1D45C",[33849,34186,34187,34192],{"dataMmlNode":33873,"transform":33874},[33849,34188,34189],{"dataMmlNode":33858},[33860,34190],{"dataC":33879,"xLinkHref":34191},"#MJX-5-TEX-I-1D454",[33849,34193,34194],{"dataMmlNode":33955,"transform":33884,"dataMjxTexclass":33956},[33849,34195,34196],{"dataMmlNode":33883},[33860,34197],{"dataC":33887,"xLinkHref":34198},"#MJX-5-TEX-N-32",[33849,34200,34201],{"dataMmlNode":33883,"transform":33891},[33860,34202],{"dataC":18740,"xLinkHref":34203},"#MJX-5-TEX-N-38",[33849,34205,34208],{"dataMmlNode":34206,"transform":34207},"mo","translate(2474.3,0)",[33860,34209],{"dataC":34210,"xLinkHref":34211},"3D","#MJX-5-TEX-N-3D",[33849,34213,34215],{"dataMmlNode":33883,"transform":34214},"translate(3530.1,0)",[33860,34216],{"dataC":26975,"xLinkHref":34217},"#MJX-5-TEX-N-33"," потому что ",[33809,34220,34222],{"className":34221,"jax":33813},[33812],[33815,34223,34228,34246],{"style":34224,"xmlns":33818,"width":34225,"height":34226,"role":15324,"focusable":33821,"viewBox":34227,"xmlnsXLink":33823},"vertical-align: -0.186ex;","6.896ex","2.071ex","0 -833.2 3048.1 915.2",[33825,34229,34230,34233,34236,34239,34242],{},[33828,34231],{"id":34232,"d":33843},"MJX-6-TEX-N-32",[33828,34234],{"id":34235,"d":34170},"MJX-6-TEX-N-33",[33828,34237],{"id":34238,"d":34166},"MJX-6-TEX-N-3D",[33828,34240],{"id":34241,"d":34162},"MJX-6-TEX-N-38",[33828,34243],{"id":34244,"d":34245},"MJX-6-TEX-N-2E","M78 60Q78 84 95 102T138 120Q162 120 180 104T199 61Q199 36 182 18T139 0T96 17T78 60Z",[33849,34247,34248],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,34249,34250,34264,34270],{"dataMmlNode":33855},[33849,34251,34253,34258],{"dataMmlNode":34252},"msup",[33849,34254,34255],{"dataMmlNode":33883},[33860,34256],{"dataC":33887,"xLinkHref":34257},"#MJX-6-TEX-N-32",[33849,34259,34261],{"dataMmlNode":33883,"transform":34260},"translate(533,363) scale(0.707)",[33860,34262],{"dataC":26975,"xLinkHref":34263},"#MJX-6-TEX-N-33",[33849,34265,34267],{"dataMmlNode":34206,"transform":34266},"translate(1214.3,0)",[33860,34268],{"dataC":34210,"xLinkHref":34269},"#MJX-6-TEX-N-3D",[33849,34271,34273,34276],{"dataMmlNode":33883,"transform":34272},"translate(2270.1,0)",[33860,34274],{"dataC":18740,"xLinkHref":34275},"#MJX-6-TEX-N-38",[33860,34277],{"dataC":34278,"xLinkHref":34279,"transform":33965},"2E","#MJX-6-TEX-N-2E","\nДля списка из 512 элементов с применением алгоритма бинарного поиска потребуется: ",[33809,34282,34284],{"className":34283,"jax":33813},[33812],[33815,34285,34288,34316],{"style":33817,"xmlns":33818,"width":34286,"height":33820,"role":15324,"focusable":33821,"viewBox":34287,"xmlnsXLink":33823},"11.38ex","0 -694 5030.1 899",[33825,34289,34290,34293,34296,34299,34302,34306,34309,34312],{},[33828,34291],{"id":34292,"d":33831},"MJX-7-TEX-I-1D459",[33828,34294],{"id":34295,"d":33835},"MJX-7-TEX-I-1D45C",[33828,34297],{"id":34298,"d":33839},"MJX-7-TEX-I-1D454",[33828,34300],{"id":34301,"d":33843},"MJX-7-TEX-N-32",[33828,34303],{"id":34304,"d":34305},"MJX-7-TEX-N-35","M164 157Q164 133 148 117T109 101H102Q148 22 224 22Q294 22 326 82Q345 115 345 210Q345 313 318 349Q292 382 260 382H254Q176 382 136 314Q132 307 129 306T114 304Q97 304 95 310Q93 314 93 485V614Q93 664 98 664Q100 666 102 666Q103 666 123 658T178 642T253 634Q324 634 389 662Q397 666 402 666Q410 666 410 648V635Q328 538 205 538Q174 538 149 544L139 546V374Q158 388 169 396T205 412T256 420Q337 420 393 355T449 201Q449 109 385 44T229 -22Q148 -22 99 32T50 154Q50 178 61 192T84 210T107 214Q132 214 148 197T164 157Z",[33828,34307],{"id":34308,"d":33927},"MJX-7-TEX-N-31",[33828,34310],{"id":34311,"d":34166},"MJX-7-TEX-N-3D",[33828,34313],{"id":34314,"d":34315},"MJX-7-TEX-N-39","M352 287Q304 211 232 211Q154 211 104 270T44 396Q42 412 42 436V444Q42 537 111 606Q171 666 243 666Q245 666 249 666T257 665H261Q273 665 286 663T323 651T370 619T413 560Q456 472 456 334Q456 194 396 97Q361 41 312 10T208 -22Q147 -22 108 7T68 93T121 149Q143 149 158 135T173 96Q173 78 164 65T148 49T135 44L131 43Q131 41 138 37T164 27T206 22H212Q272 22 313 86Q352 142 352 280V287ZM244 248Q292 248 321 297T351 430Q351 508 343 542Q341 552 337 562T323 588T293 615T246 625Q208 625 181 598Q160 576 154 546T147 441Q147 358 152 329T172 282Q197 248 244 248Z",[33849,34317,34318],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,34319,34320,34325,34330,34344,34354,34360],{"dataMmlNode":33855},[33849,34321,34322],{"dataMmlNode":33858},[33860,34323],{"dataC":33862,"xLinkHref":34324},"#MJX-7-TEX-I-1D459",[33849,34326,34327],{"dataMmlNode":33858,"transform":33866},[33860,34328],{"dataC":33869,"xLinkHref":34329},"#MJX-7-TEX-I-1D45C",[33849,34331,34332,34337],{"dataMmlNode":33873,"transform":33874},[33849,34333,34334],{"dataMmlNode":33858},[33860,34335],{"dataC":33879,"xLinkHref":34336},"#MJX-7-TEX-I-1D454",[33849,34338,34339],{"dataMmlNode":33955,"transform":33884,"dataMjxTexclass":33956},[33849,34340,34341],{"dataMmlNode":33883},[33860,34342],{"dataC":33887,"xLinkHref":34343},"#MJX-7-TEX-N-32",[33849,34345,34346,34349,34352],{"dataMmlNode":33883,"transform":33891},[33860,34347],{"dataC":20633,"xLinkHref":34348},"#MJX-7-TEX-N-35",[33860,34350],{"dataC":30856,"xLinkHref":34351,"transform":33965},"#MJX-7-TEX-N-31",[33860,34353],{"dataC":33887,"xLinkHref":34343,"transform":33975},[33849,34355,34357],{"dataMmlNode":34206,"transform":34356},"translate(3474.3,0)",[33860,34358],{"dataC":34210,"xLinkHref":34359},"#MJX-7-TEX-N-3D",[33849,34361,34363],{"dataMmlNode":33883,"transform":34362},"translate(4530.1,0)",[33860,34364],{"dataC":34365,"xLinkHref":34366},"39","#MJX-7-TEX-N-39",[33809,34368,34370],{"className":34369,"jax":33813},[33812],[33815,34371,34375,34395],{"style":34224,"xmlns":33818,"width":34372,"height":34373,"role":15324,"focusable":33821,"viewBox":34374,"xmlnsXLink":33823},"9.159ex","2.072ex","0 -833.9 4048.1 915.9",[33825,34376,34377,34380,34383,34386,34389,34392],{},[33828,34378],{"id":34379,"d":33843},"MJX-8-TEX-N-32",[33828,34381],{"id":34382,"d":34315},"MJX-8-TEX-N-39",[33828,34384],{"id":34385,"d":34166},"MJX-8-TEX-N-3D",[33828,34387],{"id":34388,"d":34305},"MJX-8-TEX-N-35",[33828,34390],{"id":34391,"d":33927},"MJX-8-TEX-N-31",[33828,34393],{"id":34394,"d":34245},"MJX-8-TEX-N-2E",[33849,34396,34397],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,34398,34399,34411,34416],{"dataMmlNode":33855},[33849,34400,34401,34406],{"dataMmlNode":34252},[33849,34402,34403],{"dataMmlNode":33883},[33860,34404],{"dataC":33887,"xLinkHref":34405},"#MJX-8-TEX-N-32",[33849,34407,34408],{"dataMmlNode":33883,"transform":34260},[33860,34409],{"dataC":34365,"xLinkHref":34410},"#MJX-8-TEX-N-39",[33849,34412,34413],{"dataMmlNode":34206,"transform":34266},[33860,34414],{"dataC":34210,"xLinkHref":34415},"#MJX-8-TEX-N-3D",[33849,34417,34418,34421,34424,34426],{"dataMmlNode":33883,"transform":34272},[33860,34419],{"dataC":20633,"xLinkHref":34420},"#MJX-8-TEX-N-35",[33860,34422],{"dataC":30856,"xLinkHref":34423,"transform":33965},"#MJX-8-TEX-N-31",[33860,34425],{"dataC":33887,"xLinkHref":34405,"transform":33975},[33860,34427],{"dataC":34278,"xLinkHref":34428,"transform":34429},"#MJX-8-TEX-N-2E","translate(1500,0)","\nСледовательно, для списка из 512 чисел придётся проверить не более 9 чисел.",[8839,34432,34433],{},[415,34434,34435],{},"Бинарный поиск работает только в отсортированных последовательностях элементов. Но что произойдет если элементы не будут отсортированы?",[415,34437,34438],{},"Рассмотрим, как запрограммировать реализацию бинарного поиска на Python. В следующем примере кода используется список.",[8839,34440,34441],{},[415,34442,34443],{},"Поскольку в Python массивы называются списками, термины массив и список часто используются как взаимозаменяемые. Но в реализациях алгоритмов на различных языках программирования могут быть отличия при создании списков(с возможностью увеличения количества элементов) либо массивов(с заранее ограниченным числом элементов).",[415,34445,34446,34447,34450],{},"Чтобы понять работу самого алгоритма, нам достаточно пока будет знать, что серию элементов можно сохранить в непрерывной последовательности ячеек, которая называется массивом.\nНумерация ячеек в которых хранятся сами элементы массива начинается с 0: первая ячейка имеет позицию с индексом(номером) 0, вторая — в позиции 1 и так далее.\nДля реализации любых алгоритмов лучше всего написать функцию. Что такое функции? Также минимум нужно знать, что они принимают значения(например массив) и внутри себя что-то с ними делают и наконец возвращают результат.\nФункцию так и назовём ",[428,34448,34449],{},"binary_search",", которая будет получать на вход отсортированный массив(список) и значение. Если значение присутствует в массиве, то функция возвращает его позицию(номер или индекс).\nПри этом мы должны следить внутри функции за тем, в какой части массива проводится поиск. В самом начале это весь массив:",[422,34452,34454],{"className":424,"code":34453,"language":396,"meta":426,"style":426},"low = 0\nhigh = len(my_list) - 1\n",[428,34455,34456,34465],{"__ignoreMap":426},[431,34457,34458,34461,34463],{"class":433,"line":434},[431,34459,34460],{"class":441},"low ",[431,34462,1189],{"class":654},[431,34464,3459],{"class":437},[431,34466,34467,34470,34472,34474,34477,34479],{"class":433,"line":452},[431,34468,34469],{"class":441},"high ",[431,34471,1189],{"class":654},[431,34473,4804],{"class":437},[431,34475,34476],{"class":441},"(my_list) ",[431,34478,853],{"class":654},[431,34480,3916],{"class":437},[415,34482,34483],{},[15324,34484],{"alt":34485,"src":34486},"Использование бинарного поиска","\u002Fimages\u002Fblog\u002Fpython\u002Fst24\u002Fimg3.png",[415,34488,34489],{},"Каждый раз алгоритм проверят средний элемент:",[422,34491,34493],{"className":424,"code":34492,"language":396,"meta":426,"style":426},"mid = (low + high) \u002F\u002F 2\nguess = my_list[mid]\n",[428,34494,34495,34514],{"__ignoreMap":426},[431,34496,34497,34500,34502,34505,34507,34510,34512],{"class":433,"line":434},[431,34498,34499],{"class":441},"mid ",[431,34501,1189],{"class":654},[431,34503,34504],{"class":441}," (low ",[431,34506,802],{"class":654},[431,34508,34509],{"class":441}," high) ",[431,34511,16854],{"class":654},[431,34513,658],{"class":437},[431,34515,34516,34519,34521],{"class":433,"line":452},[431,34517,34518],{"class":441},"guess ",[431,34520,1189],{"class":654},[431,34522,34523],{"class":441}," my_list[mid]\n",[415,34525,34526],{},"Если названое число было слишком велико, то переменная high обновляется:",[422,34528,34530],{"className":424,"code":34529,"language":396,"meta":426,"style":426},"if guess > item:\n    high = mid - 1\n",[428,34531,34532,34543],{"__ignoreMap":426},[431,34533,34534,34536,34539,34541],{"class":433,"line":434},[431,34535,10399],{"class":654},[431,34537,34538],{"class":441}," guess ",[431,34540,8883],{"class":654},[431,34542,24020],{"class":441},[431,34544,34545,34548,34550,34553,34555],{"class":433,"line":452},[431,34546,34547],{"class":441},"    high ",[431,34549,1189],{"class":654},[431,34551,34552],{"class":441}," mid ",[431,34554,853],{"class":654},[431,34556,3916],{"class":437},[415,34558,34559],{},"А если догадка была слишком мала, то обновляется переменная low.",[415,34561,34562],{},"Полный код выглядит так:",[422,34564,34566],{"className":424,"code":34565,"language":396,"meta":426,"style":426},"def search_iterative(my_list, item):\n  # в переменных low и high хранятся границы той части списка, в которой выполняется поиск\n  low = 0\n  high = len(my_list) - 1\n  # Пока эта часть не сократится до одного элемента ...\n  while low \u003C= high:\n    # ... проверяем средний элемент\n    mid = (low + high) \u002F\u002F 2\n    guess = my_list[mid]\n    # Если значение найдено возвращаем его номер(индекс списка)\n    if guess == item:\n      return mid\n    # Если найдено значение больше - уменьшаем верхний индекс(границу)\n    if guess > item:\n      high = mid - 1\n    # Если найдено значение меньше - увеличиваем нижний индекс(границу)\n    else:\n      low = mid + 1\n  # Элемент не найден\n  return None\n",[428,34567,34568,34578,34583,34592,34607,34612,34625,34630,34647,34656,34661,34671,34678,34683,34693,34706,34711,34717,34730,34735],{"__ignoreMap":426},[431,34569,34570,34572,34575],{"class":433,"line":434},[431,34571,6330],{"class":654},[431,34573,34574],{"class":6333}," search_iterative",[431,34576,34577],{"class":441},"(my_list, item):\n",[431,34579,34580],{"class":433,"line":452},[431,34581,34582],{"class":455},"  # в переменных low и high хранятся границы той части списка, в которой выполняется поиск\n",[431,34584,34585,34588,34590],{"class":433,"line":578},[431,34586,34587],{"class":441},"  low ",[431,34589,1189],{"class":654},[431,34591,3459],{"class":437},[431,34593,34594,34597,34599,34601,34603,34605],{"class":433,"line":584},[431,34595,34596],{"class":441},"  high ",[431,34598,1189],{"class":654},[431,34600,4804],{"class":437},[431,34602,34476],{"class":441},[431,34604,853],{"class":654},[431,34606,3916],{"class":437},[431,34608,34609],{"class":433,"line":1244},[431,34610,34611],{"class":455},"  # Пока эта часть не сократится до одного элемента ...\n",[431,34613,34614,34617,34620,34622],{"class":433,"line":1985},[431,34615,34616],{"class":654},"  while",[431,34618,34619],{"class":441}," low ",[431,34621,12667],{"class":654},[431,34623,34624],{"class":441}," high:\n",[431,34626,34627],{"class":433,"line":2041},[431,34628,34629],{"class":455},"    # ... проверяем средний элемент\n",[431,34631,34632,34635,34637,34639,34641,34643,34645],{"class":433,"line":4018},[431,34633,34634],{"class":441},"    mid ",[431,34636,1189],{"class":654},[431,34638,34504],{"class":441},[431,34640,802],{"class":654},[431,34642,34509],{"class":441},[431,34644,16854],{"class":654},[431,34646,658],{"class":437},[431,34648,34649,34652,34654],{"class":433,"line":4030},[431,34650,34651],{"class":441},"    guess ",[431,34653,1189],{"class":654},[431,34655,34523],{"class":441},[431,34657,34658],{"class":433,"line":4419},[431,34659,34660],{"class":455},"    # Если значение найдено возвращаем его номер(индекс списка)\n",[431,34662,34663,34665,34667,34669],{"class":433,"line":4436},[431,34664,10438],{"class":654},[431,34666,34538],{"class":441},[431,34668,8409],{"class":654},[431,34670,24020],{"class":441},[431,34672,34673,34675],{"class":433,"line":4446},[431,34674,22936],{"class":654},[431,34676,34677],{"class":441}," mid\n",[431,34679,34680],{"class":433,"line":4451},[431,34681,34682],{"class":455},"    # Если найдено значение больше - уменьшаем верхний индекс(границу)\n",[431,34684,34685,34687,34689,34691],{"class":433,"line":4086},[431,34686,10438],{"class":654},[431,34688,34538],{"class":441},[431,34690,8883],{"class":654},[431,34692,24020],{"class":441},[431,34694,34695,34698,34700,34702,34704],{"class":433,"line":4477},[431,34696,34697],{"class":441},"      high ",[431,34699,1189],{"class":654},[431,34701,34552],{"class":441},[431,34703,853],{"class":654},[431,34705,3916],{"class":437},[431,34707,34708],{"class":433,"line":4482},[431,34709,34710],{"class":455},"    # Если найдено значение меньше - увеличиваем нижний индекс(границу)\n",[431,34712,34713,34715],{"class":433,"line":4488},[431,34714,10575],{"class":654},[431,34716,8102],{"class":441},[431,34718,34719,34722,34724,34726,34728],{"class":433,"line":4505},[431,34720,34721],{"class":441},"      low ",[431,34723,1189],{"class":654},[431,34725,34552],{"class":441},[431,34727,802],{"class":654},[431,34729,3916],{"class":437},[431,34731,34732],{"class":433,"line":12871},[431,34733,34734],{"class":455},"  # Элемент не найден\n",[431,34736,34737,34739],{"class":433,"line":2874},[431,34738,20132],{"class":654},[431,34740,11872],{"class":437},[415,34742,34743],{},"После того как создали функцию, можно её протестировать:",[422,34745,34747],{"className":424,"code":34746,"language":396,"meta":426,"style":426},"my_list = [1, 3, 5, 7, 9]  # Список с отсортированными элементами(обязательно по возрастанию)\nprint(search_iterative(my_list, 3)) # => 1 — нумерация с 0.\n# \"None\" в Python означает ничего. Мы используем для обозначения того, что элемент не найден.\nprint(search_iterative(my_list, -1)) # => None\n",[428,34748,34749,34781,34796,34801],{"__ignoreMap":426},[431,34750,34751,34754,34756,34758,34760,34762,34764,34766,34768,34770,34772,34774,34776,34778],{"class":433,"line":434},[431,34752,34753],{"class":441},"my_list ",[431,34755,1189],{"class":654},[431,34757,17401],{"class":441},[431,34759,1192],{"class":437},[431,34761,4846],{"class":441},[431,34763,971],{"class":437},[431,34765,4846],{"class":441},[431,34767,856],{"class":437},[431,34769,4846],{"class":441},[431,34771,781],{"class":437},[431,34773,4846],{"class":441},[431,34775,3357],{"class":437},[431,34777,3612],{"class":441},[431,34779,34780],{"class":455},"# Список с отсортированными элементами(обязательно по возрастанию)\n",[431,34782,34783,34785,34788,34790,34793],{"class":433,"line":452},[431,34784,438],{"class":437},[431,34786,34787],{"class":441},"(search_iterative(my_list, ",[431,34789,971],{"class":437},[431,34791,34792],{"class":441},")) ",[431,34794,34795],{"class":455},"# => 1 — нумерация с 0.\n",[431,34797,34798],{"class":433,"line":578},[431,34799,34800],{"class":455},"# \"None\" в Python означает ничего. Мы используем для обозначения того, что элемент не найден.\n",[431,34802,34803,34805,34807,34809,34811,34813],{"class":433,"line":584},[431,34804,438],{"class":437},[431,34806,34787],{"class":441},[431,34808,853],{"class":654},[431,34810,1192],{"class":437},[431,34812,34792],{"class":441},[431,34814,6577],{"class":455},[415,34816,34817,34818,1853,34820,1857],{},"Попробуйте сами скопировать и запустить код в окне ниже с интерпретатором Python и повторите примеры из статьи чтобы самим увидеть и понять как всё это работает.\nДля этого в ячейке с кодом нажмите клавиши на клавиатуре ",[800,34819,1852],{},[800,34821,1856],{},[1859,34823],{},[415,34825,34826],{},"Полную реализацию алгоритма вы можете скачать ниже по ссылке(скачать файл):",[34828,34829],"downloadlink",{"address":34830,"description":34831},"\u002Ffiles\u002Fpython\u002Fst21\u002Fbinary_search.py","Скачать файл",[8839,34833,34834],{},[415,34835,34836],{},"Если скачали и увидели реализацию алгоритма с помощью \"рекурсии\" и создание класса? Чтобы понять эту реализацию бинарного поиска, нужно разобраться отдельно что же такое рекурсивные алгоритмы и создание классов в Python.",[8839,34838,34839],{},[415,34840,34841],{},"Двоичный поиск является одной из реализаций техники построения алгоритмов под названием разделяй и властвуй (divide and conquer, D&C).\nАлгоритмы D&C решают одну или более независимых подзадач, после чего совмещают их решения для поиска решения исходной задачи (двоичный поиск решает только одну подзадачу,\nсоответствующую той части входных данных, о которой известно, что она содержит решение, в то время как другие алгоритм D&C обычно решают две или более подзадач).\nЧтобы больше узнать об этом семействе алгоритмов и некоторых задачах, которые они эффективно решают, советую книгу Тима Рафгардена(Tim Roughgarden) Совершенный алгоритм. Основы. СПб.: Питер.",[29386,34843],{":isAnswers":34844,":isList":34845,"title":29391},"[\"8\",\"9\"]","[\"Имеется отсортированный список из 250 имён, вы ищите в нём значение методом бинарного поиска. Какое максимальное количество проверок для этого может потребоваться?\",\"Предположим, размер списка увеличился вдвое. Как измениться максимальное количество проверок?\"]",[632,34847,34849],{"id":34848},"время-выполнения-алгоритмов","Время выполнения алгоритмов",[415,34851,34852],{},"Каждый раз, когда я буду описывать очередной алгоритм, я буду отмечать время его выполнения.\nОбычно следует выбирать самый эффективный алгоритм при решении задач, будь то оптимизация по времени или памяти.",[415,34854,34855,34856,34861,34862,34865,34866,34861,34871,34874],{},"Обсудим время выполнения бинарного поиска. Если список состоит из 100 элементов, то при линейном поиске может потребоваться до 100 попыток.\nДля списка из 4 миллиардов элементов(чисел) потребуется до 4 миллиардов попыток. Таким образом, максимальное количество попыток соответствует размеру массива(списка).\nТакое время выполнение называется ",[1355,34857,34858],{},[800,34859,34860],{},"линейным"," и обозначается как ",[800,34863,34864],{},"O(n)",". С бинарным поиском дело обстоит иначе. Если список состоит из 100 элементов, потребуется не более 7 попыток.\nДля списка из 4 миллиардов элементов потребуется не более 32 попыток. Соответственно бинарный поиск выполняется за ",[1355,34867,34868],{},[800,34869,34870],{},"логарифмическое время",[800,34872,34873],{},"O(lbn)"," (имеется ввиду двоичный логарифм — логарифм по основанию 2).",[458,34876,34878],{"id":34877},"о-большое","\"О-большое\"",[415,34880,34881],{},"Специальная нотация \"О-большое\" описывает скорость работы алгоритма. Зачем это нужно?\nВремя от времени всем программистам приходится использовать различные алгоритмы при решении задач.\nНеплохо было бы понимать, насколько быстро или медленно они работают.\nНиже разберём что представляет собой \"О-большое\" и приведём несколько примеров распространённых вариантов времени выполнения для некоторых алгоритмов.",[12129,34883,34885],{"id":34884},"время-выполнения-растёт-с-разной-скоростью","Время выполнения растёт с разной скоростью",[415,34887,34888],{},"Допустим Иван пишет алгоритм поиска для Роскосмоса. Его алгоритм работает, когда ракета будет подлетать к луне и поможет вычислить точку посадки.\nИван пытается выбрать между линейным и бинарным поиском. Его алгоритм должен работать быстро и правильно. У Ивана есть 10 секунд, чтобы выбрать место посадки.\nЕсли он не уложится в это время, то момент для посадки будет упущен.\nС одной стороны бинарный поиск работает быстрее, с другой стороны, линейный поиск пишется проще и вероятность ошибки в нём ниже...\nКонечно же, Иван не хочет допустить ошибку в коде посадки ракеты. И тогда для лучшей уверенности он решает измерить время выполнения обоих алгоритмов для списка из 100 элементов.",[415,34890,34891],{},"Допустим, проверка одного элемента занимает 1 миллисекунду (мс). При простом поиске Ивану придётся проверить 100 элементов, и поиск займёт 100 мс.\nС другой стороны, при бинарном поиске достаточно проверить всего 7 элементов(lb100 равен приблизительно 7), а поиск займёт 7 мс.\nНо реальный список может содержать более миллиарда элементов.\nСколько времени в таком случае потребуется для выполнения простого поиска? А при бинарном поиске?\nОбязательно попробуйте ответить на два этих вопроса прежде чем продолжить чтение дальше.",[415,34893,34894],{},"Иван проводит бинарный поиск с 1 миллиардом элементов, и на это уходит 30 мс(lb2 1000000000 равен примерно 30).\nИван думает, что бинарный поиск в 15 раз быстрее простого, потому что линейный поиск для 100 элементов занял 100 мс, а бинарный всего 7 мс.\nЗначит, линейный поиск с 1 миллиардом элементов займёт 30 * 15 = 450 мс, так? Гораздо меньше отведённых 10 секунд?\nИ Иван выбирает линейный поиск. Верен ли его выбор?",[415,34896,34897],{},"Нет, Иван ошибается. Время выполнения простого поиска с 1 миллиардом элементов составит миллиард миллисекунд, а это 11 дней!\nПроблема в том, что время выполнения для бинарного и линейного поиска растёт с разной скоростью!",[9256,34899,34900,34912],{},[9259,34901,34902],{},[9262,34903,34904,34907,34910],{},[9265,34905,34906],{},"Количество элементов",[9265,34908,34909],{},"Линейный поиск",[9265,34911,33755],{},[9275,34913,34914,34924,34934],{},[9262,34915,34916,34918,34921],{},[9280,34917,2249],{},[9280,34919,34920],{},"100 мс",[9280,34922,34923],{},"7 мс",[9262,34925,34926,34929,34931],{},[9280,34927,34928],{},"10 000",[9280,34930,29167],{},[9280,34932,34933],{},"14 мс",[9262,34935,34936,34939,34942],{},[9280,34937,34938],{},"1 000 000 000",[9280,34940,34941],{},"11 дней",[9280,34943,34944],{},"30 мс",[415,34946,34947],{},"Время выполнения растёт с совершенно разной скоростью!",[415,34949,34950],{},"Простыми словами, с увеличением количества элементов бинарный поиск займёт чуть больше времени, тогда как линейный займёт гораздо больше времени!\nЕсли список состоит из 1 миллиарда элементов, то бинарный поиск работает приблизительно в 33 миллиона раз быстрее линейного!\nВот почему недостаточно знать, сколько времени отработает алгоритм — необходимо знать, как возрастает время выполнения с ростом размера количества выполняемых им операций.\n\"О-большое\" как раз описывает, насколько быстро работает алгоритм.\nПредположим, имеется список размера n. Время выполнения \"О-большое\" простого линейного поиска в общем случае выглядит как:",[415,34952,34953],{},[15324,34954],{"alt":34955,"src":34956},"Время выполнения линейного поиска","\u002Fimages\u002Fblog\u002Fpython\u002Fst24\u002Fimg4.png",[415,34958,34959],{},"Такая запись сообщает количество операций, которые придётся выполнить алгоритму.\nОна называется \"О-большое\", потому что перед количеством операций ставиться символ \"О\"(большое потому что в верхнем регистре).",[415,34961,34962],{},"Теперь рассмотрим несколько примеров и попробуем оценить время выполнения алгоритмов.",[12129,34964,34966],{"id":34965},"наглядное-представление-о-большое","Наглядное представление \"О-большое\"",[415,34968,34969],{},"Допустим вы должны построить сетку из 16 квадратов. Для этого достаточно иметь несколько листков бумаги и карандаш.",[415,34971,34972],{},[15324,34973],{"alt":34974,"src":34975},"Сетка 4*4","\u002Fimages\u002Fblog\u002Fpython\u002Fst24\u002Fimg5.png",[415,34977,34978],{},"Как должен выглядеть алгоритм построения такой сетки?",[34980,34981,34983],"h6",{"id":34982},"алгоритм-1","Алгоритм 1",[415,34985,34986],{},"Нарисовать 16 квадратов, по одному за раз. В данном примере рисование квадрата считается одной операцией.\nНужно нарисовать 16 квадратов. Сколько операций по рисованию квадрата придётся выполнить?\nЧтобы нарисовать 16 квадратов, потребуется 16 шагов. Как выглядит время выполнения алгоритма?",[415,34988,34989],{},"Ответ: O(n).",[34980,34991,34993],{"id":34992},"алгоритм-2","Алгоритм 2",[415,34995,34996],{},"А теперь попробуем так. Сложите лист пополам. На этот раз операцией считается сложение листка.\nПолучается, что одна операция создаёт сразу два прямоугольника.\nСложите затем ещё раз, а потом ещё и ещё.\nИ наконец, разверните листок после четырёх сложений — получилась сетка! Каждое сложение удваивает количество прямоугольников.\nПолучилось, что за 4 операции создаётся 16 прямоугольников! При каждом складывании количество прямоугольников увеличивается вдвое!\nКак записать время выполнения этого алгоритма?",[415,34998,34999,35000],{},"Ответ: ",[33809,35001,35003],{"className":35002,"jax":33813},[33812],[33815,35004,35009,35045],{"style":35005,"xmlns":33818,"width":35006,"height":35007,"role":15324,"focusable":33821,"viewBox":35008,"xmlnsXLink":33823},"vertical-align: -0.566ex;","12.313ex","2.262ex","0 -750 5442.6 1000",[33825,35010,35011,35015,35019,35022,35025,35028,35032,35036,35039,35042],{},[33828,35012],{"id":35013,"d":35014},"MJX-9-TEX-I-1D442","M740 435Q740 320 676 213T511 42T304 -22Q207 -22 138 35T51 201Q50 209 50 244Q50 346 98 438T227 601Q351 704 476 704Q514 704 524 703Q621 689 680 617T740 435ZM637 476Q637 565 591 615T476 665Q396 665 322 605Q242 542 200 428T157 216Q157 126 200 73T314 19Q404 19 485 98T608 313Q637 408 637 476Z",[33828,35016],{"id":35017,"d":35018},"MJX-9-TEX-N-28","M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z",[33828,35020],{"id":35021,"d":33831},"MJX-9-TEX-I-1D459",[33828,35023],{"id":35024,"d":34035},"MJX-9-TEX-I-1D44F",[33828,35026],{"id":35027,"d":33847},"MJX-9-TEX-I-1D45B",[33828,35029],{"id":35030,"d":35031},"MJX-9-TEX-N-29","M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z",[33828,35033],{"id":35034,"d":35035},"MJX-9-TEX-N-7C","M139 -249H137Q125 -249 119 -235V251L120 737Q130 750 139 750Q152 750 159 735V-235Q151 -249 141 -249H139Z",[33828,35037],{"id":35038,"d":33835},"MJX-9-TEX-I-1D45C",[33828,35040],{"id":35041,"d":33839},"MJX-9-TEX-I-1D454",[33828,35043],{"id":35044,"d":33843},"MJX-9-TEX-N-32",[33849,35046,35047],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,35048,35049,35055,35062,35068,35074,35080,35086,35093,35098,35104,35119],{"dataMmlNode":33855},[33849,35050,35051],{"dataMmlNode":33858},[33860,35052],{"dataC":35053,"xLinkHref":35054},"1D442","#MJX-9-TEX-I-1D442",[33849,35056,35058],{"dataMmlNode":34206,"transform":35057},"translate(763,0)",[33860,35059],{"dataC":35060,"xLinkHref":35061},"28","#MJX-9-TEX-N-28",[33849,35063,35065],{"dataMmlNode":33858,"transform":35064},"translate(1152,0)",[33860,35066],{"dataC":33862,"xLinkHref":35067},"#MJX-9-TEX-I-1D459",[33849,35069,35071],{"dataMmlNode":33858,"transform":35070},"translate(1450,0)",[33860,35072],{"dataC":34055,"xLinkHref":35073},"#MJX-9-TEX-I-1D44F",[33849,35075,35077],{"dataMmlNode":33858,"transform":35076},"translate(1879,0)",[33860,35078],{"dataC":33894,"xLinkHref":35079},"#MJX-9-TEX-I-1D45B",[33849,35081,35083],{"dataMmlNode":34206,"transform":35082},"translate(2479,0)",[33860,35084],{"dataC":30851,"xLinkHref":35085},"#MJX-9-TEX-N-29",[33849,35087,35089],{"dataMmlNode":34206,"transform":35088},"translate(2868,0) translate(0 -0.5)",[33860,35090],{"dataC":35091,"xLinkHref":35092},"7C","#MJX-9-TEX-N-7C",[33849,35094,35096],{"dataMmlNode":33858,"transform":35095},"translate(3146,0)",[33860,35097],{"dataC":33862,"xLinkHref":35067},[33849,35099,35101],{"dataMmlNode":33858,"transform":35100},"translate(3444,0)",[33860,35102],{"dataC":33869,"xLinkHref":35103},"#MJX-9-TEX-I-1D45C",[33849,35105,35107,35112],{"dataMmlNode":33873,"transform":35106},"translate(3929,0)",[33849,35108,35109],{"dataMmlNode":33858},[33860,35110],{"dataC":33879,"xLinkHref":35111},"#MJX-9-TEX-I-1D454",[33849,35113,35114],{"dataMmlNode":33955,"transform":33884,"dataMjxTexclass":33956},[33849,35115,35116],{"dataMmlNode":33883},[33860,35117],{"dataC":33887,"xLinkHref":35118},"#MJX-9-TEX-N-32",[33849,35120,35122],{"dataMmlNode":33858,"transform":35121},"translate(4842.6,0)",[33860,35123],{"dataC":33894,"xLinkHref":35079},[12129,35125,35127],{"id":35126},"о-большое-всегда-определяет-время-в-худшем-случае","\"О-большое\" всегда определяет время в худшем случае",[415,35129,35130],{},"Предположим вы ищете в телефонной книге фамилию используя линейный(простой поиск).\nВы знаете что простой поиск выполняется за время O(n), то есть в худшем случае вам придётся просмотреть каждую запись без исключения.\nНо представьте что искомая фамилия начинается на букву \"А\" и этот человек которого вы ищите, стоит на самом первом месте в вашей телефонной книге.\nВам не пришлось(в этот раз) просматривать все записи — вы нашли сразу нужную фамилию человека которому собрались позвонить.\nОтработал ли алгоритм за время O(n)? Или он занял время O(1), потому что результат был получен с первой попытки поиска?",[415,35132,35133,35134,35139],{},"Простой поиск, всё равно как алгоритм, выполняется за время O(n). Просто в данном случае вам повезло и вы нашли сразу нужное значение.\n",[1355,35135,35136],{},[800,35137,35138],{},"Однако нотация \"О-большое\" всегда описывает наихудший случай.","\nЗаписью O(n) фактически утверждается что придётся просмотреть каждую запись в телефонной книге по одной за раз.\nИ также запись O(n) даёт определённые гарантии — вы всегда уверены, что линейный(простой) поиск никогда не будет работать медленнее.",[8839,35141,35142],{},[415,35143,35144],{},"Наряду с временем худшего случая нужно также учитывать среднее время выполнения. Тема худшего и среднего времени выполнения будет рассмотрена в следующих статьях.",[12129,35146,35148],{"id":35147},"примеры-о-большого","Примеры \"О-большого\"",[415,35150,35151],{},"Ниже приведём несколько примеров из пяти разновидностей \"О-большого, которые встречаются особенно часто, в порядке убывания скорости выполнения:",[697,35153,35154,35157,35160,35163,35166],{},[700,35155,35156],{},"O(lbn), или логарифмическое время. Пример: бинарный поиск.",[700,35158,35159],{},"O(n), или линейное время. Пример: простой поиск.",[700,35161,35162],{},"О(n * lbn). Пример: эффективные алгоритмы сортировки(быстрая сортировка).",[700,35164,35165],{},"О(n * n). Пример: медленные алгоритмы сортировки(сортировка выбором).",[700,35167,35168],{},"O(n!). Пример: очень медленные алгоритмы(задача о коммивояжере).",[415,35170,35171],{},"Допустим, вы снова строите сетку из 16 квадратов и можете выбрать для решения задачи один из пяти алгоритмов.\nПри использовании первого алгоритма сетка будет построена за время O(lbn).\nВ секунду выполняются до 10 операций. С временем O(lbn) для построения сетки из 16 квадратов потребуются 4 операции(lbn16 = 4).\nИтак, сетка будет построена за 0,4 секунды. А если бы было нужно построить 1024 квадрата? То O(lbn) = lb1024 = 10 операций или ровно 1 секунда.\nЭти числа получены при использовании первого алгоритма.",[415,35173,35174],{},"Второй алгоритм работает медленнее: за время O(n). Для построения 16 прямоугольников нужно 16 операций, а для построения 1024 прямоугольников — 1024 операции.\nСколько времени это займёт?",[415,35176,35177],{},"Ниже показано, сколько времени потребуется для построения сетки с остальными алгоритмами, от самого быстрого до самого медленного.",[415,35179,35180],{},[15324,35181],{"alt":34849,"src":35182},"\u002Fimages\u002Fblog\u002Fpython\u002Fst24\u002Fimg6.png",[415,35184,35185],{},"Эти записи являются упрощением. На практике не всегда удаётся легко преобразовать время выполнения в количество операций в секунду с такой точностью.\nОсновные выводы:",[697,35187,35188,35191,35194,35197],{},[700,35189,35190],{},"Скорость алгоритмов измеряется не в секундах, а в темпе роста количества операций;",[700,35192,35193],{},"Формула в аннотации \"О-большое\" описывает, насколько быстро возрастает время выполнения алгоритма с увеличением размера входных данных;",[700,35195,35196],{},"Время выполнения алгоритмов выражается как \"О-большое\";",[700,35198,35199],{},"Время выполнения O(lbn) быстрее O(n). С увеличением размера массива(списка), в котором происходит поиск значения, оно кратно быстрее.",[29386,35201],{":isAnswers":35202,":isList":35203,":startOl":971,"title":29391,"isText":35204},"[\"O(log n)\",\"O(n)\",\"O(n)\",\"O(n). Возможно, кто-то подумает: \\\"Я делаю это только для одной из 30 букв, а значит, время выполнения должно быть равно O(n\u002F30)\\\". Но для О-большого есть правило: игнорируются числа, задействованные в операциях сложения, вычитания, умножения или деления и т.п. 30 является просто константой в этом вопросе.\"]","[\"Известна фамилия, нужно найти номер в телефонной книге\",\"Известен номер, нужно найти фамилию в телефонной книге\",\"Нужно посчитать телефона всех людей в телефонной книге\",\"Нужно посчитать телефоны всех людей, фамилии которых начинаются с буквы \\\"А\\\"\"]","Назовите время выполнения \"О-большое\" для каждого из следующих сценариев",[458,35206,35208],{"id":35207},"задача-о-коммивояжере","Задача о коммивояжере",[415,35210,35211],{},"Наверное после прочтения предыдущего раздела можно подумать, что нам точно не попадётся задача с алгоритмом времени выполнения O(n!).\nНо здесь как раз таки пойдёт информация о такой задаче с очень и очень плохим временем выполнения.\nЭто известная задача из области вычислений в которой время выполнения вырастает просто с ужасающей скоростью.\nНекоторые очень умные люди считают, что с этим ничего нельзя поделать. Это задача о коммивояжере.",[415,35213,35214],{},"Смысл задачи в следующем: коммивояжер должен объехать города, например пусть будет пять городов.\nКоммивояжер хочет побывать в каждом из 5 городов так, чтобы при это ещё проехать минимальное общее расстояние.\nОдно из возможных решений: перебрать все возможные комбинации порядка объезда городов.\nВсе расстояния суммируются, после чего выбирается путь с кратчайшим расстоянием.\nДля 5 городов можно создать 120 перестановок, поэтому решение задачи для 5 городов потребует 120 операций.\nДля 6 городов количество операций увеличивается до 720(существует уже 720 возможных перестановок).\nА для 7 городов потребуется уже 5040 операций! Количество операций стремительно растёт!",[9256,35216,35217,35227],{},[9259,35218,35219],{},[9262,35220,35221,35224],{},[9265,35222,35223],{},"Города",[9265,35225,35226],{},"Операции",[9275,35228,35229,35236,35243,35250],{},[9262,35230,35231,35233],{},[9280,35232,742],{},[9280,35234,35235],{},"720",[9262,35237,35238,35240],{},[9280,35239,781],{},[9280,35241,35242],{},"5040",[9262,35244,35245,35247],{},[9280,35246,1021],{},[9280,35248,35249],{},"40320",[9262,35251,35252,35254],{},[9280,35253,22026],{},[9280,35255,35256],{},"1307674368000",[415,35258,35259,35260,35265],{},"В общем случае для вычисления результата при n элементах потребуется n-факториал операций.\nЗначит время выполнения составит O(n!) и такое время называется ",[1355,35261,35262],{},[800,35263,35264],{},"факториальным",".\nМожно сделать вывод: если вы попытаетесь решить задачу для 100+ городов, то сделать этот вовремя не удастся.\nИ как бы ни было это печально, но у задачи коммивояжера нет другого решения!\nЭто одна из самых знаменитых задач в теории вычислений!\nСчитается что для этой задачи можно найти лишь приближенное решение(с помощью жадного алгоритма).",[415,35267,35268],{},[1355,35269,35270],{},"P.S. Подробнее об остальных алгоритмов будет в следующих статьях.",[29130,35272],{":isList":35273,"title":30269},"[\"Бинарный поиск работает намного быстрее простого;\",\"Скорость алгоритмов не измеряется в секундах\",\"Время выполнения алгоритма описывается ростом количества операций\",\"Время выполнения алгоритмов записывается в нотации \\\"О-большое\\\"\",\"Время выполнения O(lbn) быстрее O(n), с увеличением количества элементов по которым осуществляется поиск, оно(время) становится намного быстрее\"]",[1862,35275,35276],{},"\nmjx-container[jax=\"SVG\"] {\n  direction: ltr;\n}\n\nmjx-container[jax=\"SVG\"] > svg {\n  overflow: visible;\n  min-height: 1px;\n  min-width: 1px;\n}\n\nmjx-container[jax=\"SVG\"] > svg a {\n  fill: blue;\n  stroke: blue;\n}\n\nmjx-container[jax=\"SVG\"][display=\"true\"] {\n  display: block;\n  text-align: center;\n  margin: 1em 0;\n}\n\nmjx-container[jax=\"SVG\"][display=\"true\"][width=\"full\"] {\n  display: flex;\n}\n\nmjx-container[jax=\"SVG\"][justify=\"left\"] {\n  text-align: left;\n}\n\nmjx-container[jax=\"SVG\"][justify=\"right\"] {\n  text-align: right;\n}\n\ng[data-mml-node=\"merror\"] > g {\n  fill: red;\n  stroke: red;\n}\n\ng[data-mml-node=\"merror\"] > rect[data-background] {\n  fill: yellow;\n  stroke: none;\n}\n\ng[data-mml-node=\"mtable\"] > line[data-line], svg[data-table] > g > line[data-line] {\n  stroke-width: 70px;\n  fill: none;\n}\n\ng[data-mml-node=\"mtable\"] > rect[data-frame], svg[data-table] > g > rect[data-frame] {\n  stroke-width: 70px;\n  fill: none;\n}\n\ng[data-mml-node=\"mtable\"] > .mjx-dashed, svg[data-table] > g > .mjx-dashed {\n  stroke-dasharray: 140;\n}\n\ng[data-mml-node=\"mtable\"] > .mjx-dotted, svg[data-table] > g > .mjx-dotted {\n  stroke-linecap: round;\n  stroke-dasharray: 0,140;\n}\n\ng[data-mml-node=\"mtable\"] > g > svg {\n  overflow: visible;\n}\n\n[jax=\"SVG\"] mjx-tool {\n  display: inline-block;\n  position: relative;\n  width: 0;\n  height: 0;\n}\n\n[jax=\"SVG\"] mjx-tool > mjx-tip {\n  position: absolute;\n  top: 0;\n  left: 0;\n}\n\nmjx-tool > mjx-tip {\n  display: inline-block;\n  padding: .2em;\n  border: 1px solid #888;\n  font-size: 70%;\n  background-color: #F8F8F8;\n  color: black;\n  box-shadow: 2px 2px 5px #AAAAAA;\n}\n\ng[data-mml-node=\"maction\"][data-toggle] {\n  cursor: pointer;\n}\n\nmjx-status {\n  display: block;\n  position: fixed;\n  left: 1em;\n  bottom: 1em;\n  min-width: 25%;\n  padding: .2em .4em;\n  border: 1px solid #888;\n  font-size: 90%;\n  background-color: #F8F8F8;\n  color: black;\n}\n\nforeignObject[data-mjx-xml] {\n  font-family: initial;\n  line-height: normal;\n  overflow: visible;\n}\n\nmjx-container[jax=\"SVG\"] path[data-c], mjx-container[jax=\"SVG\"] use[data-c] {\n  stroke-width: 3;\n}\n",[1862,35278,35279],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":426,"searchDepth":452,"depth":1244,"links":35281},[35282],{"id":33707,"depth":452,"text":254,"children":35283},[35284,35285,35286],{"id":33713,"depth":578,"text":33714},{"id":33754,"depth":578,"text":33755},{"id":34848,"depth":578,"text":34849,"children":35287},[35288,35297],{"id":34877,"depth":584,"text":34878,"children":35289},[35290,35291,35295,35296],{"id":34884,"depth":1244,"text":34885},{"id":34965,"depth":1244,"text":34966,"children":35292},[35293,35294],{"id":34982,"depth":1985,"text":34983},{"id":34992,"depth":1985,"text":34993},{"id":35126,"depth":1244,"text":35127},{"id":35147,"depth":1244,"text":35148},{"id":35207,"depth":584,"text":35208},"2025-10-02","Введение. Реализация алгоритма бинарного поиска. Время выполнения алгоритмов","images\u002Fblog\u002Fpython\u002Fst24\u002Fimg.png",{},{"title":254,"description":35299},"d18iAe0IVcWhOOwFIH6Bh-Tj0iTuIJgvDNZ6ZFznuQg",{"id":35305,"title":258,"author":35306,"body":35308,"date":40725,"description":40726,"extension":1887,"image":40727,"meta":40728,"minRead":40729,"navigation":393,"num":8382,"path":259,"seo":40730,"stem":260,"__hash__":40731},"python\u002Fblog\u002Fpython\u002Fst25.md",{"name":402,"avatar":35307},{"src":404,"alt":405},{"type":407,"value":35309,"toc":40679},[35310,35314,35320,35326,35330,35334,35337,35340,35343,35346,35352,35355,35358,35362,35365,35376,35400,35403,35407,35410,35414,35417,35420,35423,35427,35608,35611,35615,35622,35628,35637,35812,35893,35897,35906,36026,36059,36128,36131,36134,36151,36155,36158,36172,36179,36182,36185,36189,36192,36195,36198,36201,36204,36207,36210,36213,36220,36223,36226,36246,36249,36252,36279,36282,36285,36289,36292,36316,36319,36322,36325,36328,36472,36475,36492,36495,36498,36556,36559,36562,36565,36667,36670,36673,36676,36744,36751,36755,36758,36761,36782,36959,36965,36968,36971,36974,36989,37033,37036,37039,37042,37049,37058,37327,37334,37337,37340,37431,37451,37606,37639,37978,37982,37985,37997,38102,38108,38111,38122,38125,38384,38394,38400,38404,38407,38572,38575,38582,38585,38631,38634,38699,38702,38709,38712,38876,38879,39043,39046,39049,39216,39219,39383,39386,39783,39889,39893,39896,39899,39909,39912,39938,39941,39973,39976,39979,39987,39993,39996,40015,40026,40033,40090,40097,40100,40204,40207,40210,40213,40289,40314,40317,40327,40330,40333,40336,40339,40620,40632,40638,40644,40666,40669,40671,40674,40676],[410,35311,35313],{"id":35312},"примеры-задач-бинарного-поиска","Примеры задач бинарного поиска",[12129,35315,35317],{"id":35316},"рекомендую-изучать-примеры-задач-когда-вы-знаете-также-и-другие-алгоритмы-сортировки-рекурсии-жадные-алгоритмы-алгоритмы-на-графах-динамическое-программирование",[800,35318,35319],{},"РЕКОМЕНДУЮ ИЗУЧАТЬ ПРИМЕРЫ ЗАДАЧ КОГДА ВЫ ЗНАЕТЕ ТАКЖЕ И ДРУГИЕ АЛГОРИТМЫ: СОРТИРОВКИ, РЕКУРСИИ, ЖАДНЫЕ АЛГОРИТМЫ, АЛГОРИТМЫ НА ГРАФАХ, ДИНАМИЧЕСКОЕ ПРОГРАММИРОВАНИЕ!",[458,35321,35323],{"id":35322},"описание-алгоритма-здесь",[1205,35324,35325],{"href":255},"Описание алгоритма здесь",[458,35327,35329],{"id":35328},"задача-1-кормление-муравьев","Задача 1. Кормление муравьев",[12129,35331,35333],{"id":35332},"условие","Условие",[415,35335,35336],{},"У Боби есть террариум в форме дерева. Каждое ребро этого дерева является трубкой, по которой стекает жидкость.\nНекоторые ребра образованы супер трубками, по которым может протекать большее количество жидкости. В каждом листе\n(концевом узле) дерева находится один ручной муравей (согласен, что контекст фантастический, но сама задача очень интересная).",[415,35338,35339],{},"У каждой трубки-ребра есть значение веса, указывающее процент протекающей по ней жидкости.\nК примеру, из узла n исходят три трубки, по которым стекает 20%, 50% и 30% жидкости от общего объема.\nЕсли в узел n поступает 20 литров жидкости, тогда по первой трубке стекает 20 × 0,2 = 4 литра, по второй 20 × 0,5 = 10 литров, по третьей 20 × 0,3 = 6 литров.",[415,35341,35342],{},"Каждая супер трубка может работать в стандартном или супер режиме — в зависимости от выбора Боби.\nЕсли включен супер режим, то количество протекающей жидкости возводится в квадрат.",[415,35344,35345],{},"Боби заливает жидкость в корень дерева. Его цель — дать каждому муравью не меньше необходимого количества, минимизируя при этом заливаемый объем.\nКонкретизируем описание на примере террариума на рисунке.",[415,35347,35348],{},[15324,35349],{"alt":35350,"src":35351},"Задача 1. Условие","\u002Fimages\u002Fblog\u002Fpython\u002Fst25\u002Fimg1.png",[415,35353,35354],{},"Узлы пронумерованы от 1 до 6. Концевые узлы (2, 3, 5 и 6) имеют дополнительные значения, указывающие необходимое каждому муравью количество жидкости.\nТакже указаны процентные значения для ребер. Обратите внимание, что сумма этих значений для ребер, исходящих из одного узла, всегда равна 100%.\nВ дереве есть одна супер трубка, ведущая из узла 1 к узлу 4. Она обозначена красной линией.",[415,35356,35357],{},"Предположим, что в корень заливается 20 литров жидкости. Супер трубка получает 30% от 20 литров. Если супер режим этой трубки отключен, то через нее протекает 6 литров.\nЕсли же этот режим активен, то через нее пройдет 6 * 6 = 36 литров.",[12129,35359,35361],{"id":35360},"входные-данные","Входные данные",[415,35363,35364],{},"Входные данные содержат один тестовый пример, состоящий из следующих строк:",[697,35366,35367,35370,35373],{},[700,35368,35369],{},"целого числа n, задающего количество узлов в дереве. Значение n находится между 1 и 1000. Узлы дерева пронумерованы от 1 до n, а корнем является узел 1;",[700,35371,35372],{},"(n – 1) строк, используемых для построения дерева. Каждая содержит данные об одной трубке и состоит из четырех целых чисел: номеров двух узлов, соединяемых этой трубкой, ее процентного значения (между 1 и 100) и указания о возможности суперрежима (0 означает отсутствие, 1 — наличие);",[700,35374,35375],{},"строки, содержащей n целых чисел, по одному для каждого узла, сообщающих количество литров, необходимых муравью в этом узле. Каждому муравью требуется от 1 до 10 литров жидкости. Все не концевые узлы (в которых нет муравья) содержат значение –1.",[415,35377,35378,35379,35381,35382,35384,35385,35387,35388,35390,35391,35393,35394,35396,35397,35399],{},"Вот входные данные, которые сгенерируют образец террариума с рисунка выше: ",[1518,35380],{},"\n6 ",[1518,35383],{},"\n1 2 20 0 ",[1518,35386],{},"\n1 3 50 0 ",[1518,35389],{},"\n1 4 30 1 ",[1518,35392],{},"\n4 5 50 0 ",[1518,35395],{},"\n4 6 50 0 ",[1518,35398],{},"\n-1 2 9 -1 7 8",[415,35401,35402],{},"Обратите внимание, что первая строка (число 6) указывает количество узлов дерева, а не количество строк, его выстраивающих.\nЧисло строк, создающих дерево(в данном случае пять), всегда будет на единицу меньше числа узлов.",[12129,35404,35406],{"id":35405},"выходные-данные","Выходные данные",[415,35408,35409],{},"Требуется вывести минимальное количество литров жидкости, которое Боби должен залить в корневой узел дерева, чтобы напоить всех муравьев.\nТочность должна быть выше четырех цифр после запятой. Верное значение не будет превышать двух миллиардов.\nВремя на решение тестового примера — 2,5 секунды.",[12129,35411,35413],{"id":35412},"решение","Решение",[415,35415,35416],{},"В данном случае для исследования дерева террариума можно использовать алгоритм бинарного поиска или рекурсию.\nПоскольку дерево не предоставляет необходимую информацию в готовом виде, возьмем значение объема наугад.\nИтак, Боби, давай зальем в корень 10 литров. Вероятно, вас сильно удивит, если верным ответом окажется именно 10, ведь это\nчисло я выбрал наугад. Вас также может удивить, что, выбрав произвольное число и проанализировав происходящее, мы можем многое узнать.\nВернемся к рисунку из условия и предположим, что заливаем в корневой узел 10 литров. Итак, 20% от 10 — это 2, значит, 2 литра жидкости поступят к муравью в узле 2.\nИдеально: именно 2 литра ему и надо. Продолжим. Поскольку 50% от 10 равно 5, то муравей в узле 3 получает 5 литров жидкости.\nВот теперь у нас проблема, потому что ему нужно 9 литров. При этом трубка между узлами 1 и 3 не имеет супер режима, значит, изменить ситуацию нельзя и 10 верным решением не является.\nМожно продолжить подставлять наугад и другие количества жидкости, аналогичным образом моделируя ее течение по дереву.\nИ все же, если 10 литров оказалось недостаточно, теперь следует ограничить диапазон до значений больше 10.\nПоскольку 10 литров было мало, любое меньшее значение также окажется недостаточным. Нет смысла пробовать 2, 7, 9, 5 литров или любое другое количество меньше 10.",[415,35418,35419],{},"Теперь давайте возьмем 20 литров. На этот раз муравей в узле 2 получает 4 литра, что вполне нормально, так как ему достаточно двух.\nМуравей в узле 3 получает 10 литров, что также допустимо, потому что ему нужно 9.\nТрубка между узлами 1 и 4 проводит 30% жидкости, то есть 6 из 20 литров. Но при этом она еще и является супер трубкой!\nЕсли задействовать супер режим, то она прокачает 36 литров. Значит, в узел 4 протекает 36 литров.\nТеперь муравьи 5 и 6 будут довольны: каждый из них получает по 18 литров при том, что в узел 5 нужно 7, а в узел 6 — 8 литров.\nВ отличие от 10 литров, 20 оказалось допустимым решением, но является ли оно оптимальным (то есть минимальным)? Возможно, но не обязательно.\nОднозначно нам известно лишь то, что проверять количество более 20 литров смысла нет. 20 уже\nдает нам допустимое решение, так зачем пробовать 25 или 30, которые точно хуже?\nТеперь мы сократили область задачи до нахождения оптимального решения между 10 и 20 литрами.\nМожно продолжать подбирать числа, с каждым шагом сужая диапазон, пока он не станет столь мал, что его конечные точки окажутся точным решением.",[415,35421,35422],{},"Если рассуждать в общем, то какое количество литров следует выбирать изначально? Оптимальный объем может иметь значение вплоть до 2 миллиардов, так\nчто, начиная с 10, можно оказаться очень далеко от истины. Установив начальное значение, что следует делать дальше?\nОптимальное решение может быть значительно больше или меньше выбранного значения, значит, прибавление или вычитание 10 на каждом шаге может не слишком помочь в его поиске.\nСначала нужно разобраться с тем, как считывать входные данные (чтобы иметь возможность исследовать дерево) и определять, является ли некоторое количество литров допустимым решением.\nЗатем построить супер быстрый алгоритм для поиска в больших диапазонах.\nДиапазон в два миллиарда? Мы выполним расчет для него, не напрягаясь с помощью бинарного поиска.",[34980,35424,35426],{"id":35425},"считывание-входных-данных","СЧИТЫВАНИЕ ВХОДНЫХ ДАННЫХ",[422,35428,35430],{"className":424,"code":35429,"language":396,"meta":426,"style":426},"nodes = dict()  # Словарь узлов\nN = int(input()) # Количество узлов\nfor i in range(N - 1):\n    from_node, to_node, percentage, superpipe = map(int, input().split())\n    if from_node not in nodes:  # Если узла ещё нет\n        nodes[from_node] = [[], [], []]\n    nodes[from_node][0].append(to_node)\n    nodes[from_node][1].append(percentage)\n    nodes[from_node][2].append(superpipe)\nliquid_needed = list(map(int, input().split()))# Список по узлам конечных значений о количестве нужной каждому муравью жидкости\nprint(nodes) # => {1: [[2, 3, 4], [20, 50, 30], [0, 0, 1]], 4: [[5, 6], [50, 50], [0, 0]]}\nprint(liquid_needed) # => [-1, 2, 9, -1, 7, 8]\n",[428,35431,35432,35447,35465,35483,35504,35521,35531,35541,35550,35559,35588,35598],{"__ignoreMap":426},[431,35433,35434,35437,35439,35442,35444],{"class":433,"line":434},[431,35435,35436],{"class":441},"nodes ",[431,35438,1189],{"class":654},[431,35440,35441],{"class":437}," dict",[431,35443,27836],{"class":441},[431,35445,35446],{"class":455},"# Словарь узлов\n",[431,35448,35449,35451,35453,35455,35457,35459,35462],{"class":433,"line":452},[431,35450,30542],{"class":441},[431,35452,1189],{"class":654},[431,35454,4312],{"class":437},[431,35456,442],{"class":441},[431,35458,30551],{"class":437},[431,35460,35461],{"class":441},"()) ",[431,35463,35464],{"class":455},"# Количество узлов\n",[431,35466,35467,35469,35471,35473,35475,35477,35479,35481],{"class":433,"line":578},[431,35468,14329],{"class":654},[431,35470,12664],{"class":441},[431,35472,14421],{"class":654},[431,35474,14424],{"class":437},[431,35476,30584],{"class":441},[431,35478,853],{"class":654},[431,35480,1032],{"class":437},[431,35482,7381],{"class":441},[431,35484,35485,35488,35490,35493,35495,35497,35499,35501],{"class":433,"line":584},[431,35486,35487],{"class":441},"    from_node, to_node, percentage, superpipe ",[431,35489,1189],{"class":654},[431,35491,35492],{"class":437}," map",[431,35494,442],{"class":441},[431,35496,2266],{"class":437},[431,35498,4846],{"class":441},[431,35500,30551],{"class":437},[431,35502,35503],{"class":441},"().split())\n",[431,35505,35506,35508,35511,35513,35515,35518],{"class":433,"line":1244},[431,35507,10438],{"class":654},[431,35509,35510],{"class":441}," from_node ",[431,35512,9369],{"class":654},[431,35514,21531],{"class":654},[431,35516,35517],{"class":441}," nodes:  ",[431,35519,35520],{"class":455},"# Если узла ещё нет\n",[431,35522,35523,35526,35528],{"class":433,"line":1985},[431,35524,35525],{"class":441},"        nodes[from_node] ",[431,35527,1189],{"class":654},[431,35529,35530],{"class":441}," [[], [], []]\n",[431,35532,35533,35536,35538],{"class":433,"line":2041},[431,35534,35535],{"class":441},"    nodes[from_node][",[431,35537,3302],{"class":437},[431,35539,35540],{"class":441},"].append(to_node)\n",[431,35542,35543,35545,35547],{"class":433,"line":4018},[431,35544,35535],{"class":441},[431,35546,1192],{"class":437},[431,35548,35549],{"class":441},"].append(percentage)\n",[431,35551,35552,35554,35556],{"class":433,"line":4030},[431,35553,35535],{"class":441},[431,35555,651],{"class":437},[431,35557,35558],{"class":441},"].append(superpipe)\n",[431,35560,35561,35564,35566,35569,35571,35574,35576,35578,35580,35582,35585],{"class":433,"line":4419},[431,35562,35563],{"class":441},"liquid_needed ",[431,35565,1189],{"class":654},[431,35567,35568],{"class":437}," list",[431,35570,442],{"class":441},[431,35572,35573],{"class":437},"map",[431,35575,442],{"class":441},[431,35577,2266],{"class":437},[431,35579,4846],{"class":441},[431,35581,30551],{"class":437},[431,35583,35584],{"class":441},"().split()))",[431,35586,35587],{"class":455},"# Список по узлам конечных значений о количестве нужной каждому муравью жидкости\n",[431,35589,35590,35592,35595],{"class":433,"line":4436},[431,35591,438],{"class":437},[431,35593,35594],{"class":441},"(nodes) ",[431,35596,35597],{"class":455},"# => {1: [[2, 3, 4], [20, 50, 30], [0, 0, 1]], 4: [[5, 6], [50, 50], [0, 0]]}\n",[431,35599,35600,35602,35605],{"class":433,"line":4446},[431,35601,438],{"class":437},[431,35603,35604],{"class":441},"(liquid_needed) ",[431,35606,35607],{"class":455},"# => [-1, 2, 9, -1, 7, 8]\n",[415,35609,35610],{},"Переменная to_node указывает на дочерний узел, соединенный ребром с родительским. percentage является целым числом между 1 и 100, которое сообщает процентное\nзначение для трубки (ребра). superpipe — флаг, который имеет значение 1, если трубка имеет суперрежим, и 0, если такой режим отсутствует.\nВ частности, каждое ребро считывается из входных данных, затем устанавливаются его члены, после чего оно добавляется в список ребер для from_node.\nПри этом можно было бы предположить существование соответствующего ребра из to_node, потому что граф ненаправленный, но я такую возможность исключил:\nжидкость стекает вниз по дереву, но не вверх, значит, добавление обратных ребер излишне усложнит код, исследующий дерево.\nПосле считывания информации о дереве остается только считать значения количества жидкости, необходимого каждому муравью.\nДля этого используется список liquid_needed.\nКомбинация из nodes и liquid_needed обеспечивает всю необходимую нам информацию на тестовом примере.",[34980,35612,35614],{"id":35613},"проверка-пригодности-решения","ПРОВЕРКА ПРИГОДНОСТИ РЕШЕНИЯ",[415,35616,35617,35618,35621],{},"На следующем этапе надо определить, является ли заданное количество жидкости допустимым решением.\nЭто очень важный шаг, потому что, когда у нас появится функция для проверки допустимости значения,\nмы сможем использовать ее для постепенного сужения пространства поиска до момента обнаружения оптимального решения.\nДля этой функции мы напишем следующий заголовок: ",[428,35619,35620],{},"def can_feed(node, liquid, nodes, liquid_needed):",".\nЗдесь node является корневым узлом дерева, liquid указывает количество жидкости, заливаемой в корень, nodes представляет словарь для дерева,\nа liquid_needed отражает объем жидкости, необходимый каждому муравью. Если значения liquid окажется достаточно, будет возвращаться 1, в противном случае 0.",[415,35623,35624,35625],{},"Давайте теперь подумаем, можно ли применить рекурсию в этой задаче.\nВспомним, что для использования рекурсии требуется сформулировать базовый случай, который можно решить без рекурсии.\nК счастью, у нас такой имеется. Если дерево представлено одним концевым узлом, то можно сразу определить, достаточно ли количества liquid.\nЕсли liquid больше либо равно необходимому муравью количеству жидкости, то перед нами допустимое решение.\nВ противном случае решение не допустимое.\nОпределить, является ли узел концевым, можно проверкой соответствующего значения в liquid_needed:\nесли это -1, значит, он не концевой (можно также проверить, является ли связный список смежности пустым).\nВот что получается: ",[428,35626,35627],{},"if liquid_needed[node] != -1: return liquid >= liquid_needed[node]",[415,35629,35630,35631,35633,35634,35636],{},"А теперь рассмотрим рекурсивный алгоритм. Представьте, что корневой узел некоторого дерева имеет p нисходящих трубок (а значит, и p детей).\nДано количество заливаемой в корень жидкости. Используя процентные значения трубок, можно определить объем жидкости, которая поступает через каждую из них.\nПри этом с помощью статусов супертрубок можно определить количество жидкости на выходе из каждой трубки.\nЕсли до низа трубки доходит достаточный объем питья, то заливаемой в корень жидкости хватает и нужно вернуть ",[428,35632,4463],{},".\nЕсли до низа хотя бы одной из трубок доходит недостаточный объем жидкости, то возвращается ",[428,35635,4431],{},".\nЭто предполагает, что нужно сделать p рекурсивных вызовов, по одному для каждой нисходящей из корня трубки.\nСделаем мы это в цикле, использующем словарь для каждой такой трубки:",[422,35638,35640],{"className":424,"code":35639,"language":396,"meta":426,"style":426},"def can_feed(node, liquid, nodes, liquid_needed):\n    if liquid_needed[node - 1] != -1:\n        return liquid >= liquid_needed[node - 1]\n    e = nodes.get(node)\n    if e:\n        for p in range(len(e[0])):\n            down_pipe = liquid * e[1][p] \u002F 100  # e[1] это percentage — процентное значение для трубки\n            if e[2][p]: # если \"супер трубка\"\n                down_pipe *= down_pipe  # 2\n            if not can_feed(e[0][p], down_pipe, nodes, liquid_needed): # 3\n                return False\n    return True\n",[428,35641,35642,35652,35673,35690,35700,35707,35730,35756,35770,35783,35799,35806],{"__ignoreMap":426},[431,35643,35644,35646,35649],{"class":433,"line":434},[431,35645,6330],{"class":654},[431,35647,35648],{"class":6333}," can_feed",[431,35650,35651],{"class":441},"(node, liquid, nodes, liquid_needed):\n",[431,35653,35654,35656,35659,35661,35663,35665,35667,35669,35671],{"class":433,"line":452},[431,35655,10438],{"class":654},[431,35657,35658],{"class":441}," liquid_needed[node ",[431,35660,853],{"class":654},[431,35662,1032],{"class":437},[431,35664,4049],{"class":441},[431,35666,10686],{"class":654},[431,35668,981],{"class":654},[431,35670,1192],{"class":437},[431,35672,8102],{"class":441},[431,35674,35675,35677,35680,35682,35684,35686,35688],{"class":433,"line":578},[431,35676,10453],{"class":654},[431,35678,35679],{"class":441}," liquid ",[431,35681,9105],{"class":654},[431,35683,35658],{"class":441},[431,35685,853],{"class":654},[431,35687,1032],{"class":437},[431,35689,3568],{"class":441},[431,35691,35692,35695,35697],{"class":433,"line":584},[431,35693,35694],{"class":441},"    e ",[431,35696,1189],{"class":654},[431,35698,35699],{"class":441}," nodes.get(node)\n",[431,35701,35702,35704],{"class":433,"line":1244},[431,35703,10438],{"class":654},[431,35705,35706],{"class":441}," e:\n",[431,35708,35709,35711,35714,35716,35718,35720,35722,35725,35727],{"class":433,"line":1985},[431,35710,33447],{"class":654},[431,35712,35713],{"class":441}," p ",[431,35715,14421],{"class":654},[431,35717,14424],{"class":437},[431,35719,442],{"class":441},[431,35721,5205],{"class":437},[431,35723,35724],{"class":441},"(e[",[431,35726,3302],{"class":437},[431,35728,35729],{"class":441},"])):\n",[431,35731,35732,35735,35737,35739,35741,35744,35746,35749,35751,35753],{"class":433,"line":2041},[431,35733,35734],{"class":441},"            down_pipe ",[431,35736,1189],{"class":654},[431,35738,35679],{"class":441},[431,35740,1357],{"class":654},[431,35742,35743],{"class":441}," e[",[431,35745,1192],{"class":437},[431,35747,35748],{"class":441},"][p] ",[431,35750,14218],{"class":654},[431,35752,9108],{"class":437},[431,35754,35755],{"class":455},"  # e[1] это percentage — процентное значение для трубки\n",[431,35757,35758,35760,35762,35764,35767],{"class":433,"line":4018},[431,35759,33458],{"class":654},[431,35761,35743],{"class":441},[431,35763,651],{"class":437},[431,35765,35766],{"class":441},"][p]: ",[431,35768,35769],{"class":455},"# если \"супер трубка\"\n",[431,35771,35772,35775,35778,35781],{"class":433,"line":4030},[431,35773,35774],{"class":441},"                down_pipe ",[431,35776,35777],{"class":654},"*=",[431,35779,35780],{"class":441}," down_pipe  ",[431,35782,5652],{"class":455},[431,35784,35785,35787,35789,35792,35794,35797],{"class":433,"line":4419},[431,35786,33458],{"class":654},[431,35788,9498],{"class":654},[431,35790,35791],{"class":441}," can_feed(e[",[431,35793,3302],{"class":437},[431,35795,35796],{"class":441},"][p], down_pipe, nodes, liquid_needed): ",[431,35798,5340],{"class":455},[431,35800,35801,35804],{"class":433,"line":4436},[431,35802,35803],{"class":654},"                return",[431,35805,14187],{"class":437},[431,35807,35808,35810],{"class":433,"line":4446},[431,35809,6599],{"class":654},[431,35811,10188],{"class":437},[415,35813,35814,35815,35818,35819,35821,35822,35824,35825,35827,35828,35830,35831,35833,35834,35836,35837,35840,35841,35844,35845,35847,35848,35850,35851,35853,35854,35856,35857,35860,35861,35863,35864,35866,35867,35869,35870,35872,35873,35876,35877,35879,35880,35882,35883,9379,35886,35889,35890,35892],{},"Функция отслеживает, является ли ",[428,35816,35817],{},"liquid"," допустимым решением для дерева.\nПока функция возвращает ",[428,35820,4463],{},", решение считается допустимым. По умолчанию функция вернёт ",[428,35823,4463],{}," а в процессе работы может вернуть ",[428,35826,4431],{},",\nесли количество жидкости, прошедшей через одну из трубок, окажется недостаточным. Если к концу работы функции по-прежнему будет\n",[428,35829,4463],{},", то все трубки провели достаточное количество жидкости и мы заключаем, что решение ",[428,35832,35817],{}," допустимо.\nКоличество жидкости, поступающее в каждую трубку, определяется с помощью ее процентного значения.\nЗатем, если трубка имеет супер режим, это значение возводится в квадрат... но стоп!\nВ условии задачи сказано, что Боби должен решить, нужно ли использовать супер режим каждой супер трубки.\nОднако здесь мы без вариантов возводим количество жидкости в квадрат, всегда используя супер режим.\nПричина в том, что возведение в квадрат увеличивает значения: сравните 2 и 2*2 = 4, 3 и 3*3 = 9, и т. д.\nПоскольку нам нужно знать, является ли данное количество жидкости допустимым, и штрафа за использование супер трубки нет,\nможно предполагать максимальный объем жидкости.\nВозможно, есть вариант обойтись и без использования супер режима какой-то супер трубки, но никто не просит нас экономить.\nНе беспокойтесь о том, что возведение в квадрат уменьшает положительные числа меньше единицы, например 0,5 (0,5 * 0,5 = 0,25).\nДействительно, в подобных случаях активировать супер трубку мы бы не стали. Поскольку каждому муравью нужно не менее 1 литра жидкости,\nзначит, если в одном из узлов мы получим 0,5 литра, то независимо от наших действий муравьи в поддереве этого узла останутся голодными и мы вернем ",[428,35835,4431],{},".\nТеперь посмотрим, насколько полезна функция ",[428,35838,35839],{},"can_feed",", и для этого продолжим работу.\nРанее выше мы показали, что 10 литров недостаточно для рассматривавшегося примера.\nДобавьте вызов can_feed для проверки объема 10 литров(после получения тестовых данных): ",[428,35842,35843],{},"print(can_feed(1, 10, nodes, liquid_needed)",".\nВ результате должен вернуться ",[428,35846,4431],{},", означающий, что ",[428,35849,3565],{}," литров мало. В том же разделе мы продемонстрировали, что 20 литров будет достаточно.\nИзмените вызов ",[428,35852,35839],{}," для проверки ",[428,35855,19588],{}," литров: ",[428,35858,35859],{},"print(can_feed(1, 20, nodes, liquid_needed)",".\nВ результате должна вернуться ",[428,35862,4463],{},", означающая, что ",[428,35865,19588],{}," литров достаточно.\nТеперь нам известно, что 10 недостаточно, а 20 хватает. Давайте сужать этот диапазон далее.\nПопробуйте ",[428,35868,22026],{},", на что должен вернуться ",[428,35871,4431],{},". Значит, 15 маловато. Теперь оптимальный ответ больше 15, но не больше 20.\nПопробуйте ",[428,35874,35875],{},"18"," — в этом случае жидкости окажется достаточно. А как насчет ",[428,35878,30836],{},"?\nНет, ",[428,35881,30836],{}," уже мало, как и ",[428,35884,35885],{},"17.5",[428,35887,35888],{},"17.9",", значит, оптимальное решение — ",[428,35891,35875],{},".\nЭтих результатов узконаправленного поиска достаточно, теперь можно их систематизировать.",[34980,35894,35896],{"id":35895},"поиск-решения","ПОИСК РЕШЕНИЯ",[415,35898,35899,35900],{},"Из условия задачи известно, что оптимальное значение не больше 2 миллиардов.\nСледовательно, решение находится в огромном пространстве поиска.\nНаша цель сократить это пространство максимально быстро, не тратя времени на пустые догадки.\nПромахнуться легко. Например, если начать с предположения 10, а оптимальное решение окажется равным двум миллиардам,\nтогда, по сути, это предположение следует считать промахом, исключающим из области поиска только значения от 0 до 10.\nНо 10 окажется отличным вариантом, если ответ будет равен, например, 8, потому что тогда первый же шаг сразу сократит диапазон до 0 — 10,\nи на поиск решения много времени не уйдет. Совершение таких выстрелов в небо себя не оправдывает,\nпоскольку редкое везение не перекроет наиболее вероятный случай, когда такая догадка практически бесполезна.\nИменно поэтому, когда вас попросят отгадать число между 0 и 1000, вы вряд ли начнете с 10.\nКонечно же, если на такое предположение вам скажут «меньше», то вы очень обрадуетесь, но если ответом будет «больше»,\nкак скорее всего и получится, то можно считать, что первую попытку вы потратили зря.\nЧтобы гарантировать получение с каждой догадкой максимальной информации, мы всегда будем загадывать середину диапазона.\nДля этого нужно будет вести две переменные, low и high, которые будут хранить нижнюю и верхнюю границы текущего диапазона соответственно.\nЗатем мы будем вычислять середину этого диапазона, mid, проверять допустимость mid, по результату обновляя low и high.\n",[800,35901,35902,35903,2699],{},"Используем алгоритм ",[1355,35904,35905],{},"двоичного поиска",[422,35907,35909],{"className":424,"code":35908,"language":396,"meta":426,"style":426},"def solve(nodes, liquid_needed):\n    low = 0\n    high = 2000000000\n    while high - low > 0.00001: # 1\n        mid = (low + high) \u002F 2 # 2\n        if can_feed(1, mid, nodes, liquid_needed): # 3\n            high = mid\n        else:\n            low = mid\n    print(high) # 4\n",[428,35910,35911,35921,35930,35939,35959,35979,35993,36002,36008,36017],{"__ignoreMap":426},[431,35912,35913,35915,35918],{"class":433,"line":434},[431,35914,6330],{"class":654},[431,35916,35917],{"class":6333}," solve",[431,35919,35920],{"class":441},"(nodes, liquid_needed):\n",[431,35922,35923,35926,35928],{"class":433,"line":452},[431,35924,35925],{"class":441},"    low ",[431,35927,1189],{"class":654},[431,35929,3459],{"class":437},[431,35931,35932,35934,35936],{"class":433,"line":578},[431,35933,34547],{"class":441},[431,35935,1189],{"class":654},[431,35937,35938],{"class":437}," 2000000000\n",[431,35940,35941,35943,35946,35948,35950,35952,35955,35957],{"class":433,"line":584},[431,35942,12537],{"class":654},[431,35944,35945],{"class":441}," high ",[431,35947,853],{"class":654},[431,35949,34619],{"class":441},[431,35951,8883],{"class":654},[431,35953,35954],{"class":437}," 0.00001",[431,35956,26306],{"class":441},[431,35958,13119],{"class":455},[431,35960,35961,35964,35966,35968,35970,35972,35974,35976],{"class":433,"line":1244},[431,35962,35963],{"class":441},"        mid ",[431,35965,1189],{"class":654},[431,35967,34504],{"class":441},[431,35969,802],{"class":654},[431,35971,34509],{"class":441},[431,35973,14218],{"class":654},[431,35975,689],{"class":437},[431,35977,35978],{"class":455}," # 2\n",[431,35980,35981,35983,35986,35988,35991],{"class":433,"line":1985},[431,35982,11471],{"class":654},[431,35984,35985],{"class":441}," can_feed(",[431,35987,1192],{"class":437},[431,35989,35990],{"class":441},", mid, nodes, liquid_needed): ",[431,35992,5340],{"class":455},[431,35994,35995,35998,36000],{"class":433,"line":2041},[431,35996,35997],{"class":441},"            high ",[431,35999,1189],{"class":654},[431,36001,34677],{"class":441},[431,36003,36004,36006],{"class":433,"line":4018},[431,36005,24030],{"class":654},[431,36007,8102],{"class":441},[431,36009,36010,36013,36015],{"class":433,"line":4030},[431,36011,36012],{"class":441},"            low ",[431,36014,1189],{"class":654},[431,36016,34677],{"class":441},[431,36018,36019,36021,36024],{"class":433,"line":4419},[431,36020,6357],{"class":437},[431,36022,36023],{"class":441},"(high) ",[431,36025,7774],{"class":455},[415,36027,36028,36029,36032,36033,3228,36036,36039,36040,36042,36043,36045,36046,36048,36049,36051,36052,36054,36055,36058],{},"После определения функций и получения данных запустим решение: ",[428,36030,36031],{},"solve(nodes, liquid_needed)",".\nВажно инициализировать ",[428,36034,36035],{},"low",[428,36037,36038],{},"high"," так, чтобы в их диапазоне гарантированно содержалось оптимальное решение.\nЗначение ",[428,36041,36035],{}," будет постоянно меньшим или равным оптимальному решению, а ",[428,36044,36038],{}," — большим или равным оптимальному решению.\nНачнем со значения ",[428,36047,36035],{},", равного ",[428,36050,3302],{},". Поскольку каждому муравью требуется не менее 1 литра, 0 литров будет определенно меньше или равно оптимальному решению.\nДля ",[428,36053,36038],{}," же стартовое значение установим как ",[428,36056,36057],{},"2000000000",", поскольку условие задачи гарантирует, что значение оптимального решения не может превышать этого числа.",[1588,36060,36061,36072,36083,36114],{},[700,36062,36063,36064,3228,36066,36068,36069,2699],{},"Условие цикла while ведет к минимизации диапазона между ",[428,36065,36035],{},[428,36067,36038],{},".\nНам нужна точность выше четырех цифр после запятой, отсюда появляются четыре 0 после десятичной точки в ",[428,36070,36071],{},"0.00001",[700,36073,36074,36075,3228,36077,36079,36080,2699],{},"Первым делом в цикле вычисляется середина диапазона. Для этого мы берем среднее от ",[428,36076,36035],{},[428,36078,36038],{},", сохраняя результат в ",[428,36081,36082],{},"mid",[700,36084,36085,36086,36088,36089,36091,36092,36094,36095,36097,36098,36101,36102,36104,36105,36107,36108,36111,36112,2699],{},"Теперь пора проверить ",[428,36087,36082],{}," литров на допустимость с помощью ",[428,36090,35839],{},". Если ",[428,36093,36082],{}," окажется допустимым числом, значит, угадывание значений выше ",[428,36096,36082],{}," бесполезно.\nСледовательно, мы устанавливаем ",[428,36099,36100],{},"high = mid",", уменьшая максимум диапазона до ",[428,36103,36082],{},". Если же ",[428,36106,36082],{}," окажется недопустимым вариантом, то бесполезно угадывать меньшие значения.\nСледовательно, мы устанавливаем ",[428,36109,36110],{},"low = mid",", повышая минимум диапазона до ",[428,36113,36082],{},[700,36115,36116,36117,3228,36119,36121,36122,36124,36125,36127],{},"По завершении цикла ",[428,36118,36035],{},[428,36120,36038],{}," окажутся очень близки. Я вывожу в конце ",[428,36123,36038],{},", но вывод ",[428,36126,36035],{}," также вполне допустим.",[415,36129,36130],{},"Такая техника, в которой мы последовательно сокращаем диапазон поиска в два раза, пока он не станет очень мал, называется двоичным поиском.\nЭто удивительно мощный алгоритм, что будет доказано в оставшихся разделах этой главы.\nОн также очень быстр и способен с легкостью обрабатывать диапазоны из миллиардов и триллионов значений.",[415,36132,36133],{},"«Кормление муравьев» относится к типу задач, для решения которых нет метода лучше двоичного поиска.\nДля них характерны две особенности:",[697,36135,36136,36142,36148],{},[700,36137,36138,36141],{},[800,36139,36140],{},"Особенность 1: сложность выбора метода решения, но простота проверки допустимости ответа.","\nДля некоторых задач сложно определить алгоритм поиска оптимального решения.\nК счастью, во многих таких случаях значительно проще определять, является ли предлагаемое решение допустимым.\nТакова и была ситуация в задаче про муравьев: мы не знали, как найти оптимальное решение, но при этом видели, как определять,\nявляется ли некоторый объем жидкости допустимым.",[700,36143,36144,36147],{},[800,36145,36146],{},"Особенность 2: четкое разделение решений на допустимые и недопустимые.","\nНам нужно, чтобы задача позволяла провести четкую черту, разделяющую допустимые и недопустимые решения.\nВ задаче про муравьев недостаточные объемы жидкости были недопустимы, а избыточные — допустимы.\nТо есть когда мы рассматривали значения объема, то могли установить для них диапазоны недопустимых и допустимых значений.\nПосле нахождения первого допустимого значения мы определяли диапазон, не содержащий недопустимых значений.\nПредположим, что выполняем проверку для 20 литров и выясняем, что этого мало.\nСледовательно, мы все еще не достигли допустимой части пространства поиска и нужно пробовать большие значения.\nЕсли же 20 литров оказывается достаточным, значит, мы находимся в допустимой части пространства и нужно пробовать меньшие значения.",[700,36149,36150],{},"Если задача не отвечает второму требованию, то двоичный поиск будет бесполезен.\nНапример, есть задачи, где меньшие значения являются недопустимыми, средние допустимыми, а большие снова недопустимыми.\nОднако вполне нормально, если область поиска будет переходить от допустимых значений к недопустимым, а не наоборот.",[34980,36152,36154],{"id":36153},"время-выполнения-алгоритма","ВРЕМЯ ВЫПОЛНЕНИЯ АЛГОРИТМА",[415,36156,36157],{},"Пора окончательно разобраться, как мы использовали в задаче двоичный поиск: мы выполняли больше чем lb 2 000 000 000 итераций алгоритма, потому что\nне останавливались, когда ширина диапазона достигала 1. Остановка происходила только при достижении точности выше четырех знаков после запятой.\nПри добавлении пяти нулей количество совершаемых итераций равно lb 200 000 000 000 000, который округляется до 48.\nВсего 48 итераций необходимо для получения решения с точностью выше четырех цифр после запятой из огромнейшего диапазона в триллионы значений!",[415,36159,36160,36161,36164,36165,36167,36168,36171],{},"В дереве из ",[428,36162,36163],{},"N"," узлов функция ",[428,36166,35839],{}," в задаче «Кормление муравьев» выполняется в линейном времени, то есть продолжительность ее выполнения пропорциональна n.\nМы вызываем эту функцию lb(m × 104) раз, где m — ширина диапазона (два миллиарда в тестовых примерах).\nЭто пропорционально lbm работы. Тогда в общей сложности выполняется n работы lbm раз.\nТо есть время можно записать как ",[800,36169,36170],{},"O(nlbm)",". Оно не совсем линейно из-за множителя lbm, но двоичный поиск все равно очень быстр.",[415,36173,36174],{},[1355,36175,36176],{},[800,36177,36178],{},"ВЫВОД",[415,36180,36181],{},"В алгоритмах двоичного поиска мне больше всего нравится то, что для определения допустимости значения зачастую нужно использовать другой метод.\nТо есть снаружи у нас двоичный поиск, а внутри что-то еще, проверяющее каждое значение на допустимость.\nПричем это «что-то еще» может быть чем угодно.\nВ «Кормлении муравьев» это был поиск по дереву, в следующей задаче это может быть жадный алгоритм, а в третьей задаче главы и вовсе динамическое программирование.\nВ некоторых задачах для определения допустимости решения задействуется алгоритм на графах.",[415,36183,36184],{},"Таким образом, в задачах надо применять материал по другим алгоритмам.\nДля определения допустимости решений нередко требуется проявить изрядную креативность (к счастью, не столь изрядную, как для нахождения оптимальных решений).\nВерно, что двоичный поиск можно использовать для нахождения подходящего индекса массива в логарифмическом времени, но задачу про муравьев мы решали также с помощью двоичного поиска, а никакого массива задано не было.\nНе стоит ограничивать использование двоичного поиска только случаями, когда анализу подлежит массив. Этот алгоритм намного более гибок.",[458,36186,36188],{"id":36187},"задача-2-прыжки-вдоль-реки","Задача 2. Прыжки вдоль реки",[415,36190,36191],{},"Рассмотрим задачу, в которой для определения допустимости решений потребуется жадный алгоритм.",[12129,36193,35333],{"id":36194},"условие-1",[415,36196,36197],{},"Дана река длиной L, вдоль которой лежат камни. Один камень лежит в точке 0 (начало реки), другой в точке L (конец реки),\nа между ними находится еще n камней.\nНапример, вдоль реки длиной 12 камни могут располагаться в следующих местах: 0, 5, 8 и 12.\nКорова начинает с первого камня (локация 0), перепрыгивает оттуда на второй камень,\nпотом со второго на третий и так далее, пока не достигает последнего камня в точке L.\nМинимальная длина прыжка равна минимальному расстоянию между любыми двумя соседними камнями.\nВ примере выше минимальное расстояние будет 3 (между точками 5 и 8).\nФермеру Джону наскучили короткие прыжки коровы, и он хочет максимально\nувеличить их длину. Камни в точках 0 или L он убрать не может, но может удалить m других камней.\nПредположим, что в приведенном выше примере Джон может убрать один камень.\nВ этом случае перед ним стоит выбор — убрать камень из точки 5 или 6.\nЕсли он уберет его из точки 5, то минимальное расстояние прыжка станет 4 (из 8 в 12).\nОднако если он уберет камень из точки 8, то получит минимальный прыжок большей длины (из 0 в 5).\nЗадача — максимизация минимальной длины прыжка, которой может добиться фермер, убрав m камней.",[12129,36199,35361],{"id":36200},"входные-данные-1",[415,36202,36203],{},"Входные данные состоят из одного тестового примера, содержащего следующие строки:\nТри целых числа: L — протяженность реки; n — количество камней, не включая начальный и конечный камни;\nm — количество камней, которые Джон может убрать.\nЗначение L может находиться в диапазоне от 1 до 1 000 000 000, n — от 0 до 50 000, а m — между 0 и n.\nn строк, каждая из которых указывает координату камня. При этом два камня в одном месте оказаться не могут.",[12129,36205,35406],{"id":36206},"выходные-данные-1",[415,36208,36209],{},"Требуется вывести максимально достижимое минимальное расстояние прыжка.\nДля примера выше выводом будет 5.\nВремя на решение тестового примера — две секунды.",[12129,36211,35413],{"id":36212},"решение-1",[415,36214,36215],{},[1355,36216,36217],{},[800,36218,36219],{},"ЖАДНЫЙ АЛГОРИТМ",[415,36221,36222],{},"Сформулировать жадный алгоритм несложно, но не всегда легко определить правильное условие.\nЕсли он и подходят, то обычно по уникальным, характерным для конкретной задачи причинам. Эта задача одна из таких.\nОчень часто, чтобы отличить реально подходящий жадный алгоритм от кажущегося подходящим, требуется тщательное доказательство корректности.\nПример, алгоритм Дейкстры. Как правило, специалисты относят этот алгоритм именно к жадным.\nКогда он объявляет о нахождении кратчайшего пути к узлу, то уже не возвращается к этому решению.\nАлгоритм окончательно утверждает найденное значение, и дальнейшее исследование пространства поиска не влияет на этот результат.",[415,36224,36225],{},"Вот жадное правило для этой задачи: найти два камня, расположенных ближе всех друг к другу, убрать тот,\nчто ближе к другому своему соседу, и повторить процесс.\nВернемся к примеру из описания задачи:",[422,36227,36229],{"className":1436,"code":36228,"language":1438,"meta":426,"style":426},"12 2 1\n5\n8\n",[428,36230,36231,36236,36241],{"__ignoreMap":426},[431,36232,36233],{"class":433,"line":434},[431,36234,36235],{},"12 2 1\n",[431,36237,36238],{"class":433,"line":452},[431,36239,36240],{},"5\n",[431,36242,36243],{"class":433,"line":578},[431,36244,36245],{},"8\n",[415,36247,36248],{},"Камни расположены в точках 0, 5, 8 и 12. Убрать можно один.\nСамые близкие друг к другу камни расположены в 5 и 8, значит, жадное правило приведет к удалению одного из них.\nКамень в точке 8 находится от своего соседа справа на расстоянии 4.\nКамень в точке 5 находится от своего соседа слева на расстоянии 5.\nСогласно жадному правилу, удаляется камень из точки 8.\nВ этом примере правило работает корректно.",[415,36250,36251],{},"Но приведём контрпример:",[422,36253,36255],{"className":1436,"code":36254,"language":1438,"meta":426,"style":426},"12 4 2\n2\n4\n5\n8\n",[428,36256,36257,36262,36266,36271,36275],{"__ignoreMap":426},[431,36258,36259],{"class":433,"line":434},[431,36260,36261],{},"12 4 2\n",[431,36263,36264],{"class":433,"line":452},[431,36265,16757],{},[431,36267,36268],{"class":433,"line":578},[431,36269,36270],{},"4\n",[431,36272,36273],{"class":433,"line":584},[431,36274,36240],{},[431,36276,36277],{"class":433,"line":1244},[431,36278,36245],{},[415,36280,36281],{},"Камни располагаются в точках 0, 2, 4, 5, 8 и 12. Допускается убрать два.\nЖадный алгоритм определяет ближайшими камни в точках 4 и 5.\nИз них он удаляет камень 4, поскольку расстояние между 4 и 2 меньше, чем между 5 и 8. Остаются 0, 2, 5, 8 и 12.\nТеперь жадное правило определяет ближайшими камни в точках 0 и 2.\nУдалять стартовый камень нельзя, значит, удаляется камень из 2. Остаются 0, 5, 8 и 12. Минимальная длина прыжка здесь — 3.\nОднако в данном случае алгоритм с задачей не справился, потому что можно добиться, чтобы это расстояние равнялось 4.\nДля получения такого значения нужно удалить камни в точках 2 и 5. Так мы получим 0, 4, 8 и 12.",[415,36283,36284],{},"Что же пошло не так? Удалив камень в локации 4 на первом ходе, жадный алгоритм создал два прыжка с длиной три.\nНа втором ходе он может убрать только один из этих двух,\nчто никак не позволит получить итоговое минимальное расстояние больше трех.",[34980,36286,36288],{"id":36287},"проверка-допустимости","ПРОВЕРКА ДОПУСТИМОСТИ",[415,36290,36291],{},"Всегда есть два ориентира используя двоичный поиск: большая простота проверки допустимости, чем определения оптимального решения;\nчеткий переход в области поиска между допустимыми и недопустимыми решениями.\nВместо поиска оптимального решения мы попробуем ответить на вопрос: можно ли добиться длины прыжка не менее d?\nЕсли нам удастся получить ответ, то можно будет использовать двоичный поиск для нахождения наибольшего допустимого значения d.\nТестовый пример на котором остановились:",[422,36293,36294],{"className":1436,"code":36254,"language":1438,"meta":426,"style":426},[428,36295,36296,36300,36304,36308,36312],{"__ignoreMap":426},[431,36297,36298],{"class":433,"line":434},[431,36299,36261],{},[431,36301,36302],{"class":433,"line":452},[431,36303,16757],{},[431,36305,36306],{"class":433,"line":578},[431,36307,36270],{},[431,36309,36310],{"class":433,"line":584},[431,36311,36240],{},[431,36313,36314],{"class":433,"line":1244},[431,36315,36245],{},[415,36317,36318],{},"Камни расположены в точках 0, 2, 4, 5, 8 и 12. Убрать можно два. Вопрос: минимум сколько нужно убрать камней, чтобы длина прыжка получилась не менее 6?\nРазберем пример слева направо и проверим.",[415,36320,36321],{},"Камень в точке 0 трогать нельзя — так гласит условие задачи. Тогда, очевидно, у нас не остается выбора в отношении камня в точке 2: его необходимо убрать.\nЕсли этого не сделать, то минимальное расстояние между двумя камнями будет меньше 6.\nИтак, после этого остались камни в точках 0, 4, 5, 8 и 12. Теперь рассмотрим камень в точке 4 — нужно ли его оставить или убрать?\nВ нашем случае его необходимо также убрать.\nЕсли этого не сделать, то минимальное расстояние между камнями составит 4, что меньше нужных нам 6.\nПосле его удаления остаются камни в точках 0, 5, 8 и 12.\nКамень в точке 5 тоже надо убрать, потому что расстояние от него до 0 равно всего лишь 5.\nЭто третье удаление, после которого остаются камни в точках 0, 8 и 12.\nТеперь нужно удалить камень из точки 8. Он достаточно удален от 0, но недостаточно от 12.\nИтого четыре удаления, и в конечном итоге остаются камни в точках 0 и 12.",[415,36323,36324],{},"Итак, чтобы получить минимальное расстояние прыжка не меньше 6, требуется четыре удаления, но разрешено удалить всего два камня.\nВ таком случае 6 не является допустимым решением. Оно слишком велико. Будет ли допустимым решением 3?\nТо есть можно ли добиться минимального расстояния прыжка 3, удалив всего два камня?\nКамень в точке 0 остается, а камень в точке 2 нужно убрать.\nЭто первое удаление, оставляющее камни в позициях 0, 4, 5, 8 и 12. Камень в точке 4 может остаться: он удален от 0 более чем на 3.\nА вот камень в точке 5 нужно убрать, потому что он слишком близок к камню в точке 4.\nЭто второе удаление, после которого остаются заняты точки 0, 4, 8 и 12.\nКамень в точке 8 не мешает: он достаточно удален от камней в 4 и 12.\nЗначит, здесь мы закончили: для получения минимального расстояния прыжка 3 потребовалось два удаления.\nТаким образом, 3 является допустимым решением.",[415,36326,36327],{},"Здесь для проверки допустимости решения мы возвращаемся к жадному алгоритму.\nПравило получается следующее: поочередно рассматривать каждый камень и удалять его, если он оказывается слишком близок к предыдущему оставленному камню.\nДля предпоследнего камня надо выполнить проверку также относительно его правого соседа.\nЗатем подсчитывается число удаленных камней.\nЭтот результат сообщит нам, является ли предложенное минимальное расстояние прыжка допустимым с учетом количества камней,\nкоторое разрешено удалить (уточню, что это формулировка жадного алгоритма для проверки допустимости заданного расстояния прыжка,\nа не поиска оптимального решения). Реализация этого алгоритма представлена ниже:",[422,36329,36331],{"className":424,"code":36330,"language":396,"meta":426,"style":426},"def can_make_min_distance(distance, rocks, num_rocks, num_remove, length):\n  removed = prev_rock_location = 0\n  if length \u003C distance:\n    return False\n  for i in range(num_rocks):\n    cur_rock_location = rocks[i]\n    if cur_rock_location - prev_rock_location \u003C distance:\n      removed += 1\n    else:\n      prev_rock_location = cur_rock_location\n  if length - prev_rock_location \u003C distance:\n    removed += 1\n  return removed \u003C= num_remove\n",[428,36332,36333,36343,36357,36368,36374,36387,36397,36412,36421,36427,36437,36451,36460],{"__ignoreMap":426},[431,36334,36335,36337,36340],{"class":433,"line":434},[431,36336,6330],{"class":654},[431,36338,36339],{"class":6333}," can_make_min_distance",[431,36341,36342],{"class":441},"(distance, rocks, num_rocks, num_remove, length):\n",[431,36344,36345,36348,36350,36353,36355],{"class":433,"line":452},[431,36346,36347],{"class":441},"  removed ",[431,36349,1189],{"class":654},[431,36351,36352],{"class":441}," prev_rock_location ",[431,36354,1189],{"class":654},[431,36356,3459],{"class":437},[431,36358,36359,36361,36363,36365],{"class":433,"line":578},[431,36360,20480],{"class":654},[431,36362,8880],{"class":441},[431,36364,8521],{"class":654},[431,36366,36367],{"class":441}," distance:\n",[431,36369,36370,36372],{"class":433,"line":584},[431,36371,6599],{"class":654},[431,36373,14187],{"class":437},[431,36375,36376,36378,36380,36382,36384],{"class":433,"line":1244},[431,36377,20523],{"class":654},[431,36379,12664],{"class":441},[431,36381,14421],{"class":654},[431,36383,14424],{"class":437},[431,36385,36386],{"class":441},"(num_rocks):\n",[431,36388,36389,36392,36394],{"class":433,"line":1985},[431,36390,36391],{"class":441},"    cur_rock_location ",[431,36393,1189],{"class":654},[431,36395,36396],{"class":441}," rocks[i]\n",[431,36398,36399,36401,36404,36406,36408,36410],{"class":433,"line":2041},[431,36400,10438],{"class":654},[431,36402,36403],{"class":441}," cur_rock_location ",[431,36405,853],{"class":654},[431,36407,36352],{"class":441},[431,36409,8521],{"class":654},[431,36411,36367],{"class":441},[431,36413,36414,36417,36419],{"class":433,"line":4018},[431,36415,36416],{"class":441},"      removed ",[431,36418,12563],{"class":654},[431,36420,3916],{"class":437},[431,36422,36423,36425],{"class":433,"line":4030},[431,36424,10575],{"class":654},[431,36426,8102],{"class":441},[431,36428,36429,36432,36434],{"class":433,"line":4419},[431,36430,36431],{"class":441},"      prev_rock_location ",[431,36433,1189],{"class":654},[431,36435,36436],{"class":441}," cur_rock_location\n",[431,36438,36439,36441,36443,36445,36447,36449],{"class":433,"line":4436},[431,36440,20480],{"class":654},[431,36442,8880],{"class":441},[431,36444,853],{"class":654},[431,36446,36352],{"class":441},[431,36448,8521],{"class":654},[431,36450,36367],{"class":441},[431,36452,36453,36456,36458],{"class":433,"line":4446},[431,36454,36455],{"class":441},"    removed ",[431,36457,12563],{"class":654},[431,36459,3916],{"class":437},[431,36461,36462,36464,36467,36469],{"class":433,"line":4451},[431,36463,20132],{"class":654},[431,36465,36466],{"class":441}," removed ",[431,36468,12667],{"class":654},[431,36470,36471],{"class":441}," num_remove\n",[415,36473,36474],{},"У этой функции пять параметров:",[697,36476,36477,36480,36483,36486,36489],{},[700,36478,36479],{},"distance — минимальное расстояние прыжка, которое проверяется;",[700,36481,36482],{},"rocks — массив, содержащий координату каждого камня, кроме расположенных в начале и конце реки;",[700,36484,36485],{},"num_rocks — количество камней в массиве rocks;",[700,36487,36488],{},"num_remove — количество камней, которые можно убрать;",[700,36490,36491],{},"length — длина реки.",[415,36493,36494],{},"Эта функция возвращает True, если distance оказывается допустимым решением, и False, если нет.\nПеременная prev_rock_location отслеживает координату последнего нетронутого камня.\nВнутри цикла for переменная cur_rock_location содержит координату камня, рассматриваемого в данный момент.\nДалее идет проверка, определяющая, нужно ли оставить или удалить текущий камень.\nЕсли он находится слишком близко к предыдущему, то мы его удаляем и увеличиваем количество удалений на один.\nВ противном случае текущий камень остается, и соответствующим образом обновляется prev_rock_location.\nПо завершении цикла мы получаем количество камней, которое нужно удалить. Хотя не совсем.\nЕщё нужно проверить, не находится ли предпоследний камень слишком близко к концу реки.\nЕсли да, то он удаляется (не беспокойтесь о возможном удалении камня в точке 0.\nЕсли действительно удалить все камни, то prev_rock_location окажется равным 0.\nОднако length – 0 \u003C distance не может быть верно.\nВ противном случае сработала бы инструкция if еще в начале функции).\nИтак, условие расстояния прыжка между камнями соблюдено, причем мы удалили заданное число камней.",[415,36496,36497],{},"Прежде чем продолжать, давайте выполним проверку на допустимость. Ниже представлен тест для примера:",[422,36499,36501],{"className":424,"code":36500,"language":396,"meta":426,"style":426},"rocks = [2, 4, 5, 8];\nprint(can_make_min_distance(6, rocks, 4, 2, 12))\n",[428,36502,36503,36531],{"__ignoreMap":426},[431,36504,36505,36508,36510,36512,36514,36516,36518,36520,36522,36524,36526,36528],{"class":433,"line":434},[431,36506,36507],{"class":441},"rocks ",[431,36509,1189],{"class":654},[431,36511,17401],{"class":441},[431,36513,651],{"class":437},[431,36515,4846],{"class":441},[431,36517,762],{"class":437},[431,36519,4846],{"class":441},[431,36521,856],{"class":437},[431,36523,4846],{"class":441},[431,36525,1021],{"class":437},[431,36527,5262],{"class":441},[431,36529,36530],{"class":25220},";\n",[431,36532,36533,36535,36538,36540,36543,36545,36547,36549,36551,36554],{"class":433,"line":452},[431,36534,438],{"class":437},[431,36536,36537],{"class":441},"(can_make_min_distance(",[431,36539,742],{"class":437},[431,36541,36542],{"class":441},", rocks, ",[431,36544,762],{"class":437},[431,36546,4846],{"class":441},[431,36548,651],{"class":437},[431,36550,4846],{"class":441},[431,36552,36553],{"class":437},"12",[431,36555,6157],{"class":441},[415,36557,36558],{},"Можно ли достичь минимальной длины прыжка в шесть единиц, удалив два камня?\nОтвет «нет», значит, в выводе должен отобразиться False(ложно).\nИзмените первый параметр с 6 на 3, и теперь вопрос ставится о возможности получения минимальной длины в три единицы.\nЗапустите программу, и на этот раз в выводе отобразится True (верно).\nПревосходно: теперь у нас есть способ проверки допустимости.\nВремя задействовать двоичный поиск для нахождения оптимального решения.",[34980,36560,35896],{"id":36561},"поиск-решения-1",[415,36563,36564],{},"Для использования двоичного поиска мы адаптируем код из задачи 1 в «Кормлении муравьев» требовалось достичь точности выше четырех знаков после запятой.\nЗдесь же нам нужно оптимизировать количество камней, выражаемое целочисленным значением.\nТак что вычисления будут останавливаться при целых значениях high и low.",[422,36566,36568],{"className":424,"code":36567,"language":396,"meta":426,"style":426},"def solve(rocks, num_rocks, num_remove, length):\n  low = 0\n  high = length + 1\n  while high - low > 1:\n    mid = (low + high) \u002F\u002F 2\n    if can_make_min_distance(mid, rocks, num_rocks, num_remove, length):\n      low = mid\n    else:\n      high = mid\n  print(low)\n",[428,36569,36570,36579,36587,36599,36615,36631,36638,36646,36652,36660],{"__ignoreMap":426},[431,36571,36572,36574,36576],{"class":433,"line":434},[431,36573,6330],{"class":654},[431,36575,35917],{"class":6333},[431,36577,36578],{"class":441},"(rocks, num_rocks, num_remove, length):\n",[431,36580,36581,36583,36585],{"class":433,"line":452},[431,36582,34587],{"class":441},[431,36584,1189],{"class":654},[431,36586,3459],{"class":437},[431,36588,36589,36591,36593,36595,36597],{"class":433,"line":578},[431,36590,34596],{"class":441},[431,36592,1189],{"class":654},[431,36594,8880],{"class":441},[431,36596,802],{"class":654},[431,36598,3916],{"class":437},[431,36600,36601,36603,36605,36607,36609,36611,36613],{"class":433,"line":584},[431,36602,34616],{"class":654},[431,36604,35945],{"class":441},[431,36606,853],{"class":654},[431,36608,34619],{"class":441},[431,36610,8883],{"class":654},[431,36612,1032],{"class":437},[431,36614,8102],{"class":441},[431,36616,36617,36619,36621,36623,36625,36627,36629],{"class":433,"line":1244},[431,36618,34634],{"class":441},[431,36620,1189],{"class":654},[431,36622,34504],{"class":441},[431,36624,802],{"class":654},[431,36626,34509],{"class":441},[431,36628,16854],{"class":654},[431,36630,658],{"class":437},[431,36632,36633,36635],{"class":433,"line":1985},[431,36634,10438],{"class":654},[431,36636,36637],{"class":441}," can_make_min_distance(mid, rocks, num_rocks, num_remove, length):\n",[431,36639,36640,36642,36644],{"class":433,"line":2041},[431,36641,34721],{"class":441},[431,36643,1189],{"class":654},[431,36645,34677],{"class":441},[431,36647,36648,36650],{"class":433,"line":4018},[431,36649,10575],{"class":654},[431,36651,8102],{"class":441},[431,36653,36654,36656,36658],{"class":433,"line":4030},[431,36655,34697],{"class":441},[431,36657,1189],{"class":654},[431,36659,34677],{"class":441},[431,36661,36662,36664],{"class":433,"line":4419},[431,36663,18530],{"class":437},[431,36665,36666],{"class":441},"(low)\n",[415,36668,36669],{},"Минимальное расстояние прыжка low, равное нулю, всегда достижимо и допустимо и high точно недопустимо: нельзя прыгнуть на длину length + 1.\nДалее нужно выяснить, что делать с этими двумя возможностями в цикле.\nВ каждой итерации мы вычисляем среднюю точку диапазона mid и используем вспомогательную функцию для проверки ее допустимости.\nЕсли mid окажется допустимо, то можно установить low = mid. Потому что low и все, что левее, является допустимым.\nЕсли же mid недопустимо, то можно установить high = mid. Потому что high и все правее него значения являются недопустимыми.\nТаким образом, в обоих случаях истинность инварианта сохраняется.\nМы видим, что никакой элемент кода не может повлиять на инвариант, а значит, можно спокойно наконец выводить low по завершении цикла.",[34980,36671,35426],{"id":36672},"считывание-входных-данных-1",[415,36674,36675],{},"Осталось только считать входные данные и вызвать solve:",[422,36677,36679],{"className":424,"code":36678,"language":396,"meta":426,"style":426},"rocks = []\nlength, num_rocks, num_remove = map(int, input().split())\nfor _ in range(num_rocks):\n  rocks.append(int(input()))\nrocks.sort()\nsolve(rocks, num_rocks, num_remove, length)\n",[428,36680,36681,36689,36708,36720,36734,36739],{"__ignoreMap":426},[431,36682,36683,36685,36687],{"class":433,"line":434},[431,36684,36507],{"class":441},[431,36686,1189],{"class":654},[431,36688,21007],{"class":441},[431,36690,36691,36694,36696,36698,36700,36702,36704,36706],{"class":433,"line":452},[431,36692,36693],{"class":441},"length, num_rocks, num_remove ",[431,36695,1189],{"class":654},[431,36697,35492],{"class":437},[431,36699,442],{"class":441},[431,36701,2266],{"class":437},[431,36703,4846],{"class":441},[431,36705,30551],{"class":437},[431,36707,35503],{"class":441},[431,36709,36710,36712,36714,36716,36718],{"class":433,"line":578},[431,36711,14329],{"class":654},[431,36713,14600],{"class":441},[431,36715,14421],{"class":654},[431,36717,14424],{"class":437},[431,36719,36386],{"class":441},[431,36721,36722,36725,36727,36729,36731],{"class":433,"line":584},[431,36723,36724],{"class":441},"  rocks.append(",[431,36726,2266],{"class":437},[431,36728,442],{"class":441},[431,36730,30551],{"class":437},[431,36732,36733],{"class":441},"()))\n",[431,36735,36736],{"class":433,"line":1244},[431,36737,36738],{"class":441},"rocks.sort()\n",[431,36740,36741],{"class":433,"line":1985},[431,36742,36743],{"class":441},"solve(rocks, num_rocks, num_remove, length)\n",[415,36745,36746,36747,36750],{},"Мы анализировали эту задачу, рассматривая координаты камней слева направо, то есть от наименьшего значения к наибольшему.\nОднако во входных данных они могут быть представлены в любом порядке, так как в условии задачи последовательность не гарантируется.\nПро алгоритмы сортировки нужно давать описание отдельно. Здесь же скажем что воспользуемся стандартным методом сортировки списков в Python ",[428,36748,36749],{},"sort()",".\nЗатем вызывается solve со списком упорядоченных камней.",[458,36752,36754],{"id":36753},"задача-3-качество-жизни","Задача 3. Качество жизни",[415,36756,36757],{},"Рассмотрим задачу, в которой для определения допустимости решений потребуется динамическое программирование.\nЭто задача из чемпионата мира по программированию (IOI 2010).",[12129,36759,35333],{"id":36760},"условие-2",[415,36762,36763,36764,36767,36768,36770,36771,36773,36774,36777,36778,36781],{},"Город состоит из прямоугольной сетки кварталов. Каждый квартал обозначается координатами строки и столбца.\nВсего есть ",[1355,36765,36766],{},"r"," строк, пронумерованных от 0 до ",[1355,36769,36766],{}," – 1 сверху вниз, и ",[1355,36772,27268],{}," столбцов, пронумерованных от 0 до ",[1355,36775,36776],{},"с"," – 1 слева направо.\nКаждому квадрату присвоен индивидуальный ранг качества в диапазоне от 1 до ",[1355,36779,36780],{},"rc",".\nК примеру, если дано семь строк и семь столбцов, то рангами кварталов будут числа между 1 и 49.\nПример схемы города дан в таблице ниже.",[9256,36783,36784,36804],{},[9259,36785,36786],{},[9262,36787,36788,36790,36792,36794,36796,36798,36800,36802],{},[9265,36789],{},[9265,36791,3302],{},[9265,36793,1192],{},[9265,36795,651],{},[9265,36797,971],{},[9265,36799,762],{},[9265,36801,856],{},[9265,36803,742],{},[9275,36805,36806,36829,36851,36872,36894,36914,36935],{},[9262,36807,36808,36812,36815,36818,36820,36823,36825,36827],{},[9280,36809,36810],{},[800,36811,3302],{},[9280,36813,36814],{},"48",[9280,36816,36817],{},"16",[9280,36819,22026],{},[9280,36821,36822],{},"45",[9280,36824,19598],{},[9280,36826,35060],{},[9280,36828,1021],{},[9262,36830,36831,36835,36837,36839,36842,36844,36847,36849],{},[9280,36832,36833],{},[800,36834,1192],{},[9280,36836,19588],{},[9280,36838,9573],{},[9280,36840,36841],{},"36",[9280,36843,30841],{},[9280,36845,36846],{},"24",[9280,36848,742],{},[9280,36850,26975],{},[9262,36852,36853,36857,36860,36862,36864,36866,36868,36870],{},[9280,36854,36855],{},[800,36856,651],{},[9280,36858,36859],{},"22",[9280,36861,34365],{},[9280,36863,19593],{},[9280,36865,781],{},[9280,36867,3357],{},[9280,36869,1192],{},[9280,36871,35875],{},[9262,36873,36874,36878,36881,36883,36885,36887,36889,36891],{},[9280,36875,36876],{},[800,36877,971],{},[9280,36879,36880],{},"14",[9280,36882,20633],{},[9280,36884,651],{},[9280,36886,16889],{},[9280,36888,30856],{},[9280,36890,36553],{},[9280,36892,36893],{},"46",[9262,36895,36896,36900,36902,36904,36906,36908,36910,36912],{},[9280,36897,36898],{},[800,36899,762],{},[9280,36901,33887],{},[9280,36903,30861],{},[9280,36905,21518],{},[9280,36907,971],{},[9280,36909,30866],{},[9280,36911,30846],{},[9280,36913,30851],{},[9262,36915,36916,36920,36922,36925,36927,36929,36931,36933],{},[9280,36917,36918],{},[800,36919,856],{},[9280,36921,9731],{},[9280,36923,36924],{},"49",[9280,36926,18740],{},[9280,36928,3565],{},[9280,36930,30836],{},[9280,36932,30876],{},[9280,36934,856],{},[9262,36936,36937,36941,36943,36945,36948,36950,36953,36956],{},[9280,36938,36939],{},[800,36940,742],{},[9280,36942,30871],{},[9280,36944,762],{},[9280,36946,36947],{},"34",[9280,36949,22031],{},[9280,36951,36952],{},"26",[9280,36954,36955],{},"27",[9280,36957,36958],{},"44",[415,36960,36961,36964],{},[1355,36962,36963],{},"Средний ранг качества прямоугольника"," — это ранг качества, относительно которого другие ранги делятся на две равные половины — с меньшими и большими значениями.\nК примеру, рассмотрим прямоугольник размером пять строк на три столбца (5 × 3) в верхнем левом углу таблицы.\nОн содержит 15 рангов качества: 48, 16, 15, 20, 11, 36, 22, 39, 30, 14, 35, 2, 32, 37 и 21.\nСредним рангом здесь выступает 22, потому что семь чисел меньше 22, а другие семь — больше.",[415,36966,36967],{},"Нам будут даны целые числа h и w, указывающие высоту (количество строк) и ширину (количество столбцов) прямоугольников.\nЗадача — определить минимальный средний ранг качества любого прямоугольника с h строк и w столбцов.\nПредположим, что h равна 5, а w равна 3. Тогда для города в таблицы средним рангом качества будет определено значение 13.\nПрямоугольник со средним рангом качества 13 — этот тот, у которого верхний левый угол образует клетка (1, 3), а правый\nнижний угол — (5, 5).",[12129,36969,35361],{"id":36970},"входные-данные-2",[415,36972,36973],{},"Все необходимые данные необходимо подставить в параметры функции. Вот функция:",[422,36975,36977],{"className":424,"code":36976,"language":396,"meta":426,"style":426},"def rectangle(r, c, h, w, q):\n",[428,36978,36979],{"__ignoreMap":426},[431,36980,36981,36983,36986],{"class":433,"line":434},[431,36982,6330],{"class":654},[431,36984,36985],{"class":6333}," rectangle",[431,36987,36988],{"class":441},"(r, c, h, w, q):\n",[415,36990,36991,36992,3228,36994,36996,36997,3228,37000,37003,37004,37006,37007,37009,37010,37012,37013,37015,37016,3228,37018,37020,37021,37024,37025,37028,37029,37032],{},"Здесь ",[428,36993,36766],{},[428,36995,27268],{}," — количество строк и столбцов в схеме соответственно.\nАналогичным образом ",[428,36998,36999],{},"h",[428,37001,37002],{},"w"," — количество строк и столбцов в рассматриваемых прямоугольниках соответственно.\n",[428,37005,36999],{}," будет не больше ",[428,37008,36766],{},", а ",[428,37011,37002],{}," не больше ",[428,37014,27268],{},".\nТакже гарантируется, что ",[428,37017,36999],{},[428,37019,37002],{}," являются нечетными (произведение двух нечетных чисел — нечетное число, поэтому и ",[428,37022,37023],{},"hw",",\nколичество кварталов в рассматриваемом прямоугольнике, будет нечетным.\nСредний ранг качества в этом случае можно определить точно.\nЕсли же у нас будет четное количество рангов качества, например четыре ранга — 2, 6, 4 и 5, то среднее значение придется выбирать между 4 и 5.\nАвтор задачи избавил нас от этого выбора).\nЗаключительный параметр ",[428,37026,37027],{},"q"," указывает ранги качества кварталов.\nК примеру, ",[428,37030,37031],{},"q[2][3]"," определяет значение ранга квартала в строке 2, ряду 3.\nОбратите внимание, что максимальное количество и строк, и столбцов в городе — 3001.",[12129,37034,35406],{"id":37035},"выходные-данные-2",[415,37037,37038],{},"Вернуть минимальный средний ранг качества.\nВремя на решение тестового примера — 10 секунд.",[12129,37040,35413],{"id":37041},"решение-2",[415,37043,37044],{},[1355,37045,37046],{},[800,37047,37048],{},"УПОРЯДОЧИВАНИЕ ПРЯМОУГОЛЬНИКОВ",[415,37050,37051,37052,37054,37055,2699],{},"Во многом мы будем использовать двумерный массив ",[428,37053,37027],{},".\nПредположим, что даны координаты верхнего левого и правого нижнего углов прямоугольника и нужно определить средний ранг качества его кварталов.\nКак это сделать? Прежде чем ответить на этот вопрос создадим саму таблицу с данными(двумерный список) по нашему примеру и вызов функции ",[428,37056,37057],{},"rectangle",[422,37059,37061],{"className":424,"code":37060,"language":396,"meta":426,"style":426},"q = [[48, 16, 15, 45, 40, 28, 8], \n         [20, 11, 36, 19, 24, 6, 33], \n         [22, 39, 30, 7, 9, 1, 18], \n         [14, 35, 2, 13, 31, 12, 46], \n         [32, 37, 21, 3, 41, 23, 29], \n         [42, 49, 38, 10, 17, 47, 5], \n         [43, 4, 34, 25, 26, 27, 44]]\nresult = rectangle(7, 7, 5, 3, q)\nprint(result)\n",[428,37062,37063,37101,37134,37166,37198,37230,37262,37294,37320],{"__ignoreMap":426},[431,37064,37065,37068,37070,37072,37074,37076,37078,37080,37082,37084,37086,37088,37090,37092,37094,37096,37098],{"class":433,"line":434},[431,37066,37067],{"class":441},"q ",[431,37069,1189],{"class":654},[431,37071,22296],{"class":441},[431,37073,36814],{"class":437},[431,37075,4846],{"class":441},[431,37077,36817],{"class":437},[431,37079,4846],{"class":441},[431,37081,22026],{"class":437},[431,37083,4846],{"class":441},[431,37085,36822],{"class":437},[431,37087,4846],{"class":441},[431,37089,19598],{"class":437},[431,37091,4846],{"class":441},[431,37093,35060],{"class":437},[431,37095,4846],{"class":441},[431,37097,1021],{"class":437},[431,37099,37100],{"class":441},"], \n",[431,37102,37103,37106,37108,37110,37112,37114,37116,37118,37120,37122,37124,37126,37128,37130,37132],{"class":433,"line":452},[431,37104,37105],{"class":441},"         [",[431,37107,19588],{"class":437},[431,37109,4846],{"class":441},[431,37111,9573],{"class":437},[431,37113,4846],{"class":441},[431,37115,36841],{"class":437},[431,37117,4846],{"class":441},[431,37119,30841],{"class":437},[431,37121,4846],{"class":441},[431,37123,36846],{"class":437},[431,37125,4846],{"class":441},[431,37127,742],{"class":437},[431,37129,4846],{"class":441},[431,37131,26975],{"class":437},[431,37133,37100],{"class":441},[431,37135,37136,37138,37140,37142,37144,37146,37148,37150,37152,37154,37156,37158,37160,37162,37164],{"class":433,"line":578},[431,37137,37105],{"class":441},[431,37139,36859],{"class":437},[431,37141,4846],{"class":441},[431,37143,34365],{"class":437},[431,37145,4846],{"class":441},[431,37147,19593],{"class":437},[431,37149,4846],{"class":441},[431,37151,781],{"class":437},[431,37153,4846],{"class":441},[431,37155,3357],{"class":437},[431,37157,4846],{"class":441},[431,37159,1192],{"class":437},[431,37161,4846],{"class":441},[431,37163,35875],{"class":437},[431,37165,37100],{"class":441},[431,37167,37168,37170,37172,37174,37176,37178,37180,37182,37184,37186,37188,37190,37192,37194,37196],{"class":433,"line":584},[431,37169,37105],{"class":441},[431,37171,36880],{"class":437},[431,37173,4846],{"class":441},[431,37175,20633],{"class":437},[431,37177,4846],{"class":441},[431,37179,651],{"class":437},[431,37181,4846],{"class":441},[431,37183,16889],{"class":437},[431,37185,4846],{"class":441},[431,37187,30856],{"class":437},[431,37189,4846],{"class":441},[431,37191,36553],{"class":437},[431,37193,4846],{"class":441},[431,37195,36893],{"class":437},[431,37197,37100],{"class":441},[431,37199,37200,37202,37204,37206,37208,37210,37212,37214,37216,37218,37220,37222,37224,37226,37228],{"class":433,"line":1244},[431,37201,37105],{"class":441},[431,37203,33887],{"class":437},[431,37205,4846],{"class":441},[431,37207,30861],{"class":437},[431,37209,4846],{"class":441},[431,37211,21518],{"class":437},[431,37213,4846],{"class":441},[431,37215,971],{"class":437},[431,37217,4846],{"class":441},[431,37219,30866],{"class":437},[431,37221,4846],{"class":441},[431,37223,30846],{"class":437},[431,37225,4846],{"class":441},[431,37227,30851],{"class":437},[431,37229,37100],{"class":441},[431,37231,37232,37234,37236,37238,37240,37242,37244,37246,37248,37250,37252,37254,37256,37258,37260],{"class":433,"line":1985},[431,37233,37105],{"class":441},[431,37235,9731],{"class":437},[431,37237,4846],{"class":441},[431,37239,36924],{"class":437},[431,37241,4846],{"class":441},[431,37243,18740],{"class":437},[431,37245,4846],{"class":441},[431,37247,3565],{"class":437},[431,37249,4846],{"class":441},[431,37251,30836],{"class":437},[431,37253,4846],{"class":441},[431,37255,30876],{"class":437},[431,37257,4846],{"class":441},[431,37259,856],{"class":437},[431,37261,37100],{"class":441},[431,37263,37264,37266,37268,37270,37272,37274,37276,37278,37280,37282,37284,37286,37288,37290,37292],{"class":433,"line":2041},[431,37265,37105],{"class":441},[431,37267,30871],{"class":437},[431,37269,4846],{"class":441},[431,37271,762],{"class":437},[431,37273,4846],{"class":441},[431,37275,36947],{"class":437},[431,37277,4846],{"class":441},[431,37279,22031],{"class":437},[431,37281,4846],{"class":441},[431,37283,36952],{"class":437},[431,37285,4846],{"class":441},[431,37287,36955],{"class":437},[431,37289,4846],{"class":441},[431,37291,36958],{"class":437},[431,37293,22301],{"class":441},[431,37295,37296,37298,37300,37303,37305,37307,37309,37311,37313,37315,37317],{"class":433,"line":4018},[431,37297,4799],{"class":441},[431,37299,1189],{"class":654},[431,37301,37302],{"class":441}," rectangle(",[431,37304,781],{"class":437},[431,37306,4846],{"class":441},[431,37308,781],{"class":437},[431,37310,4846],{"class":441},[431,37312,856],{"class":437},[431,37314,4846],{"class":441},[431,37316,971],{"class":437},[431,37318,37319],{"class":441},", q)\n",[431,37321,37322,37324],{"class":433,"line":4030},[431,37323,438],{"class":437},[431,37325,37326],{"class":441},"(result)\n",[415,37328,37329],{},[1355,37330,37331],{},[800,37332,37333],{},"Способ 1",[415,37335,37336],{},"Здесь поможет упорядочивание. Нужно просто отсортировать ранги качества от меньших к большим и затем выбрать элемент со средним индексом.\nРассмотрим, к примеру, все те же 15 рангов качества: 48, 16, 15, 20, 11, 36, 22, 39, 30, 14, 35, 2, 32, 37 и 21.\nЕсли их упорядочить, то получится: 2, 11, 14, 15, 16, 20, 21, 22, 30, 32, 35, 36, 37, 39 и 48.\nВсего здесь 15 рангов, значит, нужно взять восьмой (22), который и будет средним.\nЕсть и более быстрые алгоритмы для непосредственного нахождения среднего значения без необходимости упорядочивания.\nСортировка — алгоритм, которому для нахождения среднего значения требуется O(n logn) времени.\nСуществует и более сложный алгоритм для нахождения среднего со временем O(n). Но здесь мы не станем его использовать.\nРеализуемый в этом способе процесс будет настолько медленным, что никакое улучшение алгоритма поиска среднего значения\nвсе равно не поможет.",[415,37338,37339],{},"Итак, выше напишем функцию с кодом нахождения среднего в заданном прямоугольнике:",[422,37341,37343],{"className":424,"code":37342,"language":396,"meta":426,"style":426},"def median(top_row, left_col, bottom_row, right_col, q):\n        cur_rectangle = []\n        for i in range(top_row, bottom_row + 1):\n                for j in range(left_col, right_col + 1):\n                        cur_rectangle.append(q[i][j])\n        cur_rectangle.sort()\n        return cur_rectangle[len(cur_rectangle) \u002F\u002F 2]\n",[428,37344,37345,37355,37364,37383,37403,37408,37413],{"__ignoreMap":426},[431,37346,37347,37349,37352],{"class":433,"line":434},[431,37348,6330],{"class":654},[431,37350,37351],{"class":6333}," median",[431,37353,37354],{"class":441},"(top_row, left_col, bottom_row, right_col, q):\n",[431,37356,37357,37360,37362],{"class":433,"line":452},[431,37358,37359],{"class":441},"        cur_rectangle ",[431,37361,1189],{"class":654},[431,37363,21007],{"class":441},[431,37365,37366,37368,37370,37372,37374,37377,37379,37381],{"class":433,"line":578},[431,37367,33447],{"class":654},[431,37369,12664],{"class":441},[431,37371,14421],{"class":654},[431,37373,14424],{"class":437},[431,37375,37376],{"class":441},"(top_row, bottom_row ",[431,37378,802],{"class":654},[431,37380,1032],{"class":437},[431,37382,7381],{"class":441},[431,37384,37385,37388,37390,37392,37394,37397,37399,37401],{"class":433,"line":584},[431,37386,37387],{"class":654},"                for",[431,37389,30695],{"class":441},[431,37391,14421],{"class":654},[431,37393,14424],{"class":437},[431,37395,37396],{"class":441},"(left_col, right_col ",[431,37398,802],{"class":654},[431,37400,1032],{"class":437},[431,37402,7381],{"class":441},[431,37404,37405],{"class":433,"line":1244},[431,37406,37407],{"class":441},"                        cur_rectangle.append(q[i][j])\n",[431,37409,37410],{"class":433,"line":1985},[431,37411,37412],{"class":441},"        cur_rectangle.sort()\n",[431,37414,37415,37417,37420,37422,37425,37427,37429],{"class":433,"line":2041},[431,37416,10453],{"class":654},[431,37418,37419],{"class":441}," cur_rectangle[",[431,37421,5205],{"class":437},[431,37423,37424],{"class":441},"(cur_rectangle) ",[431,37426,16854],{"class":654},[431,37428,689],{"class":437},[431,37430,3568],{"class":441},[415,37432,37433,37434,37437,37438,37440,37441,37444,37445,37447,37448,37450],{},"Первые четыре параметра ",[428,37435,37436],{},"median"," очерчивают прямоугольник, указывая координаты его левого верхнего и правого нижнего углов.\nЗаключительный параметр ",[428,37439,37027],{}," содержит ранги качества. Для хранения рангов качества прямоугольника используется одномерный массив ",[428,37442,37443],{},"cur_rectangle",".\nВложенные циклы for проходят через каждую ячейку (квартал) прямоугольника и добавляют соответствующий ранг качества в ",[428,37446,37443],{},".\nПосле сбора всех рангов можно вызвать встроенный метод ",[428,37449,36749],{},".\nДалее нам будет в точности известно, где находится среднее значение — в середине массива, — и мы просто его возвращаем.\nВооружившись этой функцией, можно перебирать все варианты прямоугольника, и в конце определить тот, чей средний ранг качества окажется наименьшим.\nКод поиска наименьшего среднего значения среди возможных прямоугольников:",[422,37452,37454],{"className":424,"code":37453,"language":396,"meta":426,"style":426},"def rectangle(r, c, h, w, q):\n    best = r * c + 1\n    for top_row in range(r - h + 1):\n        for left_col in range(c - w + 1):\n            bottom_row = top_row + h - 1\n            right_col = left_col + w - 1\n            res = median(top_row, left_col, bottom_row, right_col, q)\n            if res \u003C best:\n                best = res\n    return best\n",[428,37455,37456,37464,37483,37508,37533,37550,37567,37577,37589,37599],{"__ignoreMap":426},[431,37457,37458,37460,37462],{"class":433,"line":434},[431,37459,6330],{"class":654},[431,37461,36985],{"class":6333},[431,37463,36988],{"class":441},[431,37465,37466,37469,37471,37474,37476,37479,37481],{"class":433,"line":452},[431,37467,37468],{"class":441},"    best ",[431,37470,1189],{"class":654},[431,37472,37473],{"class":441}," r ",[431,37475,1357],{"class":654},[431,37477,37478],{"class":441}," c ",[431,37480,802],{"class":654},[431,37482,3916],{"class":437},[431,37484,37485,37487,37490,37492,37494,37497,37499,37502,37504,37506],{"class":433,"line":578},[431,37486,14745],{"class":654},[431,37488,37489],{"class":441}," top_row ",[431,37491,14421],{"class":654},[431,37493,14424],{"class":437},[431,37495,37496],{"class":441},"(r ",[431,37498,853],{"class":654},[431,37500,37501],{"class":441}," h ",[431,37503,802],{"class":654},[431,37505,1032],{"class":437},[431,37507,7381],{"class":441},[431,37509,37510,37512,37515,37517,37519,37522,37524,37527,37529,37531],{"class":433,"line":584},[431,37511,33447],{"class":654},[431,37513,37514],{"class":441}," left_col ",[431,37516,14421],{"class":654},[431,37518,14424],{"class":437},[431,37520,37521],{"class":441},"(c ",[431,37523,853],{"class":654},[431,37525,37526],{"class":441}," w ",[431,37528,802],{"class":654},[431,37530,1032],{"class":437},[431,37532,7381],{"class":441},[431,37534,37535,37538,37540,37542,37544,37546,37548],{"class":433,"line":1244},[431,37536,37537],{"class":441},"            bottom_row ",[431,37539,1189],{"class":654},[431,37541,37489],{"class":441},[431,37543,802],{"class":654},[431,37545,37501],{"class":441},[431,37547,853],{"class":654},[431,37549,3916],{"class":437},[431,37551,37552,37555,37557,37559,37561,37563,37565],{"class":433,"line":1985},[431,37553,37554],{"class":441},"            right_col ",[431,37556,1189],{"class":654},[431,37558,37514],{"class":441},[431,37560,802],{"class":654},[431,37562,37526],{"class":441},[431,37564,853],{"class":654},[431,37566,3916],{"class":437},[431,37568,37569,37572,37574],{"class":433,"line":2041},[431,37570,37571],{"class":441},"            res ",[431,37573,1189],{"class":654},[431,37575,37576],{"class":441}," median(top_row, left_col, bottom_row, right_col, q)\n",[431,37578,37579,37581,37584,37586],{"class":433,"line":4018},[431,37580,33458],{"class":654},[431,37582,37583],{"class":441}," res ",[431,37585,8521],{"class":654},[431,37587,37588],{"class":441}," best:\n",[431,37590,37591,37594,37596],{"class":433,"line":4030},[431,37592,37593],{"class":441},"                best ",[431,37595,1189],{"class":654},[431,37597,37598],{"class":441}," res\n",[431,37600,37601,37603],{"class":433,"line":4419},[431,37602,6599],{"class":654},[431,37604,37605],{"class":441}," best\n",[415,37607,37608,37609,37612,37613,37616,37617,37620,37621,37623,37624,37626,37627,37629,37630,37632,37633,37635,37636,37638],{},"В переменной ",[428,37610,37611],{},"best"," сохраняется наилучшее (то есть наименьшее) среднее значение, найденное до сих пор.\nЭту переменную мы изначально устанавливаем с большим значением, которое превосходит среднее любого возможного прямоугольника.\nНевозможно, чтобы среднее прямоугольника равнялось ",[428,37614,37615],{},"r * с + 1",", это бы означало, что половина его рангов качества больше ",[428,37618,37619],{},"r * c",".\nНо, согласно условию задачи, никакие ранги качества не могут быть больше ",[428,37622,37619],{},".\nВложенные циклы ",[428,37625,14329],{}," рассматривают все возможные координаты верхнего левого угла прямоугольника.\nТак мы получаем верхнюю строку и левый столбец, но для вызова ",[428,37628,37436],{}," нам также нужна нижняя строка и правый столбец.\nЧтобы вычислить координату нижней строки, мы берем номер верхней строки, прибавляем ",[428,37631,36999],{}," (количество строк в рассматриваемых прямоугольниках), а затем вычитаем ",[428,37634,1192],{},".\nЗдесь очень просто допустить промах на единицу, но вычитание единицы необходимо.\nЕсли верхняя строка имеет номер 4, а h равна 2, то нам нужно, чтобы номер нижней строки был равен 4 + 2 – 1 = 5.\nЕсли же сделать этот номер равным 4 + 2 = 6, то у нас получится прямоугольник с тремя строками вместо требуемых двух.\nАналогичным образом вычисляется номер правого столбца.\nПолучив все четыре координаты, мы вызываем ",[428,37637,37436],{}," для вычисления среднего значения ранга прямоугольника.\nЕсли в итоге обнаруживается лучшее значение, то оставшаяся часть кода обновляет best.\nНа этом текущее решение закончено.",[415,37640,37641,37642,3228,37644,37646,37647,37650,37651,3228,37653,37655,37656,37659,37660,37662,37663,37665,37666,37668,37669,37671,37672,37675,37676,37678,37679,37879,37880,37974,37975,37977],{},"Но чтобы понять, почему наш код столь медленный, рассмотрим пример, в котором ",[428,37643,36766],{},[428,37645,36776],{}," представлены числом ",[1355,37648,37649],{},"m",".\nДля демонстрации наихудшего случая мы возьмем ",[428,37652,36999],{},[428,37654,37002],{},", равные ",[1355,37657,37658],{},"m\u002F2"," (нам не нужно, чтобы прямоугольники получались излишне большими, иначе их будет немного.\nНам также не нужно, чтобы они были слишком маленькими, так как тогда каждый будет легко обработать).\nСамая медленная часть функции ",[428,37661,37436],{}," — вызов ",[428,37664,36749],{},". Она получает массив с m\u002F2 × m\u002F2 = m*m\u002F4 значений.\nДля обработки массива из ",[1355,37667,33806],{}," значений ",[428,37670,36749],{}," совершает ",[1355,37673,37674],{},"nlogn"," шагов.\nЗамена ",[1355,37677,33806],{}," на m*m\u002F4 дает оценку времени ",[33809,37680,37682],{"className":37681,"jax":33813},[33812],[33815,37683,37687,37724],{"style":35005,"xmlns":33818,"width":37684,"height":37685,"role":15324,"focusable":33821,"viewBox":37686,"xmlnsXLink":33823},"31.788ex","2.452ex","0 -833.9 14050.2 1083.9",[33825,37688,37689,37692,37696,37698,37702,37706,37709,37711,37713,37715,37718,37721],{},[33828,37690],{"id":37691,"d":35018},"MJX-1-TEX-N-28",[33828,37693],{"id":37694,"d":37695},"MJX-1-TEX-I-1D45A","M21 287Q22 293 24 303T36 341T56 388T88 425T132 442T175 435T205 417T221 395T229 376L231 369Q231 367 232 367L243 378Q303 442 384 442Q401 442 415 440T441 433T460 423T475 411T485 398T493 385T497 373T500 364T502 357L510 367Q573 442 659 442Q713 442 746 415T780 336Q780 285 742 178T704 50Q705 36 709 31T724 26Q752 26 776 56T815 138Q818 149 821 151T837 153Q857 153 857 145Q857 144 853 130Q845 101 831 73T785 17T716 -10Q669 -10 648 17T627 73Q627 92 663 193T700 345Q700 404 656 404H651Q565 404 506 303L499 291L466 157Q433 26 428 16Q415 -11 385 -11Q372 -11 364 -4T353 8T350 18Q350 29 384 161L420 307Q423 322 423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 181Q151 335 151 342Q154 357 154 369Q154 405 129 405Q107 405 92 377T69 316T57 280Q55 278 41 278H27Q21 284 21 287Z",[33828,37697],{"id":33842,"d":33843},[33828,37699],{"id":37700,"d":37701},"MJX-1-TEX-N-2F","M423 750Q432 750 438 744T444 730Q444 725 271 248T92 -240Q85 -250 75 -250Q68 -250 62 -245T56 -231Q56 -221 230 257T407 740Q411 750 423 750Z",[33828,37703],{"id":37704,"d":37705},"MJX-1-TEX-N-34","M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z",[33828,37707],{"id":37708,"d":35031},"MJX-1-TEX-N-29",[33828,37710],{"id":33830,"d":33831},[33828,37712],{"id":33834,"d":33835},[33828,37714],{"id":33838,"d":33839},[33828,37716],{"id":37717,"d":34166},"MJX-1-TEX-N-3D",[33828,37719],{"id":37720,"d":35014},"MJX-1-TEX-I-1D442",[33828,37722],{"id":37723,"d":34245},"MJX-1-TEX-N-2E",[33849,37725,37726],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,37727,37728,37733,37747,37756,37762,37768,37773,37778,37783,37788,37801,37808,37813,37818,37824,37830,37835,37848,37853,37858,37863,37868,37873],{"dataMmlNode":33855},[33849,37729,37730],{"dataMmlNode":34206},[33860,37731],{"dataC":35060,"xLinkHref":37732},"#MJX-1-TEX-N-28",[33849,37734,37736,37742],{"dataMmlNode":34252,"transform":37735},"translate(389,0)",[33849,37737,37738],{"dataMmlNode":33858},[33860,37739],{"dataC":37740,"xLinkHref":37741},"1D45A","#MJX-1-TEX-I-1D45A",[33849,37743,37745],{"dataMmlNode":33883,"transform":37744},"translate(911,363) scale(0.707)",[33860,37746],{"dataC":33887,"xLinkHref":33888},[33849,37748,37750],{"dataMmlNode":33955,"dataMjxTexclass":33956,"transform":37749},"translate(1703.6,0)",[33849,37751,37752],{"dataMmlNode":34206},[33860,37753],{"dataC":37754,"xLinkHref":37755},"2F","#MJX-1-TEX-N-2F",[33849,37757,37759],{"dataMmlNode":33883,"transform":37758},"translate(2203.6,0)",[33860,37760],{"dataC":36947,"xLinkHref":37761},"#MJX-1-TEX-N-34",[33849,37763,37765],{"dataMmlNode":34206,"transform":37764},"translate(2703.6,0)",[33860,37766],{"dataC":30851,"xLinkHref":37767},"#MJX-1-TEX-N-29",[33849,37769,37771],{"dataMmlNode":33858,"transform":37770},"translate(3092.6,0)",[33860,37772],{"dataC":33862,"xLinkHref":33863},[33849,37774,37776],{"dataMmlNode":33858,"transform":37775},"translate(3390.6,0)",[33860,37777],{"dataC":33869,"xLinkHref":33870},[33849,37779,37781],{"dataMmlNode":33858,"transform":37780},"translate(3875.6,0)",[33860,37782],{"dataC":33879,"xLinkHref":33880},[33849,37784,37786],{"dataMmlNode":34206,"transform":37785},"translate(4352.6,0)",[33860,37787],{"dataC":35060,"xLinkHref":37732},[33849,37789,37791,37795],{"dataMmlNode":34252,"transform":37790},"translate(4741.6,0)",[33849,37792,37793],{"dataMmlNode":33858},[33860,37794],{"dataC":37740,"xLinkHref":37741},[33849,37796,37797],{"dataMmlNode":33955,"transform":37744,"dataMjxTexclass":33956},[33849,37798,37799],{"dataMmlNode":33883},[33860,37800],{"dataC":33887,"xLinkHref":33888},[33849,37802,37804],{"dataMmlNode":33955,"dataMjxTexclass":33956,"transform":37803},"translate(6056.1,0)",[33849,37805,37806],{"dataMmlNode":34206},[33860,37807],{"dataC":37754,"xLinkHref":37755},[33849,37809,37811],{"dataMmlNode":33883,"transform":37810},"translate(6556.1,0)",[33860,37812],{"dataC":36947,"xLinkHref":37761},[33849,37814,37816],{"dataMmlNode":34206,"transform":37815},"translate(7056.1,0)",[33860,37817],{"dataC":30851,"xLinkHref":37767},[33849,37819,37821],{"dataMmlNode":34206,"transform":37820},"translate(7722.9,0)",[33860,37822],{"dataC":34210,"xLinkHref":37823},"#MJX-1-TEX-N-3D",[33849,37825,37827],{"dataMmlNode":33858,"transform":37826},"translate(8778.7,0)",[33860,37828],{"dataC":35053,"xLinkHref":37829},"#MJX-1-TEX-I-1D442",[33849,37831,37833],{"dataMmlNode":34206,"transform":37832},"translate(9541.7,0)",[33860,37834],{"dataC":35060,"xLinkHref":37732},[33849,37836,37838,37842],{"dataMmlNode":34252,"transform":37837},"translate(9930.7,0)",[33849,37839,37840],{"dataMmlNode":33858},[33860,37841],{"dataC":37740,"xLinkHref":37741},[33849,37843,37844],{"dataMmlNode":33955,"transform":37744,"dataMjxTexclass":33956},[33849,37845,37846],{"dataMmlNode":33883},[33860,37847],{"dataC":33887,"xLinkHref":33888},[33849,37849,37851],{"dataMmlNode":33858,"transform":37850},"translate(11245.2,0)",[33860,37852],{"dataC":33862,"xLinkHref":33863},[33849,37854,37856],{"dataMmlNode":33858,"transform":37855},"translate(11543.2,0)",[33860,37857],{"dataC":33869,"xLinkHref":33870},[33849,37859,37861],{"dataMmlNode":33858,"transform":37860},"translate(12028.2,0)",[33860,37862],{"dataC":33879,"xLinkHref":33880},[33849,37864,37866],{"dataMmlNode":33858,"transform":37865},"translate(12505.2,0)",[33860,37867],{"dataC":37740,"xLinkHref":37741},[33849,37869,37871],{"dataMmlNode":34206,"transform":37870},"translate(13383.2,0)",[33860,37872],{"dataC":30851,"xLinkHref":37767},[33849,37874,37876],{"dataMmlNode":34206,"transform":37875},"translate(13772.2,0)",[33860,37877],{"dataC":34278,"xLinkHref":37878},"#MJX-1-TEX-N-2E","\nИтак, выполнение происходит уже медленнее, чем в квадратичном случае, — а мы ведь вычислили среднее значение только для одного прямоугольника.\nФункция rectangle вызывает median всего m*m\u002F4 раз, значит, общее время выполнения составляет ",[33809,37881,37883],{"className":37882,"jax":33813},[33812],[33815,37884,37888,37914],{"style":35005,"xmlns":33818,"width":37885,"height":37886,"role":15324,"focusable":33821,"viewBox":37887,"xmlnsXLink":33823},"11.927ex","2.47ex","0 -841.7 5271.6 1091.7",[33825,37889,37890,37893,37896,37899,37902,37904,37906,37908,37911],{},[33828,37891],{"id":37892,"d":35014},"MJX-2-TEX-I-1D442",[33828,37894],{"id":37895,"d":35018},"MJX-2-TEX-N-28",[33828,37897],{"id":37898,"d":37695},"MJX-2-TEX-I-1D45A",[33828,37900],{"id":37901,"d":37705},"MJX-2-TEX-N-34",[33828,37903],{"id":33917,"d":33831},[33828,37905],{"id":33920,"d":33835},[33828,37907],{"id":33923,"d":33839},[33828,37909],{"id":37910,"d":35031},"MJX-2-TEX-N-29",[33828,37912],{"id":37913,"d":34245},"MJX-2-TEX-N-2E",[33849,37915,37916],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,37917,37918,37923,37928,37942,37947,37952,37957,37962,37968],{"dataMmlNode":33855},[33849,37919,37920],{"dataMmlNode":33858},[33860,37921],{"dataC":35053,"xLinkHref":37922},"#MJX-2-TEX-I-1D442",[33849,37924,37925],{"dataMmlNode":34206,"transform":35057},[33860,37926],{"dataC":35060,"xLinkHref":37927},"#MJX-2-TEX-N-28",[33849,37929,37930,37935],{"dataMmlNode":34252,"transform":35064},[33849,37931,37932],{"dataMmlNode":33858},[33860,37933],{"dataC":37740,"xLinkHref":37934},"#MJX-2-TEX-I-1D45A",[33849,37936,37937],{"dataMmlNode":33955,"transform":37744,"dataMjxTexclass":33956},[33849,37938,37939],{"dataMmlNode":33883},[33860,37940],{"dataC":36947,"xLinkHref":37941},"#MJX-2-TEX-N-34",[33849,37943,37945],{"dataMmlNode":33858,"transform":37944},"translate(2466.6,0)",[33860,37946],{"dataC":33862,"xLinkHref":33940},[33849,37948,37950],{"dataMmlNode":33858,"transform":37949},"translate(2764.6,0)",[33860,37951],{"dataC":33869,"xLinkHref":33945},[33849,37953,37955],{"dataMmlNode":33858,"transform":37954},"translate(3249.6,0)",[33860,37956],{"dataC":33879,"xLinkHref":33952},[33849,37958,37960],{"dataMmlNode":33858,"transform":37959},"translate(3726.6,0)",[33860,37961],{"dataC":37740,"xLinkHref":37934},[33849,37963,37965],{"dataMmlNode":34206,"transform":37964},"translate(4604.6,0)",[33860,37966],{"dataC":30851,"xLinkHref":37967},"#MJX-2-TEX-N-29",[33849,37969,37971],{"dataMmlNode":34206,"transform":37970},"translate(4993.6,0)",[33860,37972],{"dataC":34278,"xLinkHref":37973},"#MJX-2-TEX-N-2E","\nПри таком числе операций данное решение подходит только для примеров с очень малым количеством данных.\nВ нашем решении присутствуют два узких места.\nПервое — это упорядочивание каждого прямоугольника.\nВторое — это создание массива ",[428,37976,37443],{}," с нуля для каждого прямоугольника.\nИспользование двоичного поиска решает первую проблему, а динамическое программирование — вторую.",[34980,37979,37981],{"id":37980},"двоичный-поиск","ДВОИЧНЫЙ ПОИСК",[415,37983,37984],{},"Почему нам стоит рассчитывать на то, что двоичный поиск обеспечит в данном случае прирост скорости?\nВо-первых, выше показано, что прямой поиск очень затратен. Подход, который опирался на сортировку, оказался медленнее m*m*m*m.\nВо-вторых, это еще один пример задачи, где сначала идут все недопустимые решения, а за ними уже допустимые.\nПредположим, что нет такого прямоугольника, чей средний ранг качества имеет значение менее 6.\nТогда не будет смысла искать прямоугольники со средним качеством 5, 4 или любым меньшим значением.\nИ наоборот, предположим, я скажу, что есть прямоугольник со средним рангом качества 5 или меньше.\nТеперь не будет смысла искать прямоугольники со средним рангом качества 6, 7 или любым другим, чье значение выше 5.\nТак задается область двоичного поиска.",[415,37986,37987,37988,37990,37991,37993,37994,37996],{},"В задаче с прыжками вдоль реки небольшие значения были допустимыми, а большие недопустимыми.\nЗдесь же у нас обратный случай: небольшие значения оказываются недопустимыми, а большие допустимыми.\nСледовательно, нам придется изменить инвариант, сменив расположение допустимых и недопустимых частей пространства решений.\nИ вот какой инвариант мы используем: ",[428,37989,36035],{}," и все, что меньше, будет недопустимо; ",[428,37992,36038],{}," и все, что больше, — допустимо.\nТаким образом, по завершении нужно возвращать ",[428,37995,36038],{},", поскольку таково будет наименьшее допустимое значение.",[422,37998,38000],{"className":424,"code":37999,"language":396,"meta":426,"style":426},"def rectangle(r, c, h, w, q):\n    low = 0\n    high = r * c + 1\n    while high - low > 1:\n        mid = (low + high) \u002F\u002F 2\n        if can_make_quality(mid, r, c, h, w, q):\n            high = mid\n        else:\n            low = mid\n    return high\n",[428,38001,38002,38010,38018,38034,38050,38066,38073,38081,38087,38095],{"__ignoreMap":426},[431,38003,38004,38006,38008],{"class":433,"line":434},[431,38005,6330],{"class":654},[431,38007,36985],{"class":6333},[431,38009,36988],{"class":441},[431,38011,38012,38014,38016],{"class":433,"line":452},[431,38013,35925],{"class":441},[431,38015,1189],{"class":654},[431,38017,3459],{"class":437},[431,38019,38020,38022,38024,38026,38028,38030,38032],{"class":433,"line":578},[431,38021,34547],{"class":441},[431,38023,1189],{"class":654},[431,38025,37473],{"class":441},[431,38027,1357],{"class":654},[431,38029,37478],{"class":441},[431,38031,802],{"class":654},[431,38033,3916],{"class":437},[431,38035,38036,38038,38040,38042,38044,38046,38048],{"class":433,"line":584},[431,38037,12537],{"class":654},[431,38039,35945],{"class":441},[431,38041,853],{"class":654},[431,38043,34619],{"class":441},[431,38045,8883],{"class":654},[431,38047,1032],{"class":437},[431,38049,8102],{"class":441},[431,38051,38052,38054,38056,38058,38060,38062,38064],{"class":433,"line":1244},[431,38053,35963],{"class":441},[431,38055,1189],{"class":654},[431,38057,34504],{"class":441},[431,38059,802],{"class":654},[431,38061,34509],{"class":441},[431,38063,16854],{"class":654},[431,38065,658],{"class":437},[431,38067,38068,38070],{"class":433,"line":1985},[431,38069,11471],{"class":654},[431,38071,38072],{"class":441}," can_make_quality(mid, r, c, h, w, q):\n",[431,38074,38075,38077,38079],{"class":433,"line":2041},[431,38076,35997],{"class":441},[431,38078,1189],{"class":654},[431,38080,34677],{"class":441},[431,38082,38083,38085],{"class":433,"line":4018},[431,38084,24030],{"class":654},[431,38086,8102],{"class":441},[431,38088,38089,38091,38093],{"class":433,"line":4030},[431,38090,36012],{"class":441},[431,38092,1189],{"class":654},[431,38094,34677],{"class":441},[431,38096,38097,38099],{"class":433,"line":4419},[431,38098,6599],{"class":654},[431,38100,38101],{"class":441}," high\n",[415,38103,38104,38105,2699],{},"Для завершения нужно проверить допустимость с помощью ",[428,38106,38107],{},"can_make_quality",[34980,38109,36288],{"id":38110},"проверка-допустимости-1",[415,38112,38113,38114,38117,38118,38121],{},"Вот функция проверки допустимости: ",[428,38115,38116],{},"def can_make_quality(quality, r, c, h, w, q):",".\nНам достаточно будет определять, не превосходит ли среднее значение некоторого прямоугольника пороговое значение ранга ",[428,38119,38120],{},"quality",".\nЭто более простая задача, для которой этап сортировки необязателен.\nКонкретные значения нам больше не важны, принципиально только соотношение между каждым значением и quality.\nПоэтому мы заменим все меньшие или равные quality значения на –1, а все большие — на 1.\nЗатем мы сложим эти –1 и 1 для заданного прямоугольника. Если в итоге значений –1 получится столько же или больше, чем значений 1\n(т.е. относительно quality число меньших значений будет превосходить количество больших),\nто их сумма будет нулевой или отрицательной и мы сделаем вывод, что средний ранг качества данного прямоугольника равен quality или меньше него.",[415,38123,38124],{},"Рассмотрим пример, в котором снова возьмем 15 рангов для прямоугольника 5 × 3 из верхнего левого угла таблицы условия:\n48, 16, 15, 20, 11, 36, 22, 39, 30, 14, 35, 2, 32, 37 и 21.\nСравним средний ранг качества этого прямоугольника с 16.\nДля этого возьмем каждое значение и, если оно меньше или равно 16, заменим его на –1, а если больше 16, то на 1.\nПолучатся следующие значения: 1, –1, –1, 1, –1, 1, 1, 1, 1, –1, 1, –1, 1, 1 и 1.\nИх сложение даст 5. Это означает, что значений, превосходящих 16, на пять больше, чем меньших или равных этому числу.\nЭто, в свою очередь, говорит о том, что среднее значение 16 или меньше для данного прямоугольника невозможно.\nЕсли бы мы хотели узнать, является ли допустимым среднее значение 30,\nто также узнали бы об этом, заменив числа на –1 и 1: 1, –1, –1, –1, –1, 1, –1, 1, –1, –1, 1, –1, 1, 1 и –1.\nСложение этих значений даст –3. Значит, 30 является допустимым средним.\nВажно отметить, что решение о допустимости\u002Fнедопустимости принимается без предварительного упорядочивания.\nНам нужно перебрать каждый прямоугольник, проверяя, содержит ли он средний ранг качества, равный quality или меньше него.\nЭтот процесс реализуется в коде ниже:",[422,38126,38128],{"className":424,"code":38127,"language":396,"meta":426,"style":426},"def can_make_quality(quality, r, c, h, w, q):\n    zero_one = [row[:] for row in q]\n    for i in range(r):\n        for j in range(c):\n            if q[i][j] \u003C= quality:\n                zero_one[i][j] = -1\n            else:\n                zero_one[i][j] = 1\n    for top_row in range(r - h + 1):\n        for left_col in range(c - w + 1):\n            bottom_row = top_row + h - 1\n            right_col = left_col + w - 1\n            total = 0\n            for i in range(top_row, bottom_row + 1):\n                for j in range(left_col, right_col + 1):\n                    total = total + zero_one[i][j]\n            if total \u003C= 0:\n                return True\n    return False\n",[428,38129,38130,38140,38159,38172,38185,38197,38209,38216,38224,38246,38268,38284,38300,38309,38327,38345,38360,38372,38378],{"__ignoreMap":426},[431,38131,38132,38134,38137],{"class":433,"line":434},[431,38133,6330],{"class":654},[431,38135,38136],{"class":6333}," can_make_quality",[431,38138,38139],{"class":441},"(quality, r, c, h, w, q):\n",[431,38141,38142,38145,38147,38150,38152,38154,38156],{"class":433,"line":452},[431,38143,38144],{"class":441},"    zero_one ",[431,38146,1189],{"class":654},[431,38148,38149],{"class":441}," [row[:] ",[431,38151,14329],{"class":654},[431,38153,22907],{"class":441},[431,38155,14421],{"class":654},[431,38157,38158],{"class":441}," q]\n",[431,38160,38161,38163,38165,38167,38169],{"class":433,"line":578},[431,38162,14745],{"class":654},[431,38164,12664],{"class":441},[431,38166,14421],{"class":654},[431,38168,14424],{"class":437},[431,38170,38171],{"class":441},"(r):\n",[431,38173,38174,38176,38178,38180,38182],{"class":433,"line":584},[431,38175,33447],{"class":654},[431,38177,30695],{"class":441},[431,38179,14421],{"class":654},[431,38181,14424],{"class":437},[431,38183,38184],{"class":441},"(c):\n",[431,38186,38187,38189,38192,38194],{"class":433,"line":1244},[431,38188,33458],{"class":654},[431,38190,38191],{"class":441}," q[i][j] ",[431,38193,12667],{"class":654},[431,38195,38196],{"class":441}," quality:\n",[431,38198,38199,38202,38204,38206],{"class":433,"line":1985},[431,38200,38201],{"class":441},"                zero_one[i][j] ",[431,38203,1189],{"class":654},[431,38205,981],{"class":654},[431,38207,38208],{"class":437},"1\n",[431,38210,38211,38214],{"class":433,"line":2041},[431,38212,38213],{"class":654},"            else",[431,38215,8102],{"class":441},[431,38217,38218,38220,38222],{"class":433,"line":4018},[431,38219,38201],{"class":441},[431,38221,1189],{"class":654},[431,38223,3916],{"class":437},[431,38225,38226,38228,38230,38232,38234,38236,38238,38240,38242,38244],{"class":433,"line":4030},[431,38227,14745],{"class":654},[431,38229,37489],{"class":441},[431,38231,14421],{"class":654},[431,38233,14424],{"class":437},[431,38235,37496],{"class":441},[431,38237,853],{"class":654},[431,38239,37501],{"class":441},[431,38241,802],{"class":654},[431,38243,1032],{"class":437},[431,38245,7381],{"class":441},[431,38247,38248,38250,38252,38254,38256,38258,38260,38262,38264,38266],{"class":433,"line":4419},[431,38249,33447],{"class":654},[431,38251,37514],{"class":441},[431,38253,14421],{"class":654},[431,38255,14424],{"class":437},[431,38257,37521],{"class":441},[431,38259,853],{"class":654},[431,38261,37526],{"class":441},[431,38263,802],{"class":654},[431,38265,1032],{"class":437},[431,38267,7381],{"class":441},[431,38269,38270,38272,38274,38276,38278,38280,38282],{"class":433,"line":4436},[431,38271,37537],{"class":441},[431,38273,1189],{"class":654},[431,38275,37489],{"class":441},[431,38277,802],{"class":654},[431,38279,37501],{"class":441},[431,38281,853],{"class":654},[431,38283,3916],{"class":437},[431,38285,38286,38288,38290,38292,38294,38296,38298],{"class":433,"line":4446},[431,38287,37554],{"class":441},[431,38289,1189],{"class":654},[431,38291,37514],{"class":441},[431,38293,802],{"class":654},[431,38295,37526],{"class":441},[431,38297,853],{"class":654},[431,38299,3916],{"class":437},[431,38301,38302,38305,38307],{"class":433,"line":4451},[431,38303,38304],{"class":441},"            total ",[431,38306,1189],{"class":654},[431,38308,3459],{"class":437},[431,38310,38311,38313,38315,38317,38319,38321,38323,38325],{"class":433,"line":4086},[431,38312,24012],{"class":654},[431,38314,12664],{"class":441},[431,38316,14421],{"class":654},[431,38318,14424],{"class":437},[431,38320,37376],{"class":441},[431,38322,802],{"class":654},[431,38324,1032],{"class":437},[431,38326,7381],{"class":441},[431,38328,38329,38331,38333,38335,38337,38339,38341,38343],{"class":433,"line":4477},[431,38330,37387],{"class":654},[431,38332,30695],{"class":441},[431,38334,14421],{"class":654},[431,38336,14424],{"class":437},[431,38338,37396],{"class":441},[431,38340,802],{"class":654},[431,38342,1032],{"class":437},[431,38344,7381],{"class":441},[431,38346,38347,38350,38352,38355,38357],{"class":433,"line":4482},[431,38348,38349],{"class":441},"                    total ",[431,38351,1189],{"class":654},[431,38353,38354],{"class":441}," total ",[431,38356,802],{"class":654},[431,38358,38359],{"class":441}," zero_one[i][j]\n",[431,38361,38362,38364,38366,38368,38370],{"class":433,"line":4488},[431,38363,33458],{"class":654},[431,38365,38354],{"class":441},[431,38367,12667],{"class":654},[431,38369,9744],{"class":437},[431,38371,8102],{"class":441},[431,38373,38374,38376],{"class":433,"line":4505},[431,38375,35803],{"class":654},[431,38377,10188],{"class":437},[431,38379,38380,38382],{"class":433,"line":12871},[431,38381,6599],{"class":654},[431,38383,14187],{"class":437},[415,38385,38386,38387,38390,38391,38393],{},"Нельзя просто заместить массив q значениями –1 и 1, потому что тогда мы не сможем использовать исходные ранги качества для последующей проверки других значений quality.\nСледовательно, здесь для хранения –1 и 1 создается новый массив ",[428,38388,38389],{},"zero_one",".\nОбратите внимание, что он заполняется на основании того, является ли каждое значение меньшим или равным (–1) либо большим (1), чем пороговый параметр ",[428,38392,38120],{},".\nДалее мы проходим по каждому прямоугольнику так же. При этом суммируются все его –1 и 1, и возвращается True (верно), если средний ранг качества оказывается достаточно мал.",[415,38395,38396,38397,38399],{},"Вот мы и избавились от сортировки — искусно, не так ли? Этот прием очень важен для решения нашей задачи, но недостаточен.\nЕсли посчитать вложенные циклы, то окажется, что у нас их целых четыре.\nМы обнаружили, что решение без двоичного поиска оказалось очень медленным.\nЗдесь же оценка скорости проверки допустимости все еще равна m",[1355,38398,37649],{},"m*m.\nУмножьте ее на логарифмический множитель, характеризующий двоичный поиск, и возникнет вопрос: а добились ли мы хоть какого-нибудь прогресса?\nНо мы добились! Просто он скрыт за слишком большим числом вложенных циклов, производящих чересчур много вычислений.\nОставшуюся часть пути нам поможет пройти динамическое программирование.",[34980,38401,38403],{"id":38402},"ускоренная-проверка-допустимости","УСКОРЕННАЯ ПРОВЕРКА ДОПУСТИМОСТИ",[415,38405,38406],{},"Предположим, что дана таблица(как в условии задачи выше) и требуется выяснить, содержит ли какой-либо из прямоугольников 5 × 3 средний ранг качества 16 или менее.\nИзменив все значения, которые меньше или равны 16, на –1, а все значения больше 16 — на 1, получим следующую таблицу:",[9256,38408,38409,38429],{},[9259,38410,38411],{},[9262,38412,38413,38415,38417,38419,38421,38423,38425,38427],{},[9265,38414],{},[9265,38416,3302],{},[9265,38418,1192],{},[9265,38420,651],{},[9265,38422,971],{},[9265,38424,762],{},[9265,38426,856],{},[9265,38428,742],{},[9275,38430,38431,38452,38472,38492,38512,38532,38552],{},[9262,38432,38433,38437,38439,38442,38444,38446,38448,38450],{},[9280,38434,38435],{},[800,38436,3302],{},[9280,38438,1192],{},[9280,38440,38441],{},"-1",[9280,38443,38441],{},[9280,38445,1192],{},[9280,38447,1192],{},[9280,38449,1192],{},[9280,38451,38441],{},[9262,38453,38454,38458,38460,38462,38464,38466,38468,38470],{},[9280,38455,38456],{},[800,38457,1192],{},[9280,38459,1192],{},[9280,38461,38441],{},[9280,38463,1192],{},[9280,38465,1192],{},[9280,38467,1192],{},[9280,38469,38441],{},[9280,38471,1192],{},[9262,38473,38474,38478,38480,38482,38484,38486,38488,38490],{},[9280,38475,38476],{},[800,38477,651],{},[9280,38479,1192],{},[9280,38481,1192],{},[9280,38483,1192],{},[9280,38485,38441],{},[9280,38487,38441],{},[9280,38489,38441],{},[9280,38491,1192],{},[9262,38493,38494,38498,38500,38502,38504,38506,38508,38510],{},[9280,38495,38496],{},[800,38497,971],{},[9280,38499,38441],{},[9280,38501,1192],{},[9280,38503,38441],{},[9280,38505,38441],{},[9280,38507,1192],{},[9280,38509,38441],{},[9280,38511,1192],{},[9262,38513,38514,38518,38520,38522,38524,38526,38528,38530],{},[9280,38515,38516],{},[800,38517,762],{},[9280,38519,1192],{},[9280,38521,1192],{},[9280,38523,1192],{},[9280,38525,38441],{},[9280,38527,1192],{},[9280,38529,1192],{},[9280,38531,1192],{},[9262,38533,38534,38538,38540,38542,38544,38546,38548,38550],{},[9280,38535,38536],{},[800,38537,856],{},[9280,38539,1192],{},[9280,38541,1192],{},[9280,38543,1192],{},[9280,38545,38441],{},[9280,38547,1192],{},[9280,38549,1192],{},[9280,38551,38441],{},[9262,38553,38554,38558,38560,38562,38564,38566,38568,38570],{},[9280,38555,38556],{},[800,38557,742],{},[9280,38559,1192],{},[9280,38561,38441],{},[9280,38563,1192],{},[9280,38565,1192],{},[9280,38567,1192],{},[9280,38569,1192],{},[9280,38571,1192],{},[415,38573,38574],{},"Можно начать с суммирования элементов прямоугольника 5 × 3 с координатами верхнего левого угла (0, 0).\nСумма значений этого прямоугольника равна 5. Далее вычислим сумму элементов прямоугольника 5 × 3 с координатами верхнего левого угла (0, 1).\nРанее мы бы в данном случае сложили все 15 чисел. Однако тогда мы не сможем воспользоваться результатами вычислений суммы первого прямоугольника.\nДействительно, во втором прямоугольнике есть 10 общих значений с первым.\nНам нужно избежать подобного дублирования работы как для этого, так и для всех остальных прямоугольников.\nИсключение повторения работы здесь подразумевает эффективное выполнение так называемого запроса суммы двумерного диапазона.\nОдномерный случай реализуется по тем же принципам, но проще, поэтому сперва мы вкратце изучим его, а потом уже вернемся к завершению задачи.",[415,38576,38577],{},[1355,38578,38579],{},[800,38580,38581],{},"Запрос суммы одномерного диапазона",[415,38583,38584],{},"Рассмотрим одномерный массив:",[9256,38586,38587,38608],{},[9259,38588,38589],{},[9262,38590,38591,38594,38596,38598,38600,38602,38604,38606],{},[9265,38592,38593],{},"Индекс",[9265,38595,3302],{},[9265,38597,1192],{},[9265,38599,651],{},[9265,38601,971],{},[9265,38603,762],{},[9265,38605,856],{},[9265,38607,742],{},[9275,38609,38610],{},[9262,38611,38612,38617,38619,38621,38623,38625,38627,38629],{},[9280,38613,38614],{},[800,38615,38616],{},"Значение",[9280,38618,742],{},[9280,38620,651],{},[9280,38622,22026],{},[9280,38624,3357],{},[9280,38626,36553],{},[9280,38628,762],{},[9280,38630,9573],{},[415,38632,38633],{},"Если требуется найти сумму элементов массива от индекса 2 до индекса 5, то можно напрямую суммировать значения в этом диапазоне: 15 + 9 + 12 + 4 = 40.\nЭто не очень быстро, и будет совсем печально, если потребуется найти сумму всего массива.\nОднако если требуется ответить всего на несколько таких запросов, то этот вариант приемлем, и можно каждый раз суммировать соответствующие значения.\nТеперь представим, что мы получаем сотни или даже тысячи подобных запросов.\nТогда есть смысл единожды проделать предварительную работу, которая позволит отвечать на них быстрее.\nРассмотрим запрос от индекса 2 до 5. Что, если предварительно найти сумму значений от индекса 0 до 5? Она равна 48.\nЭто не нужный нам ответ, которым является 40, однако здесь удобен тот факт, что 48 находится от него недалеко.\nОшибочно это значение лишь потому, что включает индексы 0 и 1, которые теперь нужно исключить.\nЭто можно быстро сделать при условии нахождения их суммы, которая равна 8. Если вычесть 8 из 48, то получится нужная сумма 40.\nВ таком случае нам нужен новый массив, тот, где индекс i содержит сумму всех значений от индекса 0 до i.\nЭтот новый массив добавляется в строку частичной суммы в следующей таблице:",[9256,38635,38636,38656],{},[9259,38637,38638],{},[9262,38639,38640,38642,38644,38646,38648,38650,38652,38654],{},[9265,38641,38593],{},[9265,38643,3302],{},[9265,38645,1192],{},[9265,38647,651],{},[9265,38649,971],{},[9265,38651,762],{},[9265,38653,856],{},[9265,38655,742],{},[9275,38657,38658,38678],{},[9262,38659,38660,38664,38666,38668,38670,38672,38674,38676],{},[9280,38661,38662],{},[800,38663,38616],{},[9280,38665,742],{},[9280,38667,651],{},[9280,38669,22026],{},[9280,38671,3357],{},[9280,38673,36553],{},[9280,38675,762],{},[9280,38677,9573],{},[9262,38679,38680,38685,38687,38689,38691,38693,38695,38697],{},[9280,38681,38682],{},[800,38683,38684],{},"Частичная сумма",[9280,38686,742],{},[9280,38688,1021],{},[9280,38690,30846],{},[9280,38692,33887],{},[9280,38694,36958],{},[9280,38696,36814],{},[9280,38698,30886],{},[415,38700,38701],{},"Теперь можно быстро отвечать на любой запрос, используя массив частичных сумм:\nдля вычисления суммы диапазона от индекса a до b нужно взять значение в индексе b и вычесть из него значение в индексе a – 1.\nДля диапазона от 2 до 5 получится 48 – 8 = 40, а от 1 до 6 получится 59 – 6 = 53.\nТеперь на получение ответов независимо от величины диапазона требуется одинаковое количество времени,\nпричем для этого достаточно было сделать всего один предварительный проход по массиву.",[415,38703,38704],{},[1355,38705,38706],{},[800,38707,38708],{},"Запрос суммы двумерного массива",[415,38710,38711],{},"Вернемся в двумерный мир наших рангов качества.\nСуммирование элементов каждого прямоугольника — слишком медленный процесс, поэтому мы расширим освоенный на одномерном примере прием до двух измерений.\nВ частности, потребуется создать новый массив, в котором индекс (i, j) является суммой элементов прямоугольника,\nкоординаты верхнего левого угла которого — (0, 0), а нижнего правого — (i, j).\nЕще раз взглянем на таблицу:",[9256,38713,38714,38734],{},[9259,38715,38716],{},[9262,38717,38718,38720,38722,38724,38726,38728,38730,38732],{},[9265,38719],{},[9265,38721,3302],{},[9265,38723,1192],{},[9265,38725,651],{},[9265,38727,971],{},[9265,38729,762],{},[9265,38731,856],{},[9265,38733,742],{},[9275,38735,38736,38756,38776,38796,38816,38836,38856],{},[9262,38737,38738,38742,38744,38746,38748,38750,38752,38754],{},[9280,38739,38740],{},[800,38741,3302],{},[9280,38743,1192],{},[9280,38745,38441],{},[9280,38747,38441],{},[9280,38749,1192],{},[9280,38751,1192],{},[9280,38753,1192],{},[9280,38755,38441],{},[9262,38757,38758,38762,38764,38766,38768,38770,38772,38774],{},[9280,38759,38760],{},[800,38761,1192],{},[9280,38763,1192],{},[9280,38765,38441],{},[9280,38767,1192],{},[9280,38769,1192],{},[9280,38771,1192],{},[9280,38773,38441],{},[9280,38775,1192],{},[9262,38777,38778,38782,38784,38786,38788,38790,38792,38794],{},[9280,38779,38780],{},[800,38781,651],{},[9280,38783,1192],{},[9280,38785,1192],{},[9280,38787,1192],{},[9280,38789,38441],{},[9280,38791,38441],{},[9280,38793,38441],{},[9280,38795,1192],{},[9262,38797,38798,38802,38804,38806,38808,38810,38812,38814],{},[9280,38799,38800],{},[800,38801,971],{},[9280,38803,38441],{},[9280,38805,1192],{},[9280,38807,38441],{},[9280,38809,38441],{},[9280,38811,1192],{},[9280,38813,38441],{},[9280,38815,1192],{},[9262,38817,38818,38822,38824,38826,38828,38830,38832,38834],{},[9280,38819,38820],{},[800,38821,762],{},[9280,38823,1192],{},[9280,38825,1192],{},[9280,38827,1192],{},[9280,38829,38441],{},[9280,38831,1192],{},[9280,38833,1192],{},[9280,38835,1192],{},[9262,38837,38838,38842,38844,38846,38848,38850,38852,38854],{},[9280,38839,38840],{},[800,38841,856],{},[9280,38843,1192],{},[9280,38845,1192],{},[9280,38847,1192],{},[9280,38849,38441],{},[9280,38851,1192],{},[9280,38853,1192],{},[9280,38855,38441],{},[9262,38857,38858,38862,38864,38866,38868,38870,38872,38874],{},[9280,38859,38860],{},[800,38861,742],{},[9280,38863,1192],{},[9280,38865,38441],{},[9280,38867,1192],{},[9280,38869,1192],{},[9280,38871,1192],{},[9280,38873,1192],{},[9280,38875,1192],{},[415,38877,38878],{},"Соответствующий ей массив \"частичных сумм\" представлен в таблице ниже:",[9256,38880,38881,38901],{},[9259,38882,38883],{},[9262,38884,38885,38887,38889,38891,38893,38895,38897,38899],{},[9265,38886],{},[9265,38888,3302],{},[9265,38890,1192],{},[9265,38892,651],{},[9265,38894,971],{},[9265,38896,762],{},[9265,38898,856],{},[9265,38900,742],{},[9275,38902,38903,38923,38943,38963,38983,39003,39023],{},[9262,38904,38905,38909,38911,38913,38915,38917,38919,38921],{},[9280,38906,38907],{},[800,38908,3302],{},[9280,38910,1192],{},[9280,38912,3302],{},[9280,38914,38441],{},[9280,38916,3302],{},[9280,38918,1192],{},[9280,38920,651],{},[9280,38922,1192],{},[9262,38924,38925,38929,38931,38933,38935,38937,38939,38941],{},[9280,38926,38927],{},[800,38928,1192],{},[9280,38930,651],{},[9280,38932,3302],{},[9280,38934,3302],{},[9280,38936,651],{},[9280,38938,762],{},[9280,38940,762],{},[9280,38942,762],{},[9262,38944,38945,38949,38951,38953,38955,38957,38959,38961],{},[9280,38946,38947],{},[800,38948,651],{},[9280,38950,971],{},[9280,38952,651],{},[9280,38954,971],{},[9280,38956,762],{},[9280,38958,856],{},[9280,38960,762],{},[9280,38962,856],{},[9262,38964,38965,38969,38971,38973,38975,38977,38979,38981],{},[9280,38966,38967],{},[800,38968,971],{},[9280,38970,651],{},[9280,38972,651],{},[9280,38974,651],{},[9280,38976,651],{},[9280,38978,762],{},[9280,38980,651],{},[9280,38982,762],{},[9262,38984,38985,38989,38991,38993,38995,38997,38999,39001],{},[9280,38986,38987],{},[800,38988,762],{},[9280,38990,971],{},[9280,38992,762],{},[9280,38994,856],{},[9280,38996,762],{},[9280,38998,781],{},[9280,39000,742],{},[9280,39002,3357],{},[9262,39004,39005,39009,39011,39013,39015,39017,39019,39021],{},[9280,39006,39007],{},[800,39008,856],{},[9280,39010,762],{},[9280,39012,742],{},[9280,39014,1021],{},[9280,39016,742],{},[9280,39018,3565],{},[9280,39020,3565],{},[9280,39022,36553],{},[9262,39024,39025,39029,39031,39033,39035,39037,39039,39041],{},[9280,39026,39027],{},[800,39028,742],{},[9280,39030,856],{},[9280,39032,742],{},[9280,39034,3357],{},[9280,39036,1021],{},[9280,39038,16889],{},[9280,39040,36880],{},[9280,39042,30836],{},[415,39044,39045],{},"Для начала убедимся, что правильно понимаем предоставляемые этим массивом данные, а потом уже перейдем к рассмотрению его построения.\nЗначение в строке 4 и столбце 2 указывает сумму чисел в прямоугольнике, координаты верхнего левого угла которого — (0, 0), а правого нижнего — (4, 2).\nКак вычислить значение для ячейки (4, 2) на основе других ранее вычисленных значений?\nНужно начать со значения из ячейки таблицы -1 и 1 и прибавить все числа выше, а также левее нее.\nЭто можно сделать, грамотно используя массив из таблицы \"частичных сумм\", как будет показано в таблице ниже.",[415,39047,39048],{},"Необходимо начать с 1, затем охватить ячейки, включающие x (выше), а также ячейки, включающие y (слева), после чего вычислить сумму.\nСумма ячеек, включающих x, представлена элементом (3, 2). Сумма ячеек, включающих y, аналогичным образом представлена элементом (4, 1).\nОднако их сложение приводит к двойному подсчету ячеек xy (расположенных выше и левее).\nНо это не проблема, потому что элемент (3, 1) содержит сумму именно этих ячеек и компенсировать двойной подсчет можно его вычитанием.\nТаким образом, получается 1 + 2 + 4 – 2 = 5, что нам и требовалось.\nПри условии продвижения сверху вниз и слева направо можно строить этот массив с помощью всего двух операций сложения и одной операции вычитания для каждой ячейки.",[9256,39050,39051,39071],{},[9259,39052,39053],{},[9262,39054,39055,39057,39059,39061,39063,39065,39067,39069],{},[9265,39056],{},[9265,39058,3302],{},[9265,39060,1192],{},[9265,39062,651],{},[9265,39064,971],{},[9265,39066,762],{},[9265,39068,856],{},[9265,39070,742],{},[9275,39072,39073,39095,39115,39135,39155,39176,39196],{},[9262,39074,39075,39079,39082,39084,39087,39089,39091,39093],{},[9280,39076,39077],{},[800,39078,3302],{},[9280,39080,39081],{},"xy",[9280,39083,39081],{},[9280,39085,39086],{},"x",[9280,39088],{},[9280,39090],{},[9280,39092],{},[9280,39094],{},[9262,39096,39097,39101,39103,39105,39107,39109,39111,39113],{},[9280,39098,39099],{},[800,39100,1192],{},[9280,39102,39081],{},[9280,39104,39081],{},[9280,39106,39086],{},[9280,39108],{},[9280,39110],{},[9280,39112],{},[9280,39114],{},[9262,39116,39117,39121,39123,39125,39127,39129,39131,39133],{},[9280,39118,39119],{},[800,39120,651],{},[9280,39122,39081],{},[9280,39124,39081],{},[9280,39126,39086],{},[9280,39128],{},[9280,39130],{},[9280,39132],{},[9280,39134],{},[9262,39136,39137,39141,39143,39145,39147,39149,39151,39153],{},[9280,39138,39139],{},[800,39140,971],{},[9280,39142,39081],{},[9280,39144,39081],{},[9280,39146,39086],{},[9280,39148],{},[9280,39150],{},[9280,39152],{},[9280,39154],{},[9262,39156,39157,39161,39164,39166,39168,39170,39172,39174],{},[9280,39158,39159],{},[800,39160,762],{},[9280,39162,39163],{},"y",[9280,39165,39163],{},[9280,39167,1192],{},[9280,39169],{},[9280,39171],{},[9280,39173],{},[9280,39175],{},[9262,39177,39178,39182,39184,39186,39188,39190,39192,39194],{},[9280,39179,39180],{},[800,39181,856],{},[9280,39183],{},[9280,39185],{},[9280,39187],{},[9280,39189],{},[9280,39191],{},[9280,39193],{},[9280,39195],{},[9262,39197,39198,39202,39204,39206,39208,39210,39212,39214],{},[9280,39199,39200],{},[800,39201,742],{},[9280,39203],{},[9280,39205],{},[9280,39207],{},[9280,39209],{},[9280,39211],{},[9280,39213],{},[9280,39215],{},[415,39217,39218],{},"Теперь мы знаем, как создавать массив \"частичных сумм\", но что это дает?\nЭто позволяет быстро вычислять сумму элементов любого прямоугольника.\nПредположим, что нам нужна сумма для прямоугольника, координаты левого верхнего угла которого — (1, 3), а правого нижнего — (5, 5).\nНельзя просто использовать значение 10 в ячейке (5, 5).\nПомимо суммы ячеек нужного прямоугольника оно включает также элементы, находящиеся выше и слева.\nОднако, как и в одномерном случае, можно вычислить необходимое значение, чтобы оно включало элементы только интересующего нас прямоугольника.\nДанная операция отражена в таблице ниже, где ячейки нужного прямоугольника отмечены звездочками.\nНа этот раз нужно вычесть ячейки, включающие x, и ячейки, включающие y.\nСумму ячеек x содержит ячейка (0, 5), а ячеек y — (5, 2).\nНо вычитанием обеих этих сумм мы дважды вычтем ячейки xy, поэтому нужно прибавить значение ячейки (0, 2).\nТаким образом, получается 10 – 2 – 8 + (–1) = –1, что и является суммой ячеек нужного прямоугольника.",[9256,39220,39221,39241],{},[9259,39222,39223],{},[9262,39224,39225,39227,39229,39231,39233,39235,39237,39239],{},[9265,39226],{},[9265,39228,3302],{},[9265,39230,1192],{},[9265,39232,651],{},[9265,39234,971],{},[9265,39236,762],{},[9265,39238,856],{},[9265,39240,742],{},[9275,39242,39243,39263,39283,39303,39323,39343,39363],{},[9262,39244,39245,39249,39251,39253,39255,39257,39259,39261],{},[9280,39246,39247],{},[800,39248,3302],{},[9280,39250,39081],{},[9280,39252,39081],{},[9280,39254,39081],{},[9280,39256,39086],{},[9280,39258,39086],{},[9280,39260,39086],{},[9280,39262],{},[9262,39264,39265,39269,39271,39273,39275,39277,39279,39281],{},[9280,39266,39267],{},[800,39268,1192],{},[9280,39270,39163],{},[9280,39272,39163],{},[9280,39274,39163],{},[9280,39276,1357],{},[9280,39278,1357],{},[9280,39280,1357],{},[9280,39282],{},[9262,39284,39285,39289,39291,39293,39295,39297,39299,39301],{},[9280,39286,39287],{},[800,39288,651],{},[9280,39290,39163],{},[9280,39292,39163],{},[9280,39294,39163],{},[9280,39296,1357],{},[9280,39298,1357],{},[9280,39300,1357],{},[9280,39302],{},[9262,39304,39305,39309,39311,39313,39315,39317,39319,39321],{},[9280,39306,39307],{},[800,39308,971],{},[9280,39310,39163],{},[9280,39312,39163],{},[9280,39314,39163],{},[9280,39316,1357],{},[9280,39318,1357],{},[9280,39320,1357],{},[9280,39322],{},[9262,39324,39325,39329,39331,39333,39335,39337,39339,39341],{},[9280,39326,39327],{},[800,39328,762],{},[9280,39330,39163],{},[9280,39332,39163],{},[9280,39334,39163],{},[9280,39336,1357],{},[9280,39338,1357],{},[9280,39340,1357],{},[9280,39342],{},[9262,39344,39345,39349,39351,39353,39355,39357,39359,39361],{},[9280,39346,39347],{},[800,39348,856],{},[9280,39350,39163],{},[9280,39352,39163],{},[9280,39354,39163],{},[9280,39356,1357],{},[9280,39358,1357],{},[9280,39360,1357],{},[9280,39362],{},[9262,39364,39365,39369,39371,39373,39375,39377,39379,39381],{},[9280,39366,39367],{},[800,39368,742],{},[9280,39370],{},[9280,39372],{},[9280,39374],{},[9280,39376],{},[9280,39378],{},[9280,39380],{},[9280,39382],{},[415,39384,39385],{},"Теперь можно объединить все воедино: идею с –1 и 1, построение массива частичных сумм и его использование для быстрого получения сумм прямоугольников.\nСоответствующий код дан ниже:",[422,39387,39389],{"className":424,"code":39388,"language":396,"meta":426,"style":426},"def can_make_quality(quality, r, c, h, w, q):\n    zero_one = [row[:] for row in q]\n    sum_q = [[0 for _ in range(c + 1)] for _ in range(r + 1)]\n    for i in range(r):\n        for j in range(c):\n            if q[i][j] \u003C= quality:\n                zero_one[i][j] = -1\n            else:\n                zero_one[i][j] = 1\n    for i in range(1, r + 1):\n        for j in range(1, c + 1):\n            sum_q[i][j] = zero_one[i - 1][j - 1] + sum_q[i - 1][j] + sum_q[i][j - 1] - sum_q[i - 1][j - 1]\n    for top_row in range(1, r - h + 2):\n        for left_col in range(1, c - w + 2):\n            bottom_row = top_row + h - 1\n            right_col = left_col + w - 1\n            total = sum_q[bottom_row][right_col] - sum_q[top_row-1][right_col] - sum_q[bottom_row][left_col-1] + sum_q[top_row-1][left_col-1]\n            if total \u003C= 0:\n                return True\n    return False\n",[428,39390,39391,39399,39415,39460,39472,39484,39494,39504,39510,39518,39541,39564,39626,39652,39678,39694,39710,39759,39771,39777],{"__ignoreMap":426},[431,39392,39393,39395,39397],{"class":433,"line":434},[431,39394,6330],{"class":654},[431,39396,38136],{"class":6333},[431,39398,38139],{"class":441},[431,39400,39401,39403,39405,39407,39409,39411,39413],{"class":433,"line":452},[431,39402,38144],{"class":441},[431,39404,1189],{"class":654},[431,39406,38149],{"class":441},[431,39408,14329],{"class":654},[431,39410,22907],{"class":441},[431,39412,14421],{"class":654},[431,39414,38158],{"class":441},[431,39416,39417,39420,39422,39424,39426,39429,39431,39433,39435,39437,39439,39441,39444,39446,39448,39450,39452,39454,39456,39458],{"class":433,"line":578},[431,39418,39419],{"class":441},"    sum_q ",[431,39421,1189],{"class":654},[431,39423,22296],{"class":441},[431,39425,3302],{"class":437},[431,39427,39428],{"class":654}," for",[431,39430,14600],{"class":441},[431,39432,14421],{"class":654},[431,39434,14424],{"class":437},[431,39436,37521],{"class":441},[431,39438,802],{"class":654},[431,39440,1032],{"class":437},[431,39442,39443],{"class":441},")] ",[431,39445,14329],{"class":654},[431,39447,14600],{"class":441},[431,39449,14421],{"class":654},[431,39451,14424],{"class":437},[431,39453,37496],{"class":441},[431,39455,802],{"class":654},[431,39457,1032],{"class":437},[431,39459,30591],{"class":441},[431,39461,39462,39464,39466,39468,39470],{"class":433,"line":584},[431,39463,14745],{"class":654},[431,39465,12664],{"class":441},[431,39467,14421],{"class":654},[431,39469,14424],{"class":437},[431,39471,38171],{"class":441},[431,39473,39474,39476,39478,39480,39482],{"class":433,"line":1244},[431,39475,33447],{"class":654},[431,39477,30695],{"class":441},[431,39479,14421],{"class":654},[431,39481,14424],{"class":437},[431,39483,38184],{"class":441},[431,39485,39486,39488,39490,39492],{"class":433,"line":1985},[431,39487,33458],{"class":654},[431,39489,38191],{"class":441},[431,39491,12667],{"class":654},[431,39493,38196],{"class":441},[431,39495,39496,39498,39500,39502],{"class":433,"line":2041},[431,39497,38201],{"class":441},[431,39499,1189],{"class":654},[431,39501,981],{"class":654},[431,39503,38208],{"class":437},[431,39505,39506,39508],{"class":433,"line":4018},[431,39507,38213],{"class":654},[431,39509,8102],{"class":441},[431,39511,39512,39514,39516],{"class":433,"line":4030},[431,39513,38201],{"class":441},[431,39515,1189],{"class":654},[431,39517,3916],{"class":437},[431,39519,39520,39522,39524,39526,39528,39530,39532,39535,39537,39539],{"class":433,"line":4419},[431,39521,14745],{"class":654},[431,39523,12664],{"class":441},[431,39525,14421],{"class":654},[431,39527,14424],{"class":437},[431,39529,442],{"class":441},[431,39531,1192],{"class":437},[431,39533,39534],{"class":441},", r ",[431,39536,802],{"class":654},[431,39538,1032],{"class":437},[431,39540,7381],{"class":441},[431,39542,39543,39545,39547,39549,39551,39553,39555,39558,39560,39562],{"class":433,"line":4436},[431,39544,33447],{"class":654},[431,39546,30695],{"class":441},[431,39548,14421],{"class":654},[431,39550,14424],{"class":437},[431,39552,442],{"class":441},[431,39554,1192],{"class":437},[431,39556,39557],{"class":441},", c ",[431,39559,802],{"class":654},[431,39561,1032],{"class":437},[431,39563,7381],{"class":441},[431,39565,39566,39569,39571,39574,39576,39578,39581,39583,39585,39587,39589,39592,39594,39596,39599,39601,39604,39606,39608,39610,39612,39614,39616,39618,39620,39622,39624],{"class":433,"line":4446},[431,39567,39568],{"class":441},"            sum_q[i][j] ",[431,39570,1189],{"class":654},[431,39572,39573],{"class":441}," zero_one[i ",[431,39575,853],{"class":654},[431,39577,1032],{"class":437},[431,39579,39580],{"class":441},"][j ",[431,39582,853],{"class":654},[431,39584,1032],{"class":437},[431,39586,4049],{"class":441},[431,39588,802],{"class":654},[431,39590,39591],{"class":441}," sum_q[i ",[431,39593,853],{"class":654},[431,39595,1032],{"class":437},[431,39597,39598],{"class":441},"][j] ",[431,39600,802],{"class":654},[431,39602,39603],{"class":441}," sum_q[i][j ",[431,39605,853],{"class":654},[431,39607,1032],{"class":437},[431,39609,4049],{"class":441},[431,39611,853],{"class":654},[431,39613,39591],{"class":441},[431,39615,853],{"class":654},[431,39617,1032],{"class":437},[431,39619,39580],{"class":441},[431,39621,853],{"class":654},[431,39623,1032],{"class":437},[431,39625,3568],{"class":441},[431,39627,39628,39630,39632,39634,39636,39638,39640,39642,39644,39646,39648,39650],{"class":433,"line":4451},[431,39629,14745],{"class":654},[431,39631,37489],{"class":441},[431,39633,14421],{"class":654},[431,39635,14424],{"class":437},[431,39637,442],{"class":441},[431,39639,1192],{"class":437},[431,39641,39534],{"class":441},[431,39643,853],{"class":654},[431,39645,37501],{"class":441},[431,39647,802],{"class":654},[431,39649,689],{"class":437},[431,39651,7381],{"class":441},[431,39653,39654,39656,39658,39660,39662,39664,39666,39668,39670,39672,39674,39676],{"class":433,"line":4086},[431,39655,33447],{"class":654},[431,39657,37514],{"class":441},[431,39659,14421],{"class":654},[431,39661,14424],{"class":437},[431,39663,442],{"class":441},[431,39665,1192],{"class":437},[431,39667,39557],{"class":441},[431,39669,853],{"class":654},[431,39671,37526],{"class":441},[431,39673,802],{"class":654},[431,39675,689],{"class":437},[431,39677,7381],{"class":441},[431,39679,39680,39682,39684,39686,39688,39690,39692],{"class":433,"line":4477},[431,39681,37537],{"class":441},[431,39683,1189],{"class":654},[431,39685,37489],{"class":441},[431,39687,802],{"class":654},[431,39689,37501],{"class":441},[431,39691,853],{"class":654},[431,39693,3916],{"class":437},[431,39695,39696,39698,39700,39702,39704,39706,39708],{"class":433,"line":4482},[431,39697,37554],{"class":441},[431,39699,1189],{"class":654},[431,39701,37514],{"class":441},[431,39703,802],{"class":654},[431,39705,37526],{"class":441},[431,39707,853],{"class":654},[431,39709,3916],{"class":437},[431,39711,39712,39714,39716,39719,39721,39724,39726,39728,39731,39733,39736,39738,39740,39742,39744,39746,39748,39750,39753,39755,39757],{"class":433,"line":4488},[431,39713,38304],{"class":441},[431,39715,1189],{"class":654},[431,39717,39718],{"class":441}," sum_q[bottom_row][right_col] ",[431,39720,853],{"class":654},[431,39722,39723],{"class":441}," sum_q[top_row",[431,39725,853],{"class":654},[431,39727,1192],{"class":437},[431,39729,39730],{"class":441},"][right_col] ",[431,39732,853],{"class":654},[431,39734,39735],{"class":441}," sum_q[bottom_row][left_col",[431,39737,853],{"class":654},[431,39739,1192],{"class":437},[431,39741,4049],{"class":441},[431,39743,802],{"class":654},[431,39745,39723],{"class":441},[431,39747,853],{"class":654},[431,39749,1192],{"class":437},[431,39751,39752],{"class":441},"][left_col",[431,39754,853],{"class":654},[431,39756,1192],{"class":437},[431,39758,3568],{"class":441},[431,39760,39761,39763,39765,39767,39769],{"class":433,"line":4505},[431,39762,33458],{"class":654},[431,39764,38354],{"class":441},[431,39766,12667],{"class":654},[431,39768,9744],{"class":437},[431,39770,8102],{"class":441},[431,39772,39773,39775],{"class":433,"line":12871},[431,39774,35803],{"class":654},[431,39776,10188],{"class":437},[431,39778,39779,39781],{"class":433,"line":2874},[431,39780,6599],{"class":654},[431,39782,14187],{"class":437},[415,39784,39785,39786,39788,39789,39792,39793,39795,39796,39888],{},"Вначале создается массив ",[428,39787,38389],{},", в точности как это делалось ранее в коде выше.\nВторым шагом идет создание массива частичных сумм ",[428,39790,39791],{},"sum_q",".\nМы будем использовать индексы, начинающиеся с 1, а не с 0, чтобы не пришлось беспокоиться о возможном выходе за границы массива при обработке ячеек в строке 0 или столбце 0.\nНа третьем шаге массив частичных сумм используется для быстрого вычисления суммы каждого прямоугольника.\nОбратите внимание, что любой прямоугольник здесь суммируется за одинаковое время.\nНа втором шаге мы выполнили предварительную обработку, которая в дальнейшем позволит узнать сумму для любого прямоугольника,\nне тратя времени на сложение всех его элементов.\nПо сравнению с кодом ранее мы удалили из циклов ",[428,39794,14329],{}," два уровня вложения.\nСледовательно, у нас получился алгоритм ",[33809,39797,39799],{"className":39798,"jax":33813},[33812],[33815,39800,39802,39831],{"style":35005,"xmlns":33818,"width":37885,"height":37685,"role":15324,"focusable":33821,"viewBox":39801,"xmlnsXLink":33823},"0 -833.9 5271.6 1083.9",[33825,39803,39804,39807,39810,39813,39816,39818,39821,39824,39827],{},[33828,39805],{"id":39806,"d":35014},"MJX-3-TEX-I-1D442",[33828,39808],{"id":39809,"d":35018},"MJX-3-TEX-N-28",[33828,39811],{"id":39812,"d":37695},"MJX-3-TEX-I-1D45A",[33828,39814],{"id":39815,"d":33843},"MJX-3-TEX-N-32",[33828,39817],{"id":34031,"d":33831},[33828,39819],{"id":39820,"d":33835},"MJX-3-TEX-I-1D45C",[33828,39822],{"id":39823,"d":33839},"MJX-3-TEX-I-1D454",[33828,39825],{"id":39826,"d":35031},"MJX-3-TEX-N-29",[33828,39828],{"id":39829,"d":39830},"MJX-3-TEX-N-2C","M78 35T78 60T94 103T137 121Q165 121 187 96T210 8Q210 -27 201 -60T180 -117T154 -158T130 -185T117 -194Q113 -194 104 -185T95 -172Q95 -168 106 -156T131 -126T157 -76T173 -3V9L172 8Q170 7 167 6T161 3T152 1T140 0Q113 0 96 17Z",[33849,39832,39833],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,39834,39835,39840,39845,39859,39863,39868,39873,39877,39882],{"dataMmlNode":33855},[33849,39836,39837],{"dataMmlNode":33858},[33860,39838],{"dataC":35053,"xLinkHref":39839},"#MJX-3-TEX-I-1D442",[33849,39841,39842],{"dataMmlNode":34206,"transform":35057},[33860,39843],{"dataC":35060,"xLinkHref":39844},"#MJX-3-TEX-N-28",[33849,39846,39847,39852],{"dataMmlNode":34252,"transform":35064},[33849,39848,39849],{"dataMmlNode":33858},[33860,39850],{"dataC":37740,"xLinkHref":39851},"#MJX-3-TEX-I-1D45A",[33849,39853,39854],{"dataMmlNode":33955,"transform":37744,"dataMjxTexclass":33956},[33849,39855,39856],{"dataMmlNode":33883},[33860,39857],{"dataC":33887,"xLinkHref":39858},"#MJX-3-TEX-N-32",[33849,39860,39861],{"dataMmlNode":33858,"transform":37944},[33860,39862],{"dataC":33862,"xLinkHref":34050},[33849,39864,39865],{"dataMmlNode":33858,"transform":37949},[33860,39866],{"dataC":33869,"xLinkHref":39867},"#MJX-3-TEX-I-1D45C",[33849,39869,39870],{"dataMmlNode":33858,"transform":37954},[33860,39871],{"dataC":33879,"xLinkHref":39872},"#MJX-3-TEX-I-1D454",[33849,39874,39875],{"dataMmlNode":33858,"transform":37959},[33860,39876],{"dataC":37740,"xLinkHref":39851},[33849,39878,39879],{"dataMmlNode":34206,"transform":37964},[33860,39880],{"dataC":30851,"xLinkHref":39881},"#MJX-3-TEX-N-29",[33849,39883,39884],{"dataMmlNode":34206,"transform":37970},[33860,39885],{"dataC":39886,"xLinkHref":39887},"2C","#MJX-3-TEX-N-2C"," который достаточно быстр.\nПопробуйте! А потом советую немного передохнуть, так как нас ждет еще одна серьезная задача.",[458,39890,39892],{"id":39891},"задача-4-двери-пещеры","Задача 4. Двери пещеры",[415,39894,39895],{},"Рассмотрим задачу, в которой двоичный поиск будет использоваться не для нахождения оптимального решения, а для выделения нужного элемента.",[12129,39897,35333],{"id":39898},"условие-3",[415,39900,39901,39902,39905,39906,39908],{},"Вы стоите перед входом в длинную узкую пещеру, через которую необходимо пробраться и достичь выхода.\nНа пути нужно пройти через n дверей: первая — это дверь 0, вторая — дверь 1 и т. д.\nКаждая дверь может быть открыта либо закрыта.\nЧерез открытые двери можно пройти, через закрытые — нельзя.\nТаким образом, если двери 0 и 1 открыты, а дверь 2 закрыта, то можно пройти только до двери 2,\nпричем вы не видите состояния следующих за ней дверей.\nУ входа в пещеру установлена панель с n рычагов.\nКак и двери, рычаги пронумерованы, начиная с 0. Каждый из них может быть в верхнем (0) или нижнем (1) положении.\nПри этом каждый рычаг связан с одной дверью, определяя, закрыта она или открыта.\nЕсли рычаг установлен в правильное положение, то соответствующая дверь открыта.\nВ противном случае эта дверь закрыта. Вам не известны ни связь рычагов с дверьми, ни правильные положения рычагов.\nК примеру, возможно, что рычаг 0 связан с дверью 5 и для ее открывания должен находиться в нижнем положении,\nа рычаг 1 связан с дверью 0 и для ее открывания должен находиться в верхнем положении.\nМожно устанавливать рычаги в желаемое положение, а затем проходить в пещеру для определения первой закрытой двери и возвращаться.\nПри этом запаса сил вам хватит максимум на 70 000 таких циклов.\nЦель — определить верное положение(0 или 1) каждого рычага и связанную с ним дверь.\nНужно написать следующую функцию: ",[428,39903,39904],{},"exploreCave(n)",".\nЗдесь ",[428,39907,33806],{}," является количеством дверей и рычагов (от 1 до 5000).\nДля реализации этой функции нужно будет вызвать две функции, предоставленные судьей.\nОни будут описаны далее.",[12129,39910,35361],{"id":39911},"входные-данные-3",[415,39913,39914,39915,39918,39919,39921,39922,39925,39926,39929,39930,39933,39934,39937],{},"Из стандартного ввода мы ничего не считываем.\nЕдинственный способ узнать исходные данные — это вызвать предоставленную судьей функцию tryCombination.\nВот ее сигнатура: ",[428,39916,39917],{},"tryCombination(switch_positions)",".\nПараметр switch_positions является массивом с длиной ",[428,39920,33806],{}," целых чисел, указывающим положение (0 или 1) каждого рычага.\nТо есть ",[428,39923,39924],{},"switch_positions[0]"," определяет положение рычага 0, ",[428,39927,39928],{},"switch_positions[1]"," — положение рычага 1 и т. д.\nФункция ",[428,39931,39932],{},"tryCombination"," симулирует ситуацию, в которой мы устанавливаем рычаги в ",[428,39935,39936],{},"switch_positions"," и проходим по пещере до первой закрытой двери.\nОна возвращает номер первой закрытой двери либо -1, если все двери открыты.",[12129,39939,35406],{"id":39940},"выходные-данные-3",[415,39942,39943,39944,39947,39948,39951,39952,39954,39955,39957,39958,39961,39962,39965,39966,39969,39970,39972],{},"В стандартный вывод запись не производится. Вместо этого мы отправляем ответ через вызов функции answer, также предоставленной судейским ресурсом.\nВот ее сигнатура: ",[428,39945,39946],{},"answer(switch_positions, door_for_switch)",".\nУ нас есть только одна попытка: при вызове ",[428,39949,39950],{},"answer"," наша программа уничтожается, так что правильный ответ следует отправлять с первого раза.\nПараметр ",[428,39953,39936],{}," — массив, содержащий предлагаемые нами положения рычагов в том же формате, что и ",[428,39956,39932],{},".\nПараметр ",[428,39959,39960],{},"door_for_switch"," содержит предлагаемые нами связи между рычагами и дверьми: ",[428,39963,39964],{},"door_for_switch[0]"," указывает дверь, связанную с рычагом 0,\n",[428,39967,39968],{},"door_for_switch[1]"," указывает дверь, связанную с рычагом 1, и т. д.\nВ данном случае ограничено не время, а количество вызовов ",[428,39971,39932],{},", которых допускается сделать на более 70 000.\nВ случае превышения этого значения программа завершается.",[12129,39974,35413],{"id":39975},"решение-3",[415,39977,39978],{},"Автор задачи разделил ее на пять подзадач. Пятая подзадача — это задача в общем виде.\nДругие подзадачи имеют дополнительные ограничения, упрощая решение.\nМне нравится, когда авторы задач используют подзадачи, особенно если у меня возникают сложности с поиском решения.\nВ таких случаях можно поочередно разделываться с каждой подзадачей, постепенно дорабатывая решение, пока не будет решена вся задача.\nПервая подзадача состоит в решении варианта, где каждый рычаг i связан с дверью под номером i.\nЭто значит, что рычаг 0 связан с дверью 0, рычаг 1 с дверью 1 и т. д.\nНам же нужно определить верное положение (0 или 1) для каждого рычага.",[415,39980,39981,39982,3228,39984,39986],{},"Начнем с подзадачи 1, чтобы иметь возможность вызывать судейские функции ",[428,39983,39932],{},[428,39985,39950],{},", а уже потом приступим к другим частям основной задачи.\nУ нас нет доступа к судейским функциям, но мы хотим протестировать свою работу локально.\nМожно запросить в Google «IOI 2013 tasks» и найти тестовые данные с шаблонами для задачи Cave. Вот пример:",[415,39988,39989],{},[15324,39990],{"alt":39991,"src":39992},"Задача 4. Пример","\u002Fimages\u002Fblog\u002Fpython\u002Fst25\u002Fimg2.png",[415,39994,39995],{},"Данные оценщика для тестового примера:",[422,39997,39999],{"className":1436,"code":39998,"language":1438,"meta":426,"style":426},"4\n1110\n3102\n",[428,40000,40001,40005,40010],{"__ignoreMap":426},[431,40002,40003],{"class":433,"line":434},[431,40004,36270],{},[431,40006,40007],{"class":433,"line":452},[431,40008,40009],{},"1110\n",[431,40011,40012],{"class":433,"line":578},[431,40013,40014],{},"3102\n",[697,40016,40017,40020,40023],{},[700,40018,40019],{},"1 строка: N – количество дверей и переключателей;",[700,40021,40022],{},"2 строка: S[0]...S[3] – правильное положение переключателей с индексами 0-3;",[700,40024,40025],{},"3 строка: D[0]...D[3] – дверь, к которой подключен переключатель с индексами 0-3;",[415,40027,40028],{},[1355,40029,40030],{},[800,40031,40032],{},"ПРИМЕР СЕАНСА",[9256,40034,40035,40047],{},[9259,40036,40037],{},[9262,40038,40039,40041,40044],{},[9265,40040,4775],{},[9265,40042,40043],{},"Возврат",[9265,40045,40046],{},"Пояснение",[9275,40048,40049,40059,40069,40079],{},[9262,40050,40051,40054,40056],{},[9280,40052,40053],{},"tryCombination([1,0,1,1])",[9280,40055,1192],{},[9280,40057,40058],{},"Это соответствует изображению. Переключатели 0, 2 и 3 опущены, а переключатель 1 поднят. Функция возвращает 1, что означает, что дверь 1 — первая закрытая дверь слева.",[9262,40060,40061,40064,40066],{},[9280,40062,40063],{},"tryCombination([0,1,1,0])",[9280,40065,971],{},[9280,40067,40068],{},"Двери 0, 1 и 2 открыты, а дверь 3 закрыта.",[9262,40070,40071,40074,40076],{},[9280,40072,40073],{},"tryCombination([1,1,1,0])",[9280,40075,38441],{},[9280,40077,40078],{},"Перемещение переключателя 0 вниз приводит к открытию всех дверей, что подтверждается возвращаемым значением 1.",[9262,40080,40081,40084,40087],{},[9280,40082,40083],{},"answer([1,1,1,0],[3,1,0,2])",[9280,40085,40086],{},"выход из программы",[9280,40088,40089],{},"Мы предполагаем, что правильная комбинация — [1,1,1,0], и что переключатели 0, 1, 2 и 3 подключаются к дверям 3, 1, 0 и 2 соответственно.",[415,40091,40092],{},[1355,40093,40094],{},[800,40095,40096],{},"Эта задача стандартно решается на C\u002FC++ мы попробуем её также решить, но на Python.",[415,40098,40099],{},"Напишем код для подзадачи 1:",[422,40101,40103],{"className":424,"code":40102,"language":396,"meta":426,"style":426},"def exploreCave(n):\n  switch_positions = [0 for _ in range(n)]\n  door_for_switch = [i for i in range(n)]\n  for i in range(n):\n    result = tryCombination(switch_positions)\n    if result == i: # дверь i закрыта\n      switch_positions[i] = 1\n  answer(switch_positions, door_for_switch)\n",[428,40104,40105,40114,40136,40155,40167,40176,40190,40199],{"__ignoreMap":426},[431,40106,40107,40109,40112],{"class":433,"line":434},[431,40108,6330],{"class":654},[431,40110,40111],{"class":6333}," exploreCave",[431,40113,12523],{"class":441},[431,40115,40116,40119,40121,40123,40125,40127,40129,40131,40133],{"class":433,"line":452},[431,40117,40118],{"class":441},"  switch_positions ",[431,40120,1189],{"class":654},[431,40122,17401],{"class":441},[431,40124,3302],{"class":437},[431,40126,39428],{"class":654},[431,40128,14600],{"class":441},[431,40130,14421],{"class":654},[431,40132,14424],{"class":437},[431,40134,40135],{"class":441},"(n)]\n",[431,40137,40138,40141,40143,40145,40147,40149,40151,40153],{"class":433,"line":578},[431,40139,40140],{"class":441},"  door_for_switch ",[431,40142,1189],{"class":654},[431,40144,30573],{"class":441},[431,40146,14329],{"class":654},[431,40148,12664],{"class":441},[431,40150,14421],{"class":654},[431,40152,14424],{"class":437},[431,40154,40135],{"class":441},[431,40156,40157,40159,40161,40163,40165],{"class":433,"line":584},[431,40158,20523],{"class":654},[431,40160,12664],{"class":441},[431,40162,14421],{"class":654},[431,40164,14424],{"class":437},[431,40166,12523],{"class":441},[431,40168,40169,40171,40173],{"class":433,"line":1244},[431,40170,6796],{"class":441},[431,40172,1189],{"class":654},[431,40174,40175],{"class":441}," tryCombination(switch_positions)\n",[431,40177,40178,40180,40182,40184,40187],{"class":433,"line":1985},[431,40179,10438],{"class":654},[431,40181,13434],{"class":441},[431,40183,8409],{"class":654},[431,40185,40186],{"class":441}," i: ",[431,40188,40189],{"class":455},"# дверь i закрыта\n",[431,40191,40192,40195,40197],{"class":433,"line":2041},[431,40193,40194],{"class":441},"      switch_positions[i] ",[431,40196,1189],{"class":654},[431,40198,3916],{"class":437},[431,40200,40201],{"class":433,"line":4018},[431,40202,40203],{"class":441},"  answer(switch_positions, door_for_switch)\n",[415,40205,40206],{},"Вначале положение каждого рычага устанавливается на 0, и дверь i связывается с рычагом i.\nПоложения рычагов мы будем обновлять при необходимости, а вот связь рычаг–дверь в данном случае (согласно ограничениям подзадачи) трогать не потребуется.\nЦикл for перебирает каждый рычаг. Его задача — определить, должен ли текущий рычаг остаться в положении 0 или переключиться в положение 1.\nРассмотрим первую итерацию, когда i равно 0. Вначале происходит вызов tryCombination, которая возвращает номер первой закрытой двери.\nЕсли возвращается 0, то рычаг 0 установлен неправильно.\nЕсли этот рычаг будет установлен верно, то дверь 0 окажется открыта и tryCombination вернет ненулевой номер двери.\nЕсли дверь 0 оказывается закрыта, мы изменяем положение рычага 0 с 0 на 1.\nВ результате дверь 0 открывается, и можно продвигаться к двери 1.\nНа следующем шаге i становится равной 1 и снова вызывается tryCombination.\nРезультат 0 в данном случае точно не вернется, потому что код уже проделал работу, гарантирующую открывание двери 0.\nЕсли возвращается 1, это означает, что дверь 1 закрыта и нужно изменить положение рычага 1 с 0 на 1.\nОбобщая, можно сказать, что в начале новой итерации цикла все двери до i (включая i – 1) открыты.\nЕсли дверь i закрыта, то мы изменяем положение рычага i с 0 на 1.\nЕсли дверь i уже открыта, значит, рычаг i установлен верно.\nЗакончив второй цикл for, мы выяснили верное положение каждого рычага.\nЭтот ответ мы передаем судейскому ресурсу через вызов функции answer.",[415,40208,40209],{},"Итак, в подзадаче 1 мы точно узнаём, какая дверь с каким рычагом связана.\nДля определения данного соответствия не требовалось выполнять поиск, но для решения всей задачи поиск нам понадобится,\nтак как неизвестно, какой рычаг за какую дверь отвечает.\nМы начнем с закрывания двери 0, после чего займемся перебором рычагов, чтобы открыть ее.\nДля этого будем последовательно изменять положение рычагов, проверяя, открылась или нет дверь 0.\nЕсли нет, то рычаг выбран ошибочно. Если же дверь 0 открылась, значит, связанный с ней рычаг найден.\nС этого момента дверь 0 остается открытой, и тот же процесс повторяется для двери 1:\nвначале она закрывается, а затем перебираются оставшиеся рычаги в поиске того, который ее откроет.",[415,40211,40212],{},"Начнем с нового кода exploreCave, приведенного ниже. Он краток, потому что перекладывает поиск на вспомогательную функцию.",[422,40214,40216],{"className":424,"code":40215,"language":396,"meta":426,"style":426},"def exploreCave(n):\n  switch_positions = [0 for _ in range(n)]\n  door_for_switch = [-1 for i in range(n)]\n  for i in range(n):\n    set_a_switch(i, switch_positions, door_for_switch, n)\n  answer(switch_positions, door_for_switch)\n",[428,40217,40218,40226,40246,40268,40280,40285],{"__ignoreMap":426},[431,40219,40220,40222,40224],{"class":433,"line":434},[431,40221,6330],{"class":654},[431,40223,40111],{"class":6333},[431,40225,12523],{"class":441},[431,40227,40228,40230,40232,40234,40236,40238,40240,40242,40244],{"class":433,"line":452},[431,40229,40118],{"class":441},[431,40231,1189],{"class":654},[431,40233,17401],{"class":441},[431,40235,3302],{"class":437},[431,40237,39428],{"class":654},[431,40239,14600],{"class":441},[431,40241,14421],{"class":654},[431,40243,14424],{"class":437},[431,40245,40135],{"class":441},[431,40247,40248,40250,40252,40254,40256,40258,40260,40262,40264,40266],{"class":433,"line":578},[431,40249,40140],{"class":441},[431,40251,1189],{"class":654},[431,40253,17401],{"class":441},[431,40255,853],{"class":654},[431,40257,1192],{"class":437},[431,40259,39428],{"class":654},[431,40261,12664],{"class":441},[431,40263,14421],{"class":654},[431,40265,14424],{"class":437},[431,40267,40135],{"class":441},[431,40269,40270,40272,40274,40276,40278],{"class":433,"line":584},[431,40271,20523],{"class":654},[431,40273,12664],{"class":441},[431,40275,14421],{"class":654},[431,40277,14424],{"class":437},[431,40279,12523],{"class":441},[431,40281,40282],{"class":433,"line":1244},[431,40283,40284],{"class":441},"    set_a_switch(i, switch_positions, door_for_switch, n)\n",[431,40286,40287],{"class":433,"line":1985},[431,40288,40203],{"class":441},[415,40290,40291,40292,40294,40295,40297,40298,40300,40301,40303,40304,40306,40307,40309,40310,40313],{},"Как и при решении подзадачи 1, каждый элемент ",[428,40293,39936],{}," будет хранить значения указывающие положение каждого рычага.\nПоложение всех рычагов устанавливается как ",[428,40296,3302],{},"(если рычаг уже связан с дверью, его положение больше никогда не должно меняться).\nМассив ",[428,40299,39960],{}," указывает, какая дверь с каким рычагом соединена.\nИзначально каждый элемент ",[428,40302,39960],{}," инициализируется как ",[428,40305,38441],{},", поскольку все связи дверей с рычагами неизвестны.\nКогда становится известна связанная с рычагом ",[428,40308,19459],{}," дверь, ",[428,40311,40312],{},"door_for_switch[i]"," должен будет обновляться.",[415,40315,40316],{},"А вот контрольный вопрос: если door_for_switch[5] равна 6, то что это значит?\nЗначит ли это, что рычаг 5 связан с дверью 6 или что дверь 5 связана с рычагом 6?\nПервый вариант! Запомните это, прежде чем продолжать.",[415,40318,40319,40320,40322,40323,40326],{},"Для каждой двери ",[428,40321,19459],{}," мы вызываем вспомогательную функцию ",[428,40324,40325],{},"set_a_switch",".\nЕе задача — выполнить поиск по рычагам и найти связанный с дверью i.\nОна также определяет, должен рычаг находиться в положении 0 или 1.",[34980,40328,37981],{"id":40329},"двоичный-поиск-1",[415,40331,40332],{},"Числа 5000 (максимальное количество дверей) и 70 000 (максимум попыток подбора) тонко намекают на необходимость применения для решения стратегии двоичного поиска.\nОбратите внимание, что lb5000 округляется до 13.\nЕсли мы найдем способ использовать двоичный поиск, то он сможет подбирать верный рычаг для текущей двери всего за 13 шагов, но никак не за 5000(линейный поиск).\nЕсли на каждую дверь нам потребуется по 13 шагов, то при 5000 дверей получится 13 × 5000 = 65 000 шагов в общем.\nТаким образом, мы впишемся в лимит 70 000.",[415,40334,40335],{},"Как же здесь использовать двоичный поиск? Процесс должен позволить отбрасывать на каждом шаге половину диапазона рычагов.\nПоясню идею на примере. Предположим, что у нас восемь дверей и восемь рычагов, а также что дверь 0 в текущий момент закрыта.\nЕсли мы переключим рычаг 0 и дверь 0 не откроется, то из этого мы поймем немногое: только то, что рычаг 0 не связан с дверью 0\n(все равно что сказать «1» при угадывании загаданного кем-то числа между 1 и 1000).\nБолее удачной идеей будет переключить половину рычагов, так что давайте переключим рычаги 0, 1, 2 и 3.\nНезависимо от того, как это повлияет на дверь 0, мы узнаем уже очень многое.\nЕсли дверь по-прежнему останется закрыта, то рычаги с 0 по 3 к ней отношения не имеют и можно сосредоточиться на оставшейся половине рычагов с 4 по 7.\nЕсли же дверь 0 откроется, то станет ясно, что с ней связан один из рычагов с 0 по 3 и нужно более плотно сосредоточиться именно на них.\nЗа один шаг мы сразу отсекаем половину диапазона.\nПродолжая таким же путем дальнейший поиск, мы в конечном итоге определим рычаг, связанный с дверью 0 (и его положение).\nПредположим, что проделываем весь этот путь, снова и снова уменьшая диапазон рычагов в два раза, пока не останется всего один рычаг.\nДопустим, что связанным с дверью 0 оказался рычаг 6. Тогда мы установим его в положение, при котором дверь 0 будет открыта.\nВ этом положении он и останется.\nКогда далее мы перейдем к обработке двери 1 или любой другой двери впоследствии, то предусмотрительно не станем менять положение рычага 6.",[415,40337,40338],{},"Теперь я могу представить решение для этой задачи, основанное на двоичном поиске. Код set_a_switch приведен ниже:",[422,40340,40342],{"className":424,"code":40341,"language":396,"meta":426,"style":426},"def set_a_switch(door, switch_positions, door_for_switch, n):\n  low, high = 0, n - 1\n\n  result = tryCombination(switch_positions)\n  if result != door:\n    for i in range(n):\n      if door_for_switch[i] == -1:\n        switch_positions[i] = 1\n\n  while low != high:\n    mid = (low + high) \u002F\u002F 2\n    for i in range(low, mid + 1):\n      if door_for_switch[i] == -1:\n        switch_positions[i] = 1 - switch_positions[i]\n    result = tryCombination(switch_positions)\n    if result != door:\n      high = mid\n      for i in range(low, mid + 1):\n        if door_for_switch[i] == -1:\n          switch_positions[i] = 1 - switch_positions[i]\n    else:\n      low = mid + 1\n  door_for_switch[low] = door\n  switch_positions[low] = 1 - switch_positions[low]\n",[428,40343,40344,40354,40370,40374,40382,40393,40405,40421,40430,40434,40444,40460,40479,40493,40506,40514,40524,40532,40551,40565,40578,40584,40596,40606],{"__ignoreMap":426},[431,40345,40346,40348,40351],{"class":433,"line":434},[431,40347,6330],{"class":654},[431,40349,40350],{"class":6333}," set_a_switch",[431,40352,40353],{"class":441},"(door, switch_positions, door_for_switch, n):\n",[431,40355,40356,40359,40361,40363,40366,40368],{"class":433,"line":452},[431,40357,40358],{"class":441},"  low, high ",[431,40360,1189],{"class":654},[431,40362,9744],{"class":437},[431,40364,40365],{"class":441},", n ",[431,40367,853],{"class":654},[431,40369,3916],{"class":437},[431,40371,40372],{"class":433,"line":578},[431,40373,1662],{"emptyLinePlaceholder":393},[431,40375,40376,40378,40380],{"class":433,"line":584},[431,40377,23097],{"class":441},[431,40379,1189],{"class":654},[431,40381,40175],{"class":441},[431,40383,40384,40386,40388,40390],{"class":433,"line":1244},[431,40385,20480],{"class":654},[431,40387,13434],{"class":441},[431,40389,10686],{"class":654},[431,40391,40392],{"class":441}," door:\n",[431,40394,40395,40397,40399,40401,40403],{"class":433,"line":1985},[431,40396,14745],{"class":654},[431,40398,12664],{"class":441},[431,40400,14421],{"class":654},[431,40402,14424],{"class":437},[431,40404,12523],{"class":441},[431,40406,40407,40410,40413,40415,40417,40419],{"class":433,"line":2041},[431,40408,40409],{"class":654},"      if",[431,40411,40412],{"class":441}," door_for_switch[i] ",[431,40414,8409],{"class":654},[431,40416,981],{"class":654},[431,40418,1192],{"class":437},[431,40420,8102],{"class":441},[431,40422,40423,40426,40428],{"class":433,"line":4018},[431,40424,40425],{"class":441},"        switch_positions[i] ",[431,40427,1189],{"class":654},[431,40429,3916],{"class":437},[431,40431,40432],{"class":433,"line":4030},[431,40433,1662],{"emptyLinePlaceholder":393},[431,40435,40436,40438,40440,40442],{"class":433,"line":4419},[431,40437,34616],{"class":654},[431,40439,34619],{"class":441},[431,40441,10686],{"class":654},[431,40443,34624],{"class":441},[431,40445,40446,40448,40450,40452,40454,40456,40458],{"class":433,"line":4436},[431,40447,34634],{"class":441},[431,40449,1189],{"class":654},[431,40451,34504],{"class":441},[431,40453,802],{"class":654},[431,40455,34509],{"class":441},[431,40457,16854],{"class":654},[431,40459,658],{"class":437},[431,40461,40462,40464,40466,40468,40470,40473,40475,40477],{"class":433,"line":4446},[431,40463,14745],{"class":654},[431,40465,12664],{"class":441},[431,40467,14421],{"class":654},[431,40469,14424],{"class":437},[431,40471,40472],{"class":441},"(low, mid ",[431,40474,802],{"class":654},[431,40476,1032],{"class":437},[431,40478,7381],{"class":441},[431,40480,40481,40483,40485,40487,40489,40491],{"class":433,"line":4451},[431,40482,40409],{"class":654},[431,40484,40412],{"class":441},[431,40486,8409],{"class":654},[431,40488,981],{"class":654},[431,40490,1192],{"class":437},[431,40492,8102],{"class":441},[431,40494,40495,40497,40499,40501,40503],{"class":433,"line":4086},[431,40496,40425],{"class":441},[431,40498,1189],{"class":654},[431,40500,1032],{"class":437},[431,40502,981],{"class":654},[431,40504,40505],{"class":441}," switch_positions[i]\n",[431,40507,40508,40510,40512],{"class":433,"line":4477},[431,40509,6796],{"class":441},[431,40511,1189],{"class":654},[431,40513,40175],{"class":441},[431,40515,40516,40518,40520,40522],{"class":433,"line":4482},[431,40517,10438],{"class":654},[431,40519,13434],{"class":441},[431,40521,10686],{"class":654},[431,40523,40392],{"class":441},[431,40525,40526,40528,40530],{"class":433,"line":4488},[431,40527,34697],{"class":441},[431,40529,1189],{"class":654},[431,40531,34677],{"class":441},[431,40533,40534,40537,40539,40541,40543,40545,40547,40549],{"class":433,"line":4505},[431,40535,40536],{"class":654},"      for",[431,40538,12664],{"class":441},[431,40540,14421],{"class":654},[431,40542,14424],{"class":437},[431,40544,40472],{"class":441},[431,40546,802],{"class":654},[431,40548,1032],{"class":437},[431,40550,7381],{"class":441},[431,40552,40553,40555,40557,40559,40561,40563],{"class":433,"line":12871},[431,40554,11471],{"class":654},[431,40556,40412],{"class":441},[431,40558,8409],{"class":654},[431,40560,981],{"class":654},[431,40562,1192],{"class":437},[431,40564,8102],{"class":441},[431,40566,40567,40570,40572,40574,40576],{"class":433,"line":2874},[431,40568,40569],{"class":441},"          switch_positions[i] ",[431,40571,1189],{"class":654},[431,40573,1032],{"class":437},[431,40575,981],{"class":654},[431,40577,40505],{"class":441},[431,40579,40580,40582],{"class":433,"line":12887},[431,40581,10575],{"class":654},[431,40583,8102],{"class":441},[431,40585,40586,40588,40590,40592,40594],{"class":433,"line":12892},[431,40587,34721],{"class":441},[431,40589,1189],{"class":654},[431,40591,34552],{"class":441},[431,40593,802],{"class":654},[431,40595,3916],{"class":437},[431,40597,40598,40601,40603],{"class":433,"line":12898},[431,40599,40600],{"class":441},"  door_for_switch[low] ",[431,40602,1189],{"class":654},[431,40604,40605],{"class":441}," door\n",[431,40607,40608,40611,40613,40615,40617],{"class":433,"line":12904},[431,40609,40610],{"class":441},"  switch_positions[low] ",[431,40612,1189],{"class":654},[431,40614,1032],{"class":437},[431,40616,981],{"class":654},[431,40618,40619],{"class":441}," switch_positions[low]\n",[415,40621,40622,40623,3228,40625,40627,40628,40631],{},"Вначале заводим переменные ",[428,40624,36035],{},[428,40626,36038],{}," необходимые для двоичного поиска и первый раз запустим функцию ",[428,40629,40630],{},"result = tryCombination(switch_positions)",".\nУстановив все еще не связанные рычаги в положение 0, мы определяем, открыта или нет текущая дверь.\nЕсли открыта, то нужно ее закрыть, чтобы потом путем поочередного изменения положения рычагов определить, какой из них ее откроет.\nДля закрывания двери мы устанавливаем все несвязанные рычаги в положение 1.\nТакой прием срабатывает, потому что, когда все рычаги находились в положении 0, дверь была открыта.\nОдин из этих рычагов связан с этой дверью, значит, при изменении их положения она точно закроется.",[415,40633,40634,40635,40637],{},"При каждой проверке условия двоичного поиска в цикле ",[428,40636,12737],{}," мы делаем так, чтобы текущая дверь была закрыта.\nВ частности, когда low и high равны и цикл завершается, дверь остается закрытой.\nТогда останется лишь изменить положение рычага low, чтобы ее открыть.",[415,40639,40640,40641,40643],{},"Теперь рассмотрим сам двоичный поиск. В каждой итерации мы вычисляем среднюю точку ",[428,40642,36082],{},", затем изменяем положение первой половины рычагов(но только тех, которые еще не связаны с дверью).\nКакой эффект это оказало на текущую дверь? Здесь есть две возможности:",[697,40645,40646,40660],{},[700,40647,40648,40651,40652,3228,40654,40656,40657,40659],{},[800,40649,40650],{},"Дверь открылась."," Теперь нам известно, что искомый рычаг находится между ",[428,40653,36035],{},[428,40655,36082],{},", значит, все рычаги больше ",[428,40658,36082],{}," отбрасываются.\nМы также возвращаем каждый рычаг между low и mid обратно в положение, предшествовавшее текущей итерации.\nВ итоге дверь снова закрывается, и можно переходить к очередной итерации.",[700,40661,40662,40665],{},[800,40663,40664],{},"Дверь осталась закрыта."," Значит, искомый рычаг находится между mid + 1 и high, поэтому мы отбрасываем все рычаги, начиная с mid и менее.\nВ данном случае никакие рычаги не переключаются, потому что дверь по-прежнему закрыта, что нам и нужно.",[415,40667,40668],{},"По завершении двоичного поиска low и high будут равны, указывая на рычаг, связанный с текущей дверью.\nТекущая дверь в этот момент будет все еще закрыта, и мы переключим найденный рычаг для ее открытия.\nМы получили чистое, быстрое решение, основанное на двоичном поиске.",[458,40670,33670],{"id":33669},[415,40672,40673],{},"Иногда найти оптимальное решение намного сложнее, чем проверить допустимость одного из его вариантов.\nСколько жидкости нужно залить в дерево? Неизвестно. Будет ли достаточно 10 литров? А вот это уже можно проверить.\nПри правильных условиях двоичный поиск способен преобразовать сложную задачу оптимизации в намного более простую задачу проверки допустимости.\nИногда это похоже на жульничество. Добавление двоичного поиска означает всего лишь необходимость учитывать дополнительный логарифмический фактор.\nНо этот фактор практически не требует ресурсов, зато взамен мы получаем более простую задачу.\nЯ не утверждаю, что двоичный поиск является единственным способом решения задач из примеров выше.\nНекоторые задачи, которые можно решить с помощью двоичного поиска, также можно решить и через динамическое программирование.\nНо двоичный поиск часто может предложить решения, которые окажутся конкурентноспособными и более простыми, чем их альтернативы.\nЕсли вам интересно, вернитесь к каждой задаче еще раз, но теперь подумайте, как можно их решить без двоичного поиска.\nИ если вы видите задачу, в которой можно использовать двоичный поиск, то не стоит сомневаться.",[1862,40675,35276],{},[1862,40677,40678],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sB1qb, html code.shiki .sB1qb{--shiki-default:#B31D28;--shiki-default-font-style:italic}",{"title":426,"searchDepth":452,"depth":1244,"links":40680},[40681],{"id":35312,"depth":452,"text":35313,"children":40682},[40683,40684,40685,40696,40706,40716,40724],{"id":35316,"depth":1244,"text":35319},{"id":35322,"depth":584,"text":35325},{"id":35328,"depth":584,"text":35329,"children":40686},[40687,40688,40689,40690],{"id":35332,"depth":1244,"text":35333},{"id":35360,"depth":1244,"text":35361},{"id":35405,"depth":1244,"text":35406},{"id":35412,"depth":1244,"text":35413,"children":40691},[40692,40693,40694,40695],{"id":35425,"depth":1985,"text":35426},{"id":35613,"depth":1985,"text":35614},{"id":35895,"depth":1985,"text":35896},{"id":36153,"depth":1985,"text":36154},{"id":36187,"depth":584,"text":36188,"children":40697},[40698,40699,40700,40701],{"id":36194,"depth":1244,"text":35333},{"id":36200,"depth":1244,"text":35361},{"id":36206,"depth":1244,"text":35406},{"id":36212,"depth":1244,"text":35413,"children":40702},[40703,40704,40705],{"id":36287,"depth":1985,"text":36288},{"id":36561,"depth":1985,"text":35896},{"id":36672,"depth":1985,"text":35426},{"id":36753,"depth":584,"text":36754,"children":40707},[40708,40709,40710,40711],{"id":36760,"depth":1244,"text":35333},{"id":36970,"depth":1244,"text":35361},{"id":37035,"depth":1244,"text":35406},{"id":37041,"depth":1244,"text":35413,"children":40712},[40713,40714,40715],{"id":37980,"depth":1985,"text":37981},{"id":38110,"depth":1985,"text":36288},{"id":38402,"depth":1985,"text":38403},{"id":39891,"depth":584,"text":39892,"children":40717},[40718,40719,40720,40721],{"id":39898,"depth":1244,"text":35333},{"id":39911,"depth":1244,"text":35361},{"id":39940,"depth":1244,"text":35406},{"id":39975,"depth":1244,"text":35413,"children":40722},[40723],{"id":40329,"depth":1985,"text":37981},{"id":33669,"depth":584,"text":33670},"2025-10-04","Примеры задач с использованием бинарного(двоичного) поиска","images\u002Fblog\u002Fpython\u002Fst25\u002Fimg.png",{},111,{"title":258,"description":40726},"kIoZJhRZoYvztfFnfni65_E9Cv93f5s_cWc-Uj6Ty04",{"id":40733,"title":262,"author":40734,"body":40736,"date":41320,"description":41321,"extension":1887,"image":41322,"meta":41323,"minRead":30788,"navigation":393,"num":25829,"path":263,"seo":41324,"stem":264,"__hash__":41325},"python\u002Fblog\u002Fpython\u002Fst26.md",{"name":402,"avatar":40735},{"src":404,"alt":405},{"type":407,"value":40737,"toc":41303},[40738,40741,40744,40756,40761,40765,40768,40772,40786,40789,40797,40801,40804,40807,40810,40814,40817,40820,40824,40831,40835,40842,40850,40854,40857,40860,40903,40908,40911,40915,40918,40921,40926,40929,40979,41055,41059,41062,41165,41168,41283,41287,41290,41296,41298,41300],[410,40739,262],{"id":40740},"сортировка-выбором",[29130,40742],{":isList":40743,"title":29133},"[\"Вы познакомитесь с массивами и связанными списками – двумя основными структурами данных.\",\"Вы изучите алгоритм сортировки выбором.\"]",[8839,40745,40746],{},[415,40747,40748,40751,40752,40755],{},[1355,40749,40750],{},"Что нужно знать прежде?"," В статье ранее про ",[1205,40753,40754],{"href":255},"бинарный поиск"," было рассмотрено такое понятие как\n\"О-большое\"(время выполнения алгоритма или объём используемой памяти который растёт с увеличением размера входных данных).\nЧтобы лучше понять эту статью, необходимо понимать смысл \"О-большого\" и логарифмов.",[415,40757,40758],{},[1355,40759,40760],{},"Прежде чем разобрать сам алгоритм сортировки выбором, необходимо разобраться как работает память компьютера и как представлена такая структура данных как массив или список.",[632,40762,40764],{"id":40763},"как-работает-память","Как работает память",[415,40766,40767],{},"Представьте, что вы пришли в кинотеатр и хотите оставить свою верхнюю одежду в гардеробе.\nДля хранения верхней одежды существуют специальные вешалки в гардеробе. На каждой вешалке помещается только одна вещь.\nВы хотите сдать к примеру две куртки, поэтому требуется выделить вам две вешалки(конечно можно попробовать обе куртки повесить на одну вешалку, но для примера представим что нельзя).\nВы оставляете свои две куртки, получаете два \"номера\" от вешалок и идёте смотреть кино.\nВ сущности, точно также работает память компьютера. Она представляет собой нечто вроде огромного гардероба со множеством вешалок и у каждой вешалки свой адрес.\nНапример: fc0addeb – адрес ячейки памяти.\nКаждый раз, когда вы хотите сохранить в памяти отдельное значение, вы запрашиваете у компьютера(процессор это делает за вас) место в памяти, а он выдаёт адрес для сохранения значения.\nЕсли же вам понадобится сохранить несколько элементов, это можно сделать двумя способами: воспользоваться массивом или списком.\nДалее рассмотрим массивы и списки, их достоинства и недостатки.\nНе существует единого мнения или единственно верного способа сохранения данных на все случаи жизни, поэтому нужно понимать различия между массивами и списками.",[632,40769,40771],{"id":40770},"массивы-и-связанные-списки","Массивы и связанные списки",[8839,40773,40774],{},[415,40775,40776,40777,4846,40780,22541,40782,4846,40784],{},"Есть про списки в Python и как их использовать статьи:\n",[1205,40778,40779],{"href":211},"Списки в циклы",[1205,40781,214],{"href":215},[1205,40783,218],{"href":219},[1205,40785,222],{"href":223},[415,40787,40788],{},"Предположим вы хотите написать приложение для списка дел и управления ими. Описание дел должны храниться в виде списка или массива в памяти.\nЧто использовать — массив или связанный список? Для начала попробуем сохранить дела в массиве.\nПри использовании массива все дела хранятся в памяти непрерывно(то есть рядом друг с другом).\nТеперь предположим, что мы хотим добавить новое дело, но следующее место в памяти для него - занято(там уже что-нибудь есть)!\nПредставьте, что вы пошли в кинотеатр вместе с друзьями и нашли места для всей своей компании, но тут вдруг приходит ещё один друг, и ему уже сесть некуда.\nПриходится искать новые места, где смогли бы разместиться все сразу! В нашем случае вам придётся запросить у компьютера другой блок памяти, в котором смогут поместиться сразу все дела.\nЕсли вдруг придёт ещё один друг, места опять не хватит и вам всем придётся снова перемещаться в поиске новых мест! Сплошная суета получается!\nВыходит, что добавление новых элементов в массив – серьёзная проблема.\nЕсли свободного места нет и вам каждый раз приходится перемещаться всей компанией друзей в новые места(делам приходится перемещаться каждый раз в новую область памяти),\nоперация добавление нового элемента или элементов будет выполниться крайне медленно.\nПростейшее решение — это \"бронирование мест\" заранее! Таким образом, если ваш список состоит всего из 4 дел, вы запрашиваете у компьютера заранее памяти на 10 дел... просто на всякий случай \"про запас\".\nТогда в массив можно будет добавить до 10 дел и ничего перемещать не придётся. Это неплохое обходное решение проблемы с массивами, но у него есть пара недостатков:",[697,40790,40791,40794],{},[700,40792,40793],{},"Если в массив будет добавлено к примеру 11 дело, а памяти было лишь на 10, то перемещать всех всё равно придётся;",[700,40795,40796],{},"Лишнее место может и не понадобиться, и тогда память будет расходоваться неэффективно. Вы её зарезервировали, однако не использовали и никто другой её использовать не может.\nВ общем, приём неплохой, но нельзя назвать его идеальным. Связанные списки решают эту проблему.",[458,40798,40800],{"id":40799},"связанные-списки","Связанные списки",[415,40802,40803],{},"При использовании связанного списка элементы могут размещаться где угодно в памяти.\nВ каждом элементе хранится адрес следующего элемента списка. Таким образом, набор произвольных адресов памяти объединяется в цепочку.\nВсё происходит как в игре \"Найди сокровище\". Нужно прийти по первому адресу, там записка: \"Следующий элемент находится по адресу 2\".\nИдём по второму адресу, там снова написано: \"Следующий элемент находится по адресу 3\" и т.д. Добавить элемент в связанный список не составляет труда:\nпросто размещаем его по любому адресу в памяти(на любое свободное место) и сохраняем этот адрес в предыдущем элементе списка.",[415,40805,40806],{},"Со связанными списками ничего перемещать в памяти не нужно. Также сама собой решается проблема, допустим вы прешли в кино с тремя друзьями.\nВы пытаетесь найти место на пятерых, но места в кинотеатре уже забиты, и найти соседних друг с другом пять мест невозможно.\nПохожая ситуация происходит также когда мы используем массив. Допустим мы пытаемся найти места на 10000 элементов.\nВ памяти можно найти места для 10000 элементов, но только не смежные друг с другом! И для создания массива уже не хватает места!\nНо при хранении данных в связанном списке вы фактически скажите: \"Окей, тогда садимся на любые свободные места и смотрим кино\".\nЕсли любое необходимое количество мест есть в памяти компьютера, вы сможете сохранить все данные в связанном списке.\nВ случае с массивом, если не можете разместить всё рядом друг с другом — \"вынуждены будите покинуть кинотеатр\"!",[415,40808,40809],{},"Если связанные списки так хороши, то зачем тогда массивы и чем они остаются также хороши?",[458,40811,40813],{"id":40812},"массивы","Массивы",[415,40815,40816],{},"На сайтах со всевозможными рейтингами, тестами и хит-парадами применяется хитрая тактика для увеличения количества просмотров.\nВместо того чтобы вывести весь список на одной странице,\nтакие сайты размещают информацию по одному элементу на страницу и заставляют пользователей нажимать на кнопку \"Далее\" для перехода к следующему элементу.\nМожет быть так, например, что рейтинг новостей не выводится на одной странице.\nВ результате просмотра всего списка новостей сайту удаётся показать вам рекламу на всех страницах пока вы нажимаете \"Далее\" или \"Показать ещё\".\nБыло бы гораздо лучше в таких случаях увидеть сразу весь список.",[415,40818,40819],{},"Похожая проблема существует и у связанных списков. Допустим, вы хотите получить последний элемент связанного списка.\nПросто прочитать нужное значение не удастся, потому что вы не знаете, по какому адресу оно хранится.\nВместо этого в связанном списке сначала придётся обратиться к элементу №1 и узнать адрес элемента №2, потом обратиться к элементу №2 и узнать адрес элемента №3... и т.д., пока не доберёмся до последнего элемента.\nСвязанные списки отлично подходят в тех ситуациях, когда данные должны читаться последовательно: сначала вы читаете один элемент, по адресу переходите к следующему.\nНо если вы хотите \"прыгать\" по списку куда угодно, то нужно выбрать массив, а не связанный список.\nРаботая с массивом вы заранее знаете адрес каждого элемента. Допустим, массив содержит пять элементов и вы знаете, что он начинается с адреса 0.\nПо какому адресу будет храниться его пятый элемент?\nПростая математика подсказывает: это адрес 4. Массивы прекрасно подходят для чтения элементов в произвольных позициях, потому что обращение к любому элементу массива происходит сразу мгновенно.\nВ связанном списке элементы не хранятся рядом друг с другом, поэтому определить адрес или позицию i-го элемента в памяти невозможно — нужно обратиться к первому элементу, затем ко второму, и потом к третьему, пока не доберёмся до i-го элемента.",[12129,40821,40823],{"id":40822},"терминология","Терминология",[415,40825,40826,40827,40830],{},"Элементы массива пронумерованы, причём нумерация начинается с 0, а не с 1. Новичков этот факт может запутывать.\nТем не менее выбор нулевой начальной позиции упрощает написание кода при работе с массивом, поэтому программисты остановились на этом варианте.\nПочти во всех языках программирования нумерация элементов массива начинается с 0.\nПозиция элемента называется его ",[1355,40828,40829],{},"индексом",". Таким образом, вместо того чтобы говорить, например, \"Значение 20 находится в позиции 1\", правильно сказать \"Значение 20 имеет индекс 1\".\nТермин \"индекс\" означает то же, что и \"позиция\" в случае с массивами.\nПредположим, вы хотите вставить элемент в начало массива. Сколько времени на это потребуется?",[12129,40832,40834],{"id":40833},"вставка-в-середину-списка","Вставка в середину списка",[415,40836,40837,40838,40841],{},"Предположим, вы хотите чтобы список дел напоминал календарь.\nПрежде данные добавлялись только в конец списка, а теперь они должны добавляться в порядке их выполнения.\nЧто лучше подойдёт для вставки элементов в середину: массив или список? Со списком задача решается изменением ",[1355,40839,40840],{},"указателя"," в предыдущем элементе.\nА при работе с массивом придётся перемещать или сдвигать все элементы. Если свободного места не осталось, все данные придётся скопировать в новую область памяти!\nВ общем случае получается что списки больше подходят для вставки элементов в середину.",[8839,40843,40844],{},[415,40845,40846,40849],{},[800,40847,40848],{},"Указатели",". Именно с помощью указателей каждый элемент связанного списка указывает на следующий элемент списка.\nВ каждом элементе связанного списка выделяется некоторый объём памяти для хранения адреса следующего элемента.\nЭта часть элемента называется указателем.\nЕсли вы будите писать программы на низкоуровневом языке программирования очень полезно понимать что значит указатель на объект данных в памяти.",[12129,40851,40853],{"id":40852},"удаление","Удаление",[415,40855,40856],{},"Что, если вы заходите удалить элемент? И снова список лучше подходит для этой операции, потому что в нём достаточно изменить указатель в предыдущем элементе.\nВ массиве при удалении элемента все последующие элементы нужно будет сдвинуть.\nВ отличие от вставки, удаление возможно всегда. Попытка вставки может быть неудачной, если в памяти не осталось свободного места. С удалением подобных проблем нет.",[415,40858,40859],{},"Ниже приведены примеры времени выполнения основных операций с массивами и списками:",[9256,40861,40862,40874],{},[9259,40863,40864],{},[9262,40865,40866,40869,40871],{},[9265,40867,40868],{},"-------",[9265,40870,40813],{},[9265,40872,40873],{},"Списки",[9275,40875,40876,40886,40895],{},[9262,40877,40878,40881,40884],{},[9280,40879,40880],{},"Чтение",[9280,40882,40883],{},"O(1)",[9280,40885,34864],{},[9262,40887,40888,40891,40893],{},[9280,40889,40890],{},"Вставка",[9280,40892,34864],{},[9280,40894,40883],{},[9262,40896,40897,40899,40901],{},[9280,40898,40853],{},[9280,40900,34864],{},[9280,40902,40883],{},[8839,40904,40905],{},[415,40906,40907],{},"O(n) – линейное время; O(1) – постоянное время.",[415,40909,40910],{},"Заметим, что вставка и удаление выполняются за время O(1) только в том случае, если вы можете мгновенно получить доступ к удаляемому элементу.\nНа практике обычно сохраняются ссылки на первый и последний элементы связанного списка, поэтому время удаления этих элементов составит всего O(1).",[458,40912,40914],{"id":40913},"массивы-или-списки","Массивы или списки?",[415,40916,40917],{},"Массивы используются часто, поскольку имеют множество преимуществ перед списками. Во-первых, данные из них проще читать. Во-вторых, массивы поддерживают произвольный доступ.\nВсего существует два вида доступа: произвольный и последовательный. При последовательном доступе элементы читаются по одному, начиная с первого.\nСвязанные списки поддерживают только последовательный доступ.\nЕсли вы захотите прочитать 10-й элемент связанного списка, нам придётся прочитать первые 9 его элементов и перейти по ссылкам к 10-му элементу.\nМногие реальные ситуации требуют произвольного доступа, поэтому массивы часто применяются на практике.\nОднако даже безотносительно произвольного доступа массивы работают быстрее, поскольку могут использовать такой принцип как \"кэширование\".\nВозможно, вы представляете себе процесс чтения как восприятие одного элемента за раз.\nНо на самом деле компьютеры читают целыми разделами, поскольку это значительно ускоряет переход к следующему элементу.\nС массивами можно сделать то, что не получится со связанными списками.\nС помощью массива можно прочитать целый раздел элементов.\nВ связанном списке местоположение следующего элемента неизвестно.\nПридётся прочитать элемент, узнать, где находится следующий, а затем прочитать и его. Таким образом, массивы обеспечивают не только произвольный, но и более быстрый доступ к данным!",[415,40919,40920],{},"А как насчёт эффективного использования памяти? Помните, что в случае с массивами обычно выделяют больше памяти, чем нужно, и если в конечном итоге она окажется не нужна, то получается, ресурс расходуется впустую?\nНа деле конечно же(особенно сегодня и думаю в будущем) объём такой неиспользованной памяти получается не очень то большим(в сравнении с памятью современных устройств).\nС другой стороны, когда вы применяете связанный список, вы выделяете дополнительную память для каждого элемента, поскольку в ней сохраняется адрес следующего элемента.\nТаким образом данные в связанном списке занимают больше места, при аналогичной размерности массива, если их элементы относительно невелики.\nКонечно, если элементы массива крупные, то даже один слот неиспользованной памяти может оказаться очень большим, а объём дополнительной памяти, используемой для хранения указателей(адресов на последующий элемент), по сравнению с ним будет совсем незначительным.\nТаким образом, массивы используются чаще, чем связанные списки, за исключением особых случаев.",[29386,40922],{":isAnswers":40923,":isList":40924,"title":29391,"isText":40925},"[\"В данном случае траты добавляются в списко ежедневно, а чтение всех данных происходит один раз в месяц. Для массивов характерно быстрое чтение и медленная вставка, а для связанных списков – медленное чтение и быстрая вставка. Связанный списк станет хорошим решением.\",\"Связанный список. Вставка происходит очень часто, а связанные списки эффективно выполняют эту операцию. Ни поиск, ни произвольный доступ вам не понадобятся, потому что повар всегда извлекает из очереди первый заказ.\",\"В виде отсортированного массива. Массивы обеспечивают произвольный доступ – можно мгновенно получить элемент из середины.\",\"Вставка в массив выполняется медленно. Кроме того, если мы используем бинарный поиск для нахождения имён пользователей, массив необходимо отсортировать. Предположим новый пользователь регистрируется на сайте. Его имя будет вставлено в конец массива. Следовательно, массив ещё нужно будет сортировать при каждой вставке нового имени!\",\"Поиск – медленнее чем для массивов, и быстрее, чем для связанных списков. Вставка – быстрее, чем для массивов, и с такой же скоростью для связанных списков. Гибридная структура уступает массиву по скорости поиска, но по крайней мере не хуже связанных списков для всего остального. Есть ещё такое понятие как хеш-таблица. Она даёт некоторое представление о том, как строить сложные структуры данных из простых. Вероятно, ВКонтакте использует разные базы данных, за которыми стоят разные структуры данных: хеш-таблицы, B-деревья и т.п. Массивы и связанные списки становятся структурными элементами для построения более сложных структур данных.\"]","[\"Допустим, вы строите приложение для управления финансами со множеством категорий трат. Ежедневно вы записываете все свои траты. В конце месяца вы анализируете расходы и вычисляете, сколько денег было потрачено. При работе с данными выполняется множество операций вставки и относительно немного операций чтения. Какую структуру данных лучше использовать массив или список?\",\"Допустим, вы пишите приложение для приёма заказов от посетителей ресторана. Приложение должно хранить список заказов. Официанты добавляют заказы в список, а повара читают заказы из списка и выполняют их. Заказы образуют очередь: официанты добавляют заказы в конец очереди, а повар берёт новый заказ из очереди и начинает его готовить. Какую структуру данных вы использовали бы для реализации этой очереди: массив или список?\",\"Проведём мысленный эксперимент. Допусти, ВКонтакте хранит список имён пользователей. Когда кто-то пытается зайти на сайт ВКонтакте, система пытается найти пользователя. Если имя входит в список имён зарегистрированных пользователей, то вход разрешается. Пользователи приходят на сайт достаточно часто, поэтому поиск по списку имён пользователей выполняется часто. Будем считать, что ВКонтакте использует бинарный поиск для поиска имён пользователей. Бинарному поиску необходим произвольный доступ — алгоритм должен мгновенно обращаться к среднему элементу среди всех имён. Зная это обстоятельство, как бы вы реализовали список пользователей: в виде массива или в виде связанного списка?\",\"Пользователи также довольно часто создают новые учётные записи на ВКонтакте. Предположим, вы решили использовать массив для хранения списка пользователей. Какими недостатками обладает массив для выполнения вставки? Допустим, вы используете бинарный поиск для нахождения учётных данных. Что произойдёт при добавлении новых пользователей в массив?\",\"В действительности ВКонтакте не использует ни массив, ни связанный список для хранения информации об именах пользователей. Он использует базу данных. Но мы представим гибридную структуру: массив связанных списков. Имеется массив из 30 элементов. Каждый элемент содержит ссылку на связанный список. Например, первый элемент массива указывает на связанный список всех имён пользователей, начинающихся на букву \\\"А\\\". Второй элемент указывает на связанный список всех имён пользователей, начинающихся на букву \\\"Б\\\", и т.д. Предположим, пользователь с именем \\\"Андрей В\\\" регистрируется на сайте и вы хотите добавить его в список. Вы обращаетесь к первому элементу массива, находите связанный список и добавляете пользователя \\\"Андрей В\\\" в конец этого списка. Теперь предположим, что на сайте зарегистрировался пользователь с именем \\\"Яков Н\\\". Вы также обращаетесь к элементу 30, который содержит связанный список всех имён, начинающихся на \\\"Я\\\", и проверяете, присутствует ли \\\"Яков Н\\\" в этом списке. Теперь сравните эту гибридную структуру данных с простым мыссивом и простым связанным списком. Будет ли она быстрее или медленнее каждой из них при поиске и\u002Fили вставке? Просто ответите выбрав одно из двух: \\\"будет быстрее\\\" или \\\"будет медленнее\\\".\"]","Попробуйте ответить на следующие вопросы",[632,40927,262],{"id":40928},"сортировка-выбором-1",[415,40930,40931,40932],{},"Объединим все знания выше для построения алгоритма: сортировка выбором.\nЧтобы понять этот алгоритм, представьте, у вас на компьютере хранится музыка и для каждого исполнителя хранится счётчик воспроизведений его звукозаписей.\nВы хотели бы отсортировать список по убыванию счётчика воспроизведений, чтобы самые любимые исполнители стояли на первых местах. Как это реализовать?\nОдно из возможных решений — пройти по списку, найти исполнителя с наибольшим количеством воспроизведений и добавить его в новый список.\nПотом нужно сделать те же действия, но уже со следующим по количеству воспроизведений исполнителем.\nПродолжаем действовать так до конца, пока последнего исполнителя не перенесём в новый отсортированный список.\nА теперь попробуем оценить происходящее с точки зрения теории вычислений и посмотрим, сколько времени будут занимать операции.\nНапомним, что время O(n) означает, что вы по одному разу обращаетесь к каждому элементу списка(или массива).\nНапример, при простом поиске по списку исполнителей каждый исполнитель будет проверен один раз.\nЧтобы найти исполнителя с наибольшим значением счётчика воспроизведений, необходимо проверить каждый элемент в списке.\nЭто получается сделать за время O(n).\nИтак, имеется операция, выполняемая за время O(n), и её необходимо выполнить n раз: всё это потребует времени O(n * n) или\n",[33809,40933,40935],{"className":40934,"jax":33813},[33812],[33815,40936,40939,40951],{"style":35005,"xmlns":33818,"width":40937,"height":37685,"role":15324,"focusable":33821,"viewBox":40938,"xmlnsXLink":33823},"5.832ex","0 -833.9 2577.6 1083.9",[33825,40940,40941,40943,40945,40947,40949],{},[33828,40942],{"id":37720,"d":35014},[33828,40944],{"id":37691,"d":35018},[33828,40946],{"id":33846,"d":33847},[33828,40948],{"id":33842,"d":33843},[33828,40950],{"id":37708,"d":35031},[33849,40952,40953],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,40954,40955,40959,40963,40974],{"dataMmlNode":33855},[33849,40956,40957],{"dataMmlNode":33858},[33860,40958],{"dataC":35053,"xLinkHref":37829},[33849,40960,40961],{"dataMmlNode":34206,"transform":35057},[33860,40962],{"dataC":35060,"xLinkHref":37732},[33849,40964,40965,40969],{"dataMmlNode":34252,"transform":35064},[33849,40966,40967],{"dataMmlNode":33858},[33860,40968],{"dataC":33894,"xLinkHref":33895},[33849,40970,40972],{"dataMmlNode":33883,"transform":40971},"translate(633,363) scale(0.707)",[33860,40973],{"dataC":33887,"xLinkHref":33888},[33849,40975,40977],{"dataMmlNode":34206,"transform":40976},"translate(2188.6,0)",[33860,40978],{"dataC":30851,"xLinkHref":37767},[415,40980,40981,40982,41054],{},"Алгоритмы сортировки очень полезны. Например, вы можете отсортировать: имена или фамилии в телефонной книге; даты; сообщения электронной почты и т.п.\nАлгоритм сортировки выбором легко объясняется, но медленно работает. Быстрая сортировка — более эффективный алгоритм сортировки, который выполняется за время:\n",[33809,40983,40985],{"className":40984,"jax":33813},[33812],[33815,40986,40989,41009],{"style":35005,"xmlns":33818,"width":40987,"height":35007,"role":15324,"focusable":33821,"viewBox":40988,"xmlnsXLink":33823},"9.983ex","0 -750 4412.4 1000",[33825,40990,40991,40993,40995,40998,41002,41004,41007],{},[33828,40992],{"id":37892,"d":35014},[33828,40994],{"id":37895,"d":35018},[33828,40996],{"id":40997,"d":33847},"MJX-2-TEX-I-1D45B",[33828,40999],{"id":41000,"d":41001},"MJX-2-TEX-N-2217","M229 286Q216 420 216 436Q216 454 240 464Q241 464 245 464T251 465Q263 464 273 456T283 436Q283 419 277 356T270 286L328 328Q384 369 389 372T399 375Q412 375 423 365T435 338Q435 325 425 315Q420 312 357 282T289 250L355 219L425 184Q434 175 434 161Q434 146 425 136T401 125Q393 125 383 131T328 171L270 213Q283 79 283 63Q283 53 276 44T250 35Q231 35 224 44T216 63Q216 80 222 143T229 213L171 171Q115 130 110 127Q106 124 100 124Q87 124 76 134T64 161Q64 166 64 169T67 175T72 181T81 188T94 195T113 204T138 215T170 230T210 250L74 315Q65 324 65 338Q65 353 74 363T98 374Q106 374 116 368T171 328L229 286Z",[33828,41003],{"id":33917,"d":33831},[33828,41005],{"id":41006,"d":34035},"MJX-2-TEX-I-1D44F",[33828,41008],{"id":37910,"d":35031},[33849,41010,41011],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,41012,41013,41017,41021,41026,41033,41038,41044,41049],{"dataMmlNode":33855},[33849,41014,41015],{"dataMmlNode":33858},[33860,41016],{"dataC":35053,"xLinkHref":37922},[33849,41018,41019],{"dataMmlNode":34206,"transform":35057},[33860,41020],{"dataC":35060,"xLinkHref":37927},[33849,41022,41023],{"dataMmlNode":33858,"transform":35064},[33860,41024],{"dataC":33894,"xLinkHref":41025},"#MJX-2-TEX-I-1D45B",[33849,41027,41029],{"dataMmlNode":34206,"transform":41028},"translate(1974.2,0)",[33860,41030],{"dataC":41031,"xLinkHref":41032},"2217","#MJX-2-TEX-N-2217",[33849,41034,41036],{"dataMmlNode":33858,"transform":41035},"translate(2696.4,0)",[33860,41037],{"dataC":33862,"xLinkHref":33940},[33849,41039,41041],{"dataMmlNode":33858,"transform":41040},"translate(2994.4,0)",[33860,41042],{"dataC":34055,"xLinkHref":41043},"#MJX-2-TEX-I-1D44F",[33849,41045,41047],{"dataMmlNode":33858,"transform":41046},"translate(3423.4,0)",[33860,41048],{"dataC":33894,"xLinkHref":41025},[33849,41050,41052],{"dataMmlNode":34206,"transform":41051},"translate(4023.4,0)",[33860,41053],{"dataC":30851,"xLinkHref":37967},"\nНо об этом в следующей статье.",[458,41056,41058],{"id":41057},"пример-кода","Пример кода",[415,41060,41061],{},"Напишем две функции. Выполним сортировку массива по возрастанию. Сначала напишем функцию для поиска наименьшего значения элемента массива:",[422,41063,41065],{"className":424,"code":41064,"language":396,"meta":426,"style":426},"def findSmallestEl(arr):\n  smaller = arr[0]  # Для хранения наименьшего значения\n  smaller_i = 0  # Для хранения индекса наименьшего значения\n  for i in range(1, len(arr)):\n    if arr[i] \u003C smaller:\n      smaller = arr[i]\n      smaller_i = i\n  return smaller_i\n",[428,41066,41067,41077,41094,41106,41127,41139,41149,41158],{"__ignoreMap":426},[431,41068,41069,41071,41074],{"class":433,"line":434},[431,41070,6330],{"class":654},[431,41072,41073],{"class":6333}," findSmallestEl",[431,41075,41076],{"class":441},"(arr):\n",[431,41078,41079,41082,41084,41087,41089,41091],{"class":433,"line":452},[431,41080,41081],{"class":441},"  smaller ",[431,41083,1189],{"class":654},[431,41085,41086],{"class":441}," arr[",[431,41088,3302],{"class":437},[431,41090,3612],{"class":441},[431,41092,41093],{"class":455},"# Для хранения наименьшего значения\n",[431,41095,41096,41099,41101,41103],{"class":433,"line":578},[431,41097,41098],{"class":441},"  smaller_i ",[431,41100,1189],{"class":654},[431,41102,9744],{"class":437},[431,41104,41105],{"class":455},"  # Для хранения индекса наименьшего значения\n",[431,41107,41108,41110,41112,41114,41116,41118,41120,41122,41124],{"class":433,"line":584},[431,41109,20523],{"class":654},[431,41111,12664],{"class":441},[431,41113,14421],{"class":654},[431,41115,14424],{"class":437},[431,41117,442],{"class":441},[431,41119,1192],{"class":437},[431,41121,4846],{"class":441},[431,41123,5205],{"class":437},[431,41125,41126],{"class":441},"(arr)):\n",[431,41128,41129,41131,41134,41136],{"class":433,"line":1244},[431,41130,10438],{"class":654},[431,41132,41133],{"class":441}," arr[i] ",[431,41135,8521],{"class":654},[431,41137,41138],{"class":441}," smaller:\n",[431,41140,41141,41144,41146],{"class":433,"line":1985},[431,41142,41143],{"class":441},"      smaller ",[431,41145,1189],{"class":654},[431,41147,41148],{"class":441}," arr[i]\n",[431,41150,41151,41154,41156],{"class":433,"line":2041},[431,41152,41153],{"class":441},"      smaller_i ",[431,41155,1189],{"class":654},[431,41157,14375],{"class":441},[431,41159,41160,41162],{"class":433,"line":4018},[431,41161,20132],{"class":654},[431,41163,41164],{"class":441}," smaller_i\n",[415,41166,41167],{},"Затем напишем основную функцию алгоритма сортировки выбором:",[422,41169,41171],{"className":424,"code":41170,"language":396,"meta":426,"style":426},"# Сортируем массив\ndef selectionSort(arr):\n  newArr = []  # Новый массив, как для результат сортировки\n  for i in range(len(arr)):\n      # Находим наименьший элемент в массиве с помощью вспомогательной функции\n      smallest = findSmallestEl(arr)\n      newArr.append(arr.pop(smallest))  # Добавляем наименьший элемент в новый массив\n  return newArr\n  \nprint(selectionSort([8, 1, 5, 2, 9, 4]))  # Пример работы функции\n",[428,41172,41173,41178,41187,41199,41215,41220,41230,41238,41245,41249],{"__ignoreMap":426},[431,41174,41175],{"class":433,"line":434},[431,41176,41177],{"class":455},"# Сортируем массив\n",[431,41179,41180,41182,41185],{"class":433,"line":452},[431,41181,6330],{"class":654},[431,41183,41184],{"class":6333}," selectionSort",[431,41186,41076],{"class":441},[431,41188,41189,41192,41194,41196],{"class":433,"line":578},[431,41190,41191],{"class":441},"  newArr ",[431,41193,1189],{"class":654},[431,41195,17473],{"class":441},[431,41197,41198],{"class":455},"# Новый массив, как для результат сортировки\n",[431,41200,41201,41203,41205,41207,41209,41211,41213],{"class":433,"line":584},[431,41202,20523],{"class":654},[431,41204,12664],{"class":441},[431,41206,14421],{"class":654},[431,41208,14424],{"class":437},[431,41210,442],{"class":441},[431,41212,5205],{"class":437},[431,41214,41126],{"class":441},[431,41216,41217],{"class":433,"line":1244},[431,41218,41219],{"class":455},"      # Находим наименьший элемент в массиве с помощью вспомогательной функции\n",[431,41221,41222,41225,41227],{"class":433,"line":1985},[431,41223,41224],{"class":441},"      smallest ",[431,41226,1189],{"class":654},[431,41228,41229],{"class":441}," findSmallestEl(arr)\n",[431,41231,41232,41235],{"class":433,"line":2041},[431,41233,41234],{"class":441},"      newArr.append(arr.pop(smallest))  ",[431,41236,41237],{"class":455},"# Добавляем наименьший элемент в новый массив\n",[431,41239,41240,41242],{"class":433,"line":4018},[431,41241,20132],{"class":654},[431,41243,41244],{"class":441}," newArr\n",[431,41246,41247],{"class":433,"line":4030},[431,41248,31228],{"class":441},[431,41250,41251,41253,41256,41258,41260,41262,41264,41266,41268,41270,41272,41274,41276,41278,41280],{"class":433,"line":4419},[431,41252,438],{"class":437},[431,41254,41255],{"class":441},"(selectionSort([",[431,41257,1021],{"class":437},[431,41259,4846],{"class":441},[431,41261,1192],{"class":437},[431,41263,4846],{"class":441},[431,41265,856],{"class":437},[431,41267,4846],{"class":441},[431,41269,651],{"class":437},[431,41271,4846],{"class":441},[431,41273,3357],{"class":437},[431,41275,4846],{"class":441},[431,41277,762],{"class":437},[431,41279,18747],{"class":441},[431,41281,41282],{"class":455},"# Пример работы функции\n",[415,41284,41285],{},[1355,41286,35270],{},[29130,41288],{":isList":41289,"title":30269},"[\"Память компьютера для данных можно представить как гардероб для вещей\",\"Если вам необходимо сохранить набор элементов, для начала воспользуйтесь массивом или списком\",\"В массиве все элементы хранятся рядом друг с другом\",\"В связанном списке элементы распределяются в произвольных местах памяти, при этом в каждом элементе хранится адрес следующего элемента\",\"Массивы обеспечивают быстрое чтение\",\"Списки обеспечивают быструю вставку и удаление\"]",[415,41291,34817,41292,1853,41294,1857],{},[800,41293,1852],{},[800,41295,1856],{},[1859,41297],{},[1862,41299,35276],{},[1862,41301,41302],{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":41304},[41305],{"id":40740,"depth":452,"text":262,"children":41306},[41307,41308,41317],{"id":40763,"depth":578,"text":40764},{"id":40770,"depth":578,"text":40771,"children":41309},[41310,41311,41316],{"id":40799,"depth":584,"text":40800},{"id":40812,"depth":584,"text":40813,"children":41312},[41313,41314,41315],{"id":40822,"depth":1244,"text":40823},{"id":40833,"depth":1244,"text":40834},{"id":40852,"depth":1244,"text":40853},{"id":40913,"depth":584,"text":40914},{"id":40928,"depth":578,"text":262,"children":41318},[41319],{"id":41057,"depth":584,"text":41058},"2025-11-14","Алгоритм сортировки выбором массива или списка","images\u002Fblog\u002Fpython\u002Fst26\u002Fimg.png",{},{"title":262,"description":41321},"OEKYDsGQ3XQtw2_Uby2GHxDBU8jvP5yL9PH_mdhusL0",{"id":41327,"title":266,"author":41328,"body":41330,"date":42214,"description":42215,"extension":1887,"image":42216,"meta":42217,"minRead":4488,"navigation":393,"num":25838,"path":267,"seo":42218,"stem":268,"__hash__":42219},"python\u002Fblog\u002Fpython\u002Fst27.md",{"name":402,"avatar":41329},{"src":404,"alt":405},{"type":407,"value":41331,"toc":42198},[41332,41336,41339,41342,41359,41362,41373,41379,41470,41477,41532,41535,41539,41542,41587,41597,41654,41657,41661,41668,41679,41683,41696,41750,41753,41810,41844,41848,41851,41906,41917,41921,42039,42043,42068,42072,42095,42099,42139,42143,42154,42163,42166,42178,42181,42183,42187,42193,42195],[410,41333,41335],{"id":41334},"рекурсия","Рекурсия",[29130,41337],{":isList":41338,"title":29133},"[\"Вы узнаете что такое рекурсия – метод программирования, используемый во многих алгоритмах.\",\"Вы научитесь разбивать задачи на базовый и рекурсивный случаи.\"]",[415,41340,41341],{},"Представьте, вы находите запертый загадочный сундук. Ключ от сундука лежит в коробке. В комнате где вы нашли сундук есть также множество всяких коробок.\nВ коробках могут лежать и другие коробки(например, меньшего размера). Ключ находится где в одной из таких коробок.\nКакой алгоритм поиска ключа можно придумать? Одно из решений может быть таким:",[1588,41343,41344,41347,41350,41353,41356],{},[700,41345,41346],{},"Сложить все коробки в кучу или просто обнаружить их все которые существуют на виду;",[700,41348,41349],{},"Открыть какую нибудь закрытую коробку;",[700,41351,41352],{},"Если внутри лежит коробка, добавить её в кучу для последующего вскрытия и иска;",[700,41354,41355],{},"Если внутри лежит ключ, поиск закончен!",[700,41357,41358],{},"Повторить пункт 2.",[415,41360,41361],{},"Есть также альтернативное решение:",[1588,41363,41364,41367,41370],{},[700,41365,41366],{},"Просмотреть содержимое коробки;",[700,41368,41369],{},"Если найдена внутри ещё коробка, выполнить пункт 1;",[700,41371,41372],{},"Если нашли ключ, то поиск закончен!",[415,41374,41375,41376,41378],{},"Какое решение наиболее простое? Первое решение можно построить на цикле ",[428,41377,12737],{},". Пока куча коробок не пуста, взять очередную коробку и проверить её содержимое.\nНапишем условный или псевдокод на python:",[422,41380,41382],{"className":424,"code":41381,"language":396,"meta":426,"style":426},"def look_key(box):\n  pile = box.make_to_look()\n  while pile is not empty:\n    bx = pile.give_box()\n    for item in bx:\n      if item.is_a_box():\n        pile.append(item)\n      elif item.is_a_key():\n        print(\"Найден ключ!\")\n",[428,41383,41384,41394,41404,41418,41428,41439,41446,41451,41459],{"__ignoreMap":426},[431,41385,41386,41388,41391],{"class":433,"line":434},[431,41387,6330],{"class":654},[431,41389,41390],{"class":6333}," look_key",[431,41392,41393],{"class":441},"(box):\n",[431,41395,41396,41399,41401],{"class":433,"line":452},[431,41397,41398],{"class":441},"  pile ",[431,41400,1189],{"class":654},[431,41402,41403],{"class":441}," box.make_to_look()\n",[431,41405,41406,41408,41411,41413,41415],{"class":433,"line":578},[431,41407,34616],{"class":654},[431,41409,41410],{"class":441}," pile ",[431,41412,19884],{"class":654},[431,41414,9498],{"class":654},[431,41416,41417],{"class":441}," empty:\n",[431,41419,41420,41423,41425],{"class":433,"line":584},[431,41421,41422],{"class":441},"    bx ",[431,41424,1189],{"class":654},[431,41426,41427],{"class":441}," pile.give_box()\n",[431,41429,41430,41432,41434,41436],{"class":433,"line":1244},[431,41431,14745],{"class":654},[431,41433,21014],{"class":441},[431,41435,14421],{"class":654},[431,41437,41438],{"class":441}," bx:\n",[431,41440,41441,41443],{"class":433,"line":1985},[431,41442,40409],{"class":654},[431,41444,41445],{"class":441}," item.is_a_box():\n",[431,41447,41448],{"class":433,"line":2041},[431,41449,41450],{"class":441},"        pile.append(item)\n",[431,41452,41453,41456],{"class":433,"line":4018},[431,41454,41455],{"class":654},"      elif",[431,41457,41458],{"class":441}," item.is_a_key():\n",[431,41460,41461,41463,41465,41468],{"class":433,"line":4030},[431,41462,11353],{"class":437},[431,41464,442],{"class":441},[431,41466,41467],{"class":445},"\"Найден ключ!\"",[431,41469,449],{"class":441},[415,41471,41472,41473,41476],{},"Второй способ основан на таком алгоритме и понятии как рекурсия. ",[1355,41474,41475],{},"Рекурсией"," называется вызов функции самой себя. Второе решение на псевдокоде может выглядеть так:",[422,41478,41480],{"className":424,"code":41479,"language":396,"meta":426,"style":426},"def look_key(box):\n  for item in box:\n    if item.is_a_box():\n      look_key(item)  # Здесь рекурсия!\n    elif item.is_a_key():\n      print(\"Найден ключ!\")\n",[428,41481,41482,41490,41501,41507,41515,41521],{"__ignoreMap":426},[431,41483,41484,41486,41488],{"class":433,"line":434},[431,41485,6330],{"class":654},[431,41487,41390],{"class":6333},[431,41489,41393],{"class":441},[431,41491,41492,41494,41496,41498],{"class":433,"line":452},[431,41493,20523],{"class":654},[431,41495,21014],{"class":441},[431,41497,14421],{"class":654},[431,41499,41500],{"class":441}," box:\n",[431,41502,41503,41505],{"class":433,"line":578},[431,41504,10438],{"class":654},[431,41506,41445],{"class":441},[431,41508,41509,41512],{"class":433,"line":584},[431,41510,41511],{"class":441},"      look_key(item)  ",[431,41513,41514],{"class":455},"# Здесь рекурсия!\n",[431,41516,41517,41519],{"class":433,"line":1244},[431,41518,10958],{"class":654},[431,41520,41458],{"class":441},[431,41522,41523,41526,41528,41530],{"class":433,"line":1985},[431,41524,41525],{"class":437},"      print",[431,41527,442],{"class":441},[431,41529,41467],{"class":445},[431,41531,449],{"class":441},[415,41533,41534],{},"Оба решения делают одно и тоже. При этом второе решение короче и когда вам известен такой способ как рекурсия, решение это становится более понятным.\nПрименение рекурсии не ускоряет работу программы. Более того, решение циклами и с помощью динамического программирование(о нём в другой статье) иногда работает даже быстрее.\nМне нравится одна фраза на эту тему: \"Рекурсия может ускорить работу программиста, циклы могут ускорить работу программы. Выбирайте что вам нужнее в вашей ситуации!\"\nРекурсия используется во многих задачах, поэтому важно понимать её концепцию и применимость.",[632,41536,41538],{"id":41537},"базовый-и-рекурсивный-случай","Базовый и рекурсивный случай",[415,41540,41541],{},"Так как рекурсивная функция вызывает сама себя, программисту легко ошибиться и написать функцию так, что возникнет бесконечный вызов такой рекурсивной функции.\nПредположим, вы хотите написать функцию для вывода обратного отсчёта: 3...2...1\nЕё можно записать с помощью рекурсии:",[422,41543,41545],{"className":424,"code":41544,"language":396,"meta":426,"style":426},"def ctdown(i):\n  print(i)\n  ctdown(i-1)\n\nctdown(3)\n",[428,41546,41547,41557,41563,41574,41578],{"__ignoreMap":426},[431,41548,41549,41551,41554],{"class":433,"line":434},[431,41550,6330],{"class":654},[431,41552,41553],{"class":6333}," ctdown",[431,41555,41556],{"class":441},"(i):\n",[431,41558,41559,41561],{"class":433,"line":452},[431,41560,18530],{"class":437},[431,41562,12677],{"class":441},[431,41564,41565,41568,41570,41572],{"class":433,"line":578},[431,41566,41567],{"class":441},"  ctdown(i",[431,41569,853],{"class":654},[431,41571,1192],{"class":437},[431,41573,449],{"class":441},[431,41575,41576],{"class":433,"line":584},[431,41577,1662],{"emptyLinePlaceholder":393},[431,41579,41580,41583,41585],{"class":433,"line":1244},[431,41581,41582],{"class":441},"ctdown(",[431,41584,971],{"class":437},[431,41586,449],{"class":441},[415,41588,41589,41590,41593,41594,3562],{},"Запустив такой код возникает проблема: эта функция будет выполнять бесконечно! Чтобы прервать выполнение, нужно закрыть консоль или нажать Ctrl+C.\nКогда вы пишете рекурсивную функцию, в ней необходимо предусмотреть момент прерывания рекурсии.\nПоэтому каждая правильно написанная ",[1355,41591,41592],{},"рекурсивная функция состоит из двух частей: базового и рекурсивного случая.","\nВ рекурсивном случае функция вызывает сама себя. В базовом случае функция себя не вызывает, а наоборот предотвращает вызов и тем самым \"зацикливание\".\nДобавим базовый случай в функцию ",[428,41595,41596],{},"ctdown",[422,41598,41600],{"className":424,"code":41599,"language":396,"meta":426,"style":426},"def ctdown(i):\n  print(i)\n  if i \u003C= i:\n    return\n  ctdown(i-1)\n\nctdown(3)\n",[428,41601,41602,41610,41616,41627,41632,41642,41646],{"__ignoreMap":426},[431,41603,41604,41606,41608],{"class":433,"line":434},[431,41605,6330],{"class":654},[431,41607,41553],{"class":6333},[431,41609,41556],{"class":441},[431,41611,41612,41614],{"class":433,"line":452},[431,41613,18530],{"class":437},[431,41615,12677],{"class":441},[431,41617,41618,41620,41622,41624],{"class":433,"line":578},[431,41619,20480],{"class":654},[431,41621,12664],{"class":441},[431,41623,12667],{"class":654},[431,41625,41626],{"class":441}," i:\n",[431,41628,41629],{"class":433,"line":584},[431,41630,41631],{"class":654},"    return\n",[431,41633,41634,41636,41638,41640],{"class":433,"line":1244},[431,41635,41567],{"class":441},[431,41637,853],{"class":654},[431,41639,1192],{"class":437},[431,41641,449],{"class":441},[431,41643,41644],{"class":433,"line":1985},[431,41645,1662],{"emptyLinePlaceholder":393},[431,41647,41648,41650,41652],{"class":433,"line":2041},[431,41649,41582],{"class":441},[431,41651,971],{"class":437},[431,41653,449],{"class":441},[415,41655,41656],{},"Теперь функция работает как было задумано.",[632,41658,41660],{"id":41659},"стек","Стек",[415,41662,41663,41664,41667],{},"Рассмотрим такое понятие как ",[1355,41665,41666],{},"стек вызовов",". Концепция стека вызовов важно понимать в программировании и особенно при использовании рекурсии.\nПредположим вы устраиваете вечеринку и составляете список задач записывая все дела на листках.\nЗадачи, представим что это элементы некоторого единого списка, но будут вместе выглядеть как стопка листков.\nНовые (вставленные) элементы добавляются всегда в начало списка, то есть наверх стопки с листочками.\nЧитается всегда только верхний элемент, и он же исключается из списка(из стопки). Таким образом, список задач поддерживает всего два действия:\nзанесение(вставка или добавление) и извлечение (чтение и удаление).\nПосмотрим, как работает такой список задач реализованный через стек:",[1588,41669,41670,41673,41676],{},[700,41671,41672],{},"Задача извлекается из стека(из стопки);",[700,41674,41675],{},"Читается и выполняется;",[700,41677,41678],{},"Либо пункт 1, 2 повторяются снова(только если стек не будет пустым) либо добавляется новая задача или задачи в стек.\nПрограммисты новички с самого начала программирования уже пользуются стеком даже не подозревая об этом!",[458,41680,41682],{"id":41681},"стек-вызовов","Стек вызовов",[415,41684,41685,41688,41689,41691,41692,41695],{},[15324,41686],{"alt":41682,"src":41687},"images\u002Fblog\u002Fpython\u002Fst27\u002Fimg1.png","\nВо внутренней работе вашего компьютера используется ",[1355,41690,41659],{},", называемый ",[1355,41693,41694],{},"стеком вызовов",". Разберёмся как он работает.\nПредположим, имеется простая функция:",[422,41697,41699],{"className":424,"code":41698,"language":396,"meta":426,"style":426},"def greetings(name):\n  print(\"Привет, \" + name + \"!\")\n  greet(name)\n  print(\"Дальше будет пока...\")\n  goodbye()\n",[428,41700,41701,41710,41729,41734,41745],{"__ignoreMap":426},[431,41702,41703,41705,41708],{"class":433,"line":434},[431,41704,6330],{"class":654},[431,41706,41707],{"class":6333}," greetings",[431,41709,13557],{"class":441},[431,41711,41712,41714,41716,41719,41721,41723,41725,41727],{"class":433,"line":452},[431,41713,18530],{"class":437},[431,41715,442],{"class":441},[431,41717,41718],{"class":445},"\"Привет, \"",[431,41720,655],{"class":654},[431,41722,9800],{"class":441},[431,41724,802],{"class":654},[431,41726,2946],{"class":445},[431,41728,449],{"class":441},[431,41730,41731],{"class":433,"line":578},[431,41732,41733],{"class":441},"  greet(name)\n",[431,41735,41736,41738,41740,41743],{"class":433,"line":584},[431,41737,18530],{"class":437},[431,41739,442],{"class":441},[431,41741,41742],{"class":445},"\"Дальше будет пока...\"",[431,41744,449],{"class":441},[431,41746,41747],{"class":433,"line":1244},[431,41748,41749],{"class":441},"  goodbye()\n",[415,41751,41752],{},"Эта функция приветствует вас, после чего вызывает две другие функции. Например:",[422,41754,41756],{"className":424,"code":41755,"language":396,"meta":426,"style":426},"def greet(name):\n  print(\"Как твои дела, \" + name + \"?\")\n\ndef goodbye(name):\n  print(\"Хорошо, пока!\")\n",[428,41757,41758,41766,41786,41790,41799],{"__ignoreMap":426},[431,41759,41760,41762,41764],{"class":433,"line":434},[431,41761,6330],{"class":654},[431,41763,16066],{"class":6333},[431,41765,13557],{"class":441},[431,41767,41768,41770,41772,41775,41777,41779,41781,41784],{"class":433,"line":452},[431,41769,18530],{"class":437},[431,41771,442],{"class":441},[431,41773,41774],{"class":445},"\"Как твои дела, \"",[431,41776,655],{"class":654},[431,41778,9800],{"class":441},[431,41780,802],{"class":654},[431,41782,41783],{"class":445}," \"?\"",[431,41785,449],{"class":441},[431,41787,41788],{"class":433,"line":578},[431,41789,1662],{"emptyLinePlaceholder":393},[431,41791,41792,41794,41797],{"class":433,"line":584},[431,41793,6330],{"class":654},[431,41795,41796],{"class":6333}," goodbye",[431,41798,13557],{"class":441},[431,41800,41801,41803,41805,41808],{"class":433,"line":1244},[431,41802,18530],{"class":437},[431,41804,442],{"class":441},[431,41806,41807],{"class":445},"\"Хорошо, пока!\"",[431,41809,449],{"class":441},[415,41811,41812,41813,41816,41817,41820,41821,41824,41825,41828,41829,41832,41833,41836,41837,41840,41841,41843],{},"Разберемся, что происходит при вызове функции.\nПредположим, в программе используется вызов ",[428,41814,41815],{},"greetings(\"Иван\")",". Сначала ваш компьютер выделяет блок памяти вызова функции.\nЗатем эта память используется. Переменной name присваивается значение \"Иван\"(оно также должно быть сохранено в памяти).\nКаждый раз, когда вы вызываете функцию, компьютер сохраняет в памяти значения всех переменных для вызова.\nДалее выводится приветствие: ",[428,41818,41819],{},"Привет, Иван!",", после чего следует второй вызов ",[428,41822,41823],{},"greet(\"Иван\")",".\nИ снова компьютер выделяет блок памяти для вызова функции. Далее ваш компьютер объединяет эти блоки в стек.\nВторой блок в стеке с вызовом функции greet создаётся над первым блоком с вызовом функции greetings.\nВы видите сообщение ",[428,41826,41827],{},"Как твои дела, Иван?",", после чего возвращается управление из вызова функции. Когда это происходит,\nблок на вершине стека извлекается из него(извлекается вызов функции greet).\nТеперь верхний блок в стеке относится к функции greetings; это означает, что вы вернулись к функции greetings.\nПри вызове функции greet функция greetings ещё не была завершена.\nПолучается, ",[1355,41830,41831],{},"когда происходит вызов функции из другой функции, вызывающая функция приостанавливается в частично завершенном состоянии.","\nВсе значения переменных этой функции остаются в памяти.\nА когда выполнение функции greet будет завершено, происходит возврат к функции greetings в то же место, где выполнение её прервалось.\nИ наконец, далее сначала выводится сообщение ",[428,41834,41835],{},"Дальше будет пока...",", после чего вызывается функция goodbye.\nБлок для функции goodbye добавляется на вершину стека. И напоследок выводится сообщение ",[428,41838,41839],{},"Хорошо, пока!"," с выходом из вызова функции.\nУправление снова возвращается функции greet. Делать в программе больше нечего, так что управление возвращается и из функции greetings.\nТакой стек в котором сохранялись вызовы разных функций называется ",[1355,41842,41694],{},".\nПосмотрим, как работает стек вызовов с рекурсивными функциями.",[458,41845,41847],{"id":41846},"стек-вызовов-с-рекурсией","Стек вызовов с рекурсией",[415,41849,41850],{},"В рекурсивной функции тоже используются стек вызовов!\nСамое просто это посмотреть на примере рекурсивной функции вычисления факториала. На Python запишем её так:",[422,41852,41854],{"className":424,"code":41853,"language":396,"meta":426,"style":426},"def factorial(n):\n  if n == 1:\n    return 1\n  else:\n    return n * factorial(n-1)\n",[428,41855,41856,41865,41877,41883,41889],{"__ignoreMap":426},[431,41857,41858,41860,41863],{"class":433,"line":434},[431,41859,6330],{"class":654},[431,41861,41862],{"class":6333}," factorial",[431,41864,12523],{"class":441},[431,41866,41867,41869,41871,41873,41875],{"class":433,"line":452},[431,41868,20480],{"class":654},[431,41870,8150],{"class":441},[431,41872,8409],{"class":654},[431,41874,1032],{"class":437},[431,41876,8102],{"class":441},[431,41878,41879,41881],{"class":433,"line":578},[431,41880,6599],{"class":654},[431,41882,3916],{"class":437},[431,41884,41885,41887],{"class":433,"line":584},[431,41886,21994],{"class":654},[431,41888,8102],{"class":441},[431,41890,41891,41893,41895,41897,41900,41902,41904],{"class":433,"line":1244},[431,41892,6599],{"class":654},[431,41894,8150],{"class":441},[431,41896,1357],{"class":654},[431,41898,41899],{"class":441}," factorial(n",[431,41901,853],{"class":654},[431,41903,1192],{"class":437},[431,41905,449],{"class":441},[415,41907,41908,41909,41912,41913,41916],{},"Вызов функции ",[428,41910,41911],{},"factorial(5)"," вычисляет факториал 5! и определяется следующим образом: 5! = 5 * 4 * 3 * 2 * 1.\nТо же самое соответствует вызов функции ",[428,41914,41915],{},"factorial(4)"," 4! = 4 * 3 * 2 * 1. Проанализируем этот вызов:",[12129,41918,41920],{"id":41919},"пошаговое-формирование-стека","Пошаговое формирование стека",[1588,41922,41923,41945,41964,41981,41999],{},[700,41924,41925,41926,41928],{},"Вызов ",[428,41927,41915],{},[697,41929,41930,41935],{},[700,41931,41932,41933],{},"Создаётся фрейм в стеке: ",[428,41934,41915],{},[700,41936,41937,41938,41941,41942],{},"Условие ",[428,41939,41940],{},"n == 1"," не выполнено → вызов ",[428,41943,41944],{},"factorial(3)",[700,41946,41925,41947,41949],{},[428,41948,41944],{},[697,41950,41951,41957],{},[700,41952,41953,41954,41956],{},"Новый фрейм: ",[428,41955,41944],{}," (стек: factorial(4) → factorial(3))",[700,41958,41937,41959,41941,41961],{},[428,41960,41940],{},[428,41962,41963],{},"factorial(2)",[700,41965,41966,41967],{},"Вызов factorial(2)\n",[697,41968,41969,41974],{},[700,41970,41953,41971,41973],{},[428,41972,41963],{}," (стек: factorial(4) → factorial(3) → factorial(2))",[700,41975,41937,41976,41941,41978],{},[428,41977,41940],{},[428,41979,41980],{},"factorial(1)",[700,41982,41925,41983,41985],{},[428,41984,41980],{},[697,41986,41987,41992],{},[700,41988,41953,41989,41991],{},[428,41990,41980],{}," (стек: factorial(4) → factorial(3) → factorial(2) → factorial(1))",[700,41993,41937,41994,41996,41997],{},[428,41995,41940],{}," выполнено → возврат ",[428,41998,1192],{},[700,42000,42001,42002],{},"Разворачивание стека (возвраты)\n",[697,42003,42004,42021,42030],{},[700,42005,42006,42008,42009,42011,42012,42014,42015,42018,42019],{},[428,42007,41980],{}," возвращает ",[428,42010,1192],{}," → ",[428,42013,41963],{}," вычисляет ",[428,42016,42017],{},"2 * 1 = 2"," → возвращает ",[428,42020,651],{},[700,42022,42023,42014,42025,42018,42028],{},[428,42024,41944],{},[428,42026,42027],{},"3 * 2 = 6",[428,42029,742],{},[700,42031,42032,42014,42034,42018,42037],{},[428,42033,41915],{},[428,42035,42036],{},"4 * 6 = 24",[428,42038,36846],{},[12129,42040,42042],{"id":42041},"графическая-визуализация-стека-вертикально-сверху-последний-вызов","Графическая визуализация стека (вертикально, сверху — последний вызов)",[422,42044,42046],{"className":1436,"code":42045,"language":1438,"meta":426,"style":426},"[ factorial(1) ]  ← Базовый случай (возврат 1)\n[ factorial(2) ]  ← Вычисляет 2 * 1 = 2\n[ factorial(3) ]  ← Вычисляет 3 * 2 = 6\n[ factorial(4) ]  ← Вычисляет 4 * 6 = 24\n",[428,42047,42048,42053,42058,42063],{"__ignoreMap":426},[431,42049,42050],{"class":433,"line":434},[431,42051,42052],{},"[ factorial(1) ]  ← Базовый случай (возврат 1)\n",[431,42054,42055],{"class":433,"line":452},[431,42056,42057],{},"[ factorial(2) ]  ← Вычисляет 2 * 1 = 2\n",[431,42059,42060],{"class":433,"line":578},[431,42061,42062],{},"[ factorial(3) ]  ← Вычисляет 3 * 2 = 6\n",[431,42064,42065],{"class":433,"line":584},[431,42066,42067],{},"[ factorial(4) ]  ← Вычисляет 4 * 6 = 24\n",[12129,42069,42071],{"id":42070},"текстовая-трассировка-по-шагам","Текстовая трассировка (по шагам)",[1588,42073,42074,42077,42080,42083,42086,42089,42092],{},[700,42075,42076],{},"factorial(4) → вызывает factorial(3)",[700,42078,42079],{},"factorial(3) → вызывает factorial(2)",[700,42081,42082],{},"factorial(2) → вызывает factorial(1)",[700,42084,42085],{},"factorial(1) → возвращает 1",[700,42087,42088],{},"factorial(2) → возвращает 2 * 1 = 2",[700,42090,42091],{},"factorial(3) → возвращает 3 * 2 = 6",[700,42093,42094],{},"factorial(4) → возвращает 4 * 6 = 24",[12129,42096,42098],{"id":42097},"схема-в-виде-дерева-вызовов","Схема в виде дерева вызовов",[422,42100,42102],{"className":1436,"code":42101,"language":1438,"meta":426,"style":426},"factorial(4)\n├── factorial(3)\n│   ├── factorial(2)\n│   │   └── factorial(1) → 1\n│   └── 2 * 1 = 2\n└── 3 * 2 = 6\n└── 4 * 6 = 24\n",[428,42103,42104,42109,42114,42119,42124,42129,42134],{"__ignoreMap":426},[431,42105,42106],{"class":433,"line":434},[431,42107,42108],{},"factorial(4)\n",[431,42110,42111],{"class":433,"line":452},[431,42112,42113],{},"├── factorial(3)\n",[431,42115,42116],{"class":433,"line":578},[431,42117,42118],{},"│   ├── factorial(2)\n",[431,42120,42121],{"class":433,"line":584},[431,42122,42123],{},"│   │   └── factorial(1) → 1\n",[431,42125,42126],{"class":433,"line":1244},[431,42127,42128],{},"│   └── 2 * 1 = 2\n",[431,42130,42131],{"class":433,"line":1985},[431,42132,42133],{},"└── 3 * 2 = 6\n",[431,42135,42136],{"class":433,"line":2041},[431,42137,42138],{},"└── 4 * 6 = 24\n",[12129,42140,42142],{"id":42141},"ключевые-моменты","Ключевые моменты",[697,42144,42145,42148,42151],{},[700,42146,42147],{},"Стек растёт при рекурсивных вызовах (каждый новый фрейм добавляется сверху).",[700,42149,42150],{},"Стек сокращается при возвратах (фреймы удаляются по порядку LIFO — «последний вошёл, первый вышел»).",[700,42152,42153],{},"Базовый случай (n == 1) останавливает рекурсию и запускает разворачивание стека.",[415,42155,42156,42157,42159,42160,42162],{},"Стек вызовов наглядно показывает, как рекурсия «погружается» в вызовы, а затем «поднимается» с результатами.\nСтек играет важнейшую роль в рекурсии. Здесь важно, что каждый вызов функции создаёт собственную копию переменной ",[428,42158,33806],{},".\nОбратиться к переменной ",[428,42161,33806],{},", принадлежащей другой функции(или её вызову) – невозможно!\nСтек в данном случае особенно удобен, потому что вам не нужно отслеживать значения переменной каждый раз самостоятельно – стек делает это за вас!",[415,42164,42165],{},"Стек удобен, но при его использовании есть своя цена: сохранение всей промежуточной информации может привести к значительным затратам памяти.\nКаждый вызов функции занимает немного памяти, но если стек станет слишком \"высоким\", это будет означать, что ваш компьютер сохраняет информацию по очень многим вызовам!\nНа такой стадии есть два варианта:",[1588,42167,42168,42171],{},[700,42169,42170],{},"Переписать код с использованием цикла;",[700,42172,42173,42174,42177],{},"Иногда можно воспользоваться так называемой ",[1355,42175,42176],{},"\"хвостовой рекурсией\"",". Это непростая тема, которая вдобавок поддерживается далеко не во всех языках программирования.",[29130,42179],{":isList":42180,"title":30269},"[\"Когда функция вызывает саму себя – это рекурсия;\",\"В каждой рекурсивной функции должно быть два случая: базовый и рекурсивный;\",\"Стек поддерживает две операции: занесение и извлечение элементов;\",\"Все вызовы функций сохраняются в стеке вызовов;\",\"Если стек вызовов станет очень большим, он займет слишком много памяти.\"]",[458,42182],{"id":426},[29386,42184],{":isAnswers":42185,":isList":42186,":startOl":1192,"isText":40925,"title":29391},"[\"Сначала вызывается функция greetings для переменной name = \\\"Иван\\\"; Затем функция greetings вызывает функцию greet для переменной name = \\\"Иван\\\"; На этой стадии функция greetings находится в незавершённом, приостановленном состоянии; Текущим вызовом является вызов функции greet; После завершения функции greet, функция greetings продолжит свою работу.\",\"Стек будет расти бесконечно, но каждой программе выделяется ограниченный объём памяти в стеке. Когда всё пространство памяти будет исчерпано, программа завершиться с ошибкой переполнения стека.\"]","[\"Предположим есть стек вызовов следующего вида: greet(name: \\\"Иван\\\") -> greetings(name: \\\"Иван\\\"). Что можно сказать о текущем состоянии программы на основании этого стека вызовов?\",\"Предположим, вы случайно написали рекурсивную функцию, которая бесконечно вызывает саму себя. Как вы уже видели, компьютер выделяет память в стеке при каждом вызове функции. А что произойдёт со стеком при бесконечном выполнении рекурсии?\"]",[415,42188,34817,42189,1853,42191,1857],{},[800,42190,1852],{},[800,42192,1856],{},[1859,42194],{},[1862,42196,42197],{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":426,"searchDepth":452,"depth":1244,"links":42199},[42200],{"id":41334,"depth":452,"text":41335,"children":42201},[42202,42203],{"id":41537,"depth":578,"text":41538},{"id":41659,"depth":578,"text":41660,"children":42204},[42205,42206,42213],{"id":41681,"depth":584,"text":41682},{"id":41846,"depth":584,"text":41847,"children":42207},[42208,42209,42210,42211,42212],{"id":41919,"depth":1244,"text":41920},{"id":42041,"depth":1244,"text":42042},{"id":42070,"depth":1244,"text":42071},{"id":42097,"depth":1244,"text":42098},{"id":42141,"depth":1244,"text":42142},{"id":426,"depth":584,"text":426},"2025-11-20","Алгоритм рекурсии и понятие стек вызовов функции","images\u002Fblog\u002Fpython\u002Fst27\u002Fimg.png",{},{"title":266,"description":42215},"8pzYCqUt-KaqUCrOEbKlMUq0q3elyp2Do2Z_aOthAvU",{"id":42221,"title":270,"author":42222,"body":42224,"date":43887,"description":43888,"extension":1887,"image":43889,"meta":43890,"minRead":1890,"navigation":393,"num":1890,"path":271,"seo":43891,"stem":272,"__hash__":43892},"python\u002Fblog\u002Fpython\u002Fst28.md",{"name":402,"avatar":42223},{"src":404,"alt":405},{"type":407,"value":42225,"toc":43873},[42226,42229,42232,42238,42249,42253,42256,42263,42271,42274,42279,42282,42285,42360,42370,42375,42384,42428,42438,42446,42449,42455,42465,42468,42632,42635,42638,42674,42677,42703,42714,42721,42727,42740,42743,42754,42772,42799,42802,42813,42816,42992,42994,42997,43003,43006,43231,43248,43252,43255,43287,43346,43397,43501,43514,43518,43521,43547,43550,43563,43566,43844,43847,43853,43855,43857,43862,43865,43868,43870],[410,42227,270],{"id":42228},"быстрая-сортировка",[29130,42230],{":isList":42231,"title":29133},"[\"Сначала идёт описание стратегии \\\"разделяй и властвуй\\\". Случается так, задача, над которой вы трудитесь, не решается ни одним из известных вам алгоритмов. Столкнувшись с такой задачей необходимо будет разделить её на подзадачи. \\\"Разделяй и властвуй — первая общая стратегия для разделения задачи на подзадачи.\\\"\",\"Далее рассматривается алгоритм быстрой сортировки – элегантный алгоритм сортировки, часто применяемый на практике. Алгоритм быстрой сортировки использует стратегию \\\"Разделяй и властвуй\\\".\"]",[415,42233,42234,42235],{},"В этой статье сначала исследуем принцип или стратегию \"Разделяй и властвуй\" – это хорошо известный рекурсивный метод решения задач.\n",[1205,42236,42237],{"href":267},"О рекурсии в прошлой статье можно прочитать здесь.",[415,42239,42240,42241,42244,42245,42248],{},"Сам алгоритм не особенно полезен если он решает только задачу одного типа. Стратегия \"Разделяй и властвуй\" помогает выработать новый подход к решению задач.\nСначала стоить понять в чём заключается эта стратегия и такой подход и концу статьи рассмотрим алгоритм ",[1355,42242,42243],{},"быстрой сортировки.","\nЭтот алгоритм работает намного быстрее сортировки выбором(",[1205,42246,42247],{"href":263},"о сортировке выбором в этой статье",").\nТакже алгоритм быстрой сортировки является хорошим примером элегантного способа решения задачи и написании элегантного кода.",[632,42250,42252],{"id":42251},"стратегия-разделяй-и-властвуй","Стратегия \"Разделяй и властвуй\"",[415,42254,42255],{},"Для начала рассмотрим три примера. Сначала разберём наглядный пример. Потом разберём пример кода, который выглядит не изящно, но, пожалуй воспринимается проще. И в третьем примере уже рассмотрим алгоритм быстрой сортировки, использующий стратегию \"разделяй и властвуй\".",[415,42257,42258,42259,42262],{},"Представьте, что вы владеете земельным участком размером 1680 метров на 640 метров.\nВы хотели бы разделить землю на одинаковые ",[1355,42260,42261],{},"квадратные"," участки. Участки должны быть настолько большими, насколько это возможно.\nКак определить наибольший размер квадратного участка? Воспользоваться стратегией \"разделяй и властвуй\"! Решение задачи будет состоять из двух шагов:",[1588,42264,42265,42268],{},[700,42266,42267],{},"Определить базовый случай. Это должен быть простейший случай из всех возможных.",[700,42269,42270],{},"Задача делиться или сокращается до тех пор, пока не будет сведена к базовому случаю.",[415,42272,42273],{},"А теперь воспользуемся стратегией \"разделяй и властвуй\" для решения задачи. Каков самый большой размер квадрата который может получиться?\nДля начала нужно определить базовый случай. Самая простая ситуация это если длина одной стороны кратна длине другой стороны.\nПредположим, длина одной стороны составляет 25м, а длина другой 50м. В этом случае размер самого большого участка составит 25м x 25м, и надел после деления будет состоять из двух таких участков.\nТеперь нужно вычислить рекурсивный случай. В соответствии со стратегией при каждом рекурсивном случае задача должна сокращаться. Как сократить эту задачу?\nДля начала разместим самые большие участки, которые можно использовать. По длине получится расположить два квадратных участка 640x640 метров и останется не распределённой земля в 400 метров.\nТут и наступает что называется \"момент истинны\". Нераспределённый остаток – это тоже надел земли, который нужно распределить. К нему можно также применить такой же алгоритм.\nПолучается что нужно разделить теперь оставшийся меньший участок размером 640 x 400 метров. Если будет найден этот самый большой участок для остатка, то мы найдем решение для всего размера земли.",[8839,42275,42276],{},[415,42277,42278],{},"\"Если будет найден этот самый большой участок для остатка, то мы найдем решение для всего размера земли. В доказательство поищите алгоритм Евклида.\"",[415,42280,42281],{},"Если дальше делить участок размером 640 на 400 метров, то размеры самого большого квадрата, который можно создать, составляют 400x400 метров.\nОстанется после этого ещё меньший нераспределённый участок размером 400x240 метров.\nОтсекая поделенную часть, мы приходим к ещё меньшему размеру сегмента, 240x160 метров. После очередного \"отсечения\" получается ещё меньший сегмент земли.\nИ наконец, мы придём к базовому случаю: 160 на 80. Если разбить этот сегмент на два квадрата 80 на 80, то ничего лишнего уже не останется!\nИтак, для исходного размера земли (1680 метров на 640 метров) самый большой размер участка будет равен 80 на 80 метров.",[415,42283,42284],{},"Рассмотрим ещё один пример. Имеется массив чисел: 3, 4, 6. Нужно написать код, чтобы просуммировать все числа и вернуть сумму. Сделать это можно с помощью функции например так:",[422,42286,42288],{"className":424,"code":42287,"language":396,"meta":426,"style":426},"def summ(arr):\n  total = 0\n  for x in arr:\n    total += x\n  return total\n \nprint(summ([3, 4, 6]))\n",[428,42289,42290,42299,42308,42319,42329,42336,42341],{"__ignoreMap":426},[431,42291,42292,42294,42297],{"class":433,"line":434},[431,42293,6330],{"class":654},[431,42295,42296],{"class":6333}," summ",[431,42298,41076],{"class":441},[431,42300,42301,42304,42306],{"class":433,"line":452},[431,42302,42303],{"class":441},"  total ",[431,42305,1189],{"class":654},[431,42307,3459],{"class":437},[431,42309,42310,42312,42314,42316],{"class":433,"line":578},[431,42311,20523],{"class":654},[431,42313,7388],{"class":441},[431,42315,14421],{"class":654},[431,42317,42318],{"class":441}," arr:\n",[431,42320,42321,42324,42326],{"class":433,"line":584},[431,42322,42323],{"class":441},"    total ",[431,42325,12563],{"class":654},[431,42327,42328],{"class":441}," x\n",[431,42330,42331,42333],{"class":433,"line":1244},[431,42332,20132],{"class":654},[431,42334,42335],{"class":441}," total\n",[431,42337,42338],{"class":433,"line":1985},[431,42339,42340],{"class":441}," \n",[431,42342,42343,42345,42348,42350,42352,42354,42356,42358],{"class":433,"line":2041},[431,42344,438],{"class":437},[431,42346,42347],{"class":441},"(summ([",[431,42349,971],{"class":437},[431,42351,4846],{"class":441},[431,42353,762],{"class":437},[431,42355,4846],{"class":441},[431,42357,742],{"class":437},[431,42359,21085],{"class":441},[415,42361,42362,42363,8399,42366,42369],{},"А как сделать то же самое, но уже с помощью рекурсивной функции?\n",[800,42364,42365],{},"Пункт 1:",[1355,42367,42368],{},"определить базовый случай."," Как выглядит самый простой массив, который можно получить? Если будет массив с 0 или 1 элементом, то сумму достаточно просто получить.",[8839,42371,42372],{},[415,42373,42374],{},"Если нужно написать рекурсивную функцию в которой будет задействован массив, то базовым случаем очень часто будет пустой массив или массив из одного элемента.",[415,42376,42377,8399,42380,42383],{},[800,42378,42379],{},"Пункт 2:",[1355,42381,42382],{},"каждый рекурсивный вызов должен приближать вас к пустому массиву."," Как уменьшить размер задачи? Один из возможных способов:",[422,42385,42387],{"className":424,"code":42386,"language":396,"meta":426,"style":426},"summ([3, 4, 6]) # => 13\n3 + summ([4, 6]) # => 13\n",[428,42388,42389,42409],{"__ignoreMap":426},[431,42390,42391,42394,42396,42398,42400,42402,42404,42406],{"class":433,"line":434},[431,42392,42393],{"class":441},"summ([",[431,42395,971],{"class":437},[431,42397,4846],{"class":441},[431,42399,762],{"class":437},[431,42401,4846],{"class":441},[431,42403,742],{"class":437},[431,42405,18021],{"class":441},[431,42407,42408],{"class":455},"# => 13\n",[431,42410,42411,42413,42415,42418,42420,42422,42424,42426],{"class":433,"line":452},[431,42412,971],{"class":437},[431,42414,655],{"class":654},[431,42416,42417],{"class":441}," summ([",[431,42419,762],{"class":437},[431,42421,4846],{"class":441},[431,42423,742],{"class":437},[431,42425,18021],{"class":441},[431,42427,42408],{"class":455},[415,42429,42430,42431,42434,42435,42437],{},"Во втором случае функции ",[428,42432,42433],{},"summ"," передаётся меньший массив, а результат остаётся такой же. А это означает что мы таким образом сократили размер задачи!\nФункция ",[428,42436,42433],{}," может работать по следующему правилу или схеме:",[1588,42439,42440,42443],{},[700,42441,42442],{},"Функция получает список",[700,42444,42445],{},"Если список пуст, вернуть 0. А иначе результат должен быть равен сумме первого элемента массива и суммы остальных элементов массива.",[415,42447,42448],{},"Вот как это выглядит(не забывайте, что при рекурсии сохраняется состояние переменных):",[415,42450,42451],{},[15324,42452],{"alt":42453,"src":42454},"Пример с массивом","\u002Fimages\u002Fblog\u002Fpython\u002Fst28\u002Fimg1.png",[8839,42456,42457],{},[415,42458,42459,42460],{},"Немного о функциональном программировании. Зачем применять рекурсию, если задачу можно легко решить циклом? Дело в том, что например в языках функционального программирования(Haskell, Lisp, Erlang, APL) циклов не существует, поэтому для написания подобных задач приходится применять рекурсию. Если вы хорошо поймёте рекурсию, вам будет проще работать с функциональными языками программирования. ",[1355,42461,42462],{},[800,42463,42464],{},"Если вам нравится рекурсия присмотритесь к таким языкам как Haskell, R, F#, Clojure, Scala, Erlang.",[415,42466,42467],{},"Вот ещё код для пары примеров похожих задач:",[422,42469,42471],{"className":424,"code":42470,"language":396,"meta":426,"style":426},"# Рекурсивная функция для подсчёта элементов в списке\ndef count(m_list):\n  if m_list == []:\n    return 0\n  return 1 + count(list[1:]) \n\n# Рекурсивная функция для нахождения наибольшего числа в списке\ndef maxx(m_list):\n  if len(m_list) == 2:\n    return m_list[0] if m_list[0] > m_list[1] else m_list[1]\n  s_max = maxx(m_list[1:])\n  return m_list[0] if m_list[0] > s_max else s_max\n",[428,42472,42473,42478,42488,42499,42505,42521,42525,42530,42539,42554,42589,42604],{"__ignoreMap":426},[431,42474,42475],{"class":433,"line":434},[431,42476,42477],{"class":455},"# Рекурсивная функция для подсчёта элементов в списке\n",[431,42479,42480,42482,42485],{"class":433,"line":452},[431,42481,6330],{"class":654},[431,42483,42484],{"class":6333}," count",[431,42486,42487],{"class":441},"(m_list):\n",[431,42489,42490,42492,42495,42497],{"class":433,"line":578},[431,42491,20480],{"class":654},[431,42493,42494],{"class":441}," m_list ",[431,42496,8409],{"class":654},[431,42498,20488],{"class":441},[431,42500,42501,42503],{"class":433,"line":584},[431,42502,6599],{"class":654},[431,42504,3459],{"class":437},[431,42506,42507,42509,42511,42513,42516,42518],{"class":433,"line":1244},[431,42508,20132],{"class":654},[431,42510,1032],{"class":437},[431,42512,655],{"class":654},[431,42514,42515],{"class":441}," count(list[",[431,42517,1192],{"class":437},[431,42519,42520],{"class":441},":]) \n",[431,42522,42523],{"class":433,"line":1985},[431,42524,1662],{"emptyLinePlaceholder":393},[431,42526,42527],{"class":433,"line":2041},[431,42528,42529],{"class":455},"# Рекурсивная функция для нахождения наибольшего числа в списке\n",[431,42531,42532,42534,42537],{"class":433,"line":4018},[431,42533,6330],{"class":654},[431,42535,42536],{"class":6333}," maxx",[431,42538,42487],{"class":441},[431,42540,42541,42543,42545,42548,42550,42552],{"class":433,"line":4030},[431,42542,20480],{"class":654},[431,42544,4804],{"class":437},[431,42546,42547],{"class":441},"(m_list) ",[431,42549,8409],{"class":654},[431,42551,689],{"class":437},[431,42553,8102],{"class":441},[431,42555,42556,42558,42561,42563,42565,42567,42569,42571,42573,42575,42577,42579,42581,42583,42585,42587],{"class":433,"line":4419},[431,42557,6599],{"class":654},[431,42559,42560],{"class":441}," m_list[",[431,42562,3302],{"class":437},[431,42564,4049],{"class":441},[431,42566,10399],{"class":654},[431,42568,42560],{"class":441},[431,42570,3302],{"class":437},[431,42572,4049],{"class":441},[431,42574,8883],{"class":654},[431,42576,42560],{"class":441},[431,42578,1192],{"class":437},[431,42580,4049],{"class":441},[431,42582,10515],{"class":654},[431,42584,42560],{"class":441},[431,42586,1192],{"class":437},[431,42588,3568],{"class":441},[431,42590,42591,42594,42596,42599,42601],{"class":433,"line":4436},[431,42592,42593],{"class":441},"  s_max ",[431,42595,1189],{"class":654},[431,42597,42598],{"class":441}," maxx(m_list[",[431,42600,1192],{"class":437},[431,42602,42603],{"class":441},":])\n",[431,42605,42606,42608,42610,42612,42614,42616,42618,42620,42622,42624,42627,42629],{"class":433,"line":4446},[431,42607,20132],{"class":654},[431,42609,42560],{"class":441},[431,42611,3302],{"class":437},[431,42613,4049],{"class":441},[431,42615,10399],{"class":654},[431,42617,42560],{"class":441},[431,42619,3302],{"class":437},[431,42621,4049],{"class":441},[431,42623,8883],{"class":654},[431,42625,42626],{"class":441}," s_max ",[431,42628,10515],{"class":654},[431,42630,42631],{"class":441}," s_max\n",[632,42633,270],{"id":42634},"быстрая-сортировка-1",[415,42636,42637],{},"Быстрая сортировка относится к алгоритмам сортировки и она работает намного быстрее сортировки выбором и часто применяется в реальных прогрпаммах.\nБыстрая сортировка основана на стратегии \"разделяй и властвуй\".\nВоспользуемся быстрой сортировкой для упорядочения массива. Как выглядит самый простой массив, с которым может справиться алгоритм сортировки?\nНекоторые массивы вообще не нуждаются в сортировке, например: пустой или с одним элементом – они базовый случай.\nМассивы с одним элементом или пустые нужно сразу возвращать:",[422,42639,42641],{"className":424,"code":42640,"language":396,"meta":426,"style":426},"def quicksort(arr):\n  if len(arr) \u003C 2:\n    return arr\n",[428,42642,42643,42652,42667],{"__ignoreMap":426},[431,42644,42645,42647,42650],{"class":433,"line":434},[431,42646,6330],{"class":654},[431,42648,42649],{"class":6333}," quicksort",[431,42651,41076],{"class":441},[431,42653,42654,42656,42658,42661,42663,42665],{"class":433,"line":452},[431,42655,20480],{"class":654},[431,42657,4804],{"class":437},[431,42659,42660],{"class":441},"(arr) ",[431,42662,8521],{"class":654},[431,42664,689],{"class":437},[431,42666,8102],{"class":441},[431,42668,42669,42671],{"class":433,"line":578},[431,42670,6599],{"class":654},[431,42672,42673],{"class":441}," arr\n",[415,42675,42676],{},"Рассмотрим далее массивы большего размера. Массив из двух элементов тоже сортируется без особых проблем. Сравнить нужно только два элемента – если первый меньше второго, значит меняем их местами.\nА если массив состоит из трёх элементов? То массив уже должен разделяться до тех пор, пока мы не придём к базовому случаю.",[415,42678,42679,42680,42683,42684,42686,42687,42690,42691,42694,42695,42698,42699,42702],{},"Алгоритм быстрой сортировки работает так: сначала в массиве выбирается элемент, который называется ",[1355,42681,42682],{},"опорным",".\nО том как выбирается опорный элемент будет написано далее. Пока предположим, что опорным становится ",[428,42685,19593],{}," как первый элемент массива: ",[428,42688,42689],{},"[30, 15, 10]",".\nТеперь нужно найти элементы меньше опорного и больше опорного. Числа меньше опорного это ",[428,42692,42693],{},"[15, 10]",", а больше опорного это пустой массив ",[428,42696,42697],{},"[]",".\nЭтот процесс называется ",[1355,42700,42701],{},"разделением."," Теперь у нас есть:",[697,42704,42705,42708,42711],{},[700,42706,42707],{},"подмассив всех элементов, меньших опорного;",[700,42709,42710],{},"опорный элемент;",[700,42712,42713],{},"подмассив всех элементов, больших опорного.",[415,42715,42716,42717,42720],{},"Два подмассива не отсортированы – они просто выделены из исходного массива. Но если бы они были отсортированы, то провести сортировку всего массива было бы несложно.\nЕсли подмассивы отсортированы, то их можно просто объединить в порядке: левый подмассивы – опорный элемент – правый подмассив.\nВ примере получилось бы так: ",[428,42718,42719],{},"[10, 15] + [30] + [] = [10, 15, 30]",", таким образом получился бы отсортированный массив.",[415,42722,42723,42724],{},"Как отсортировать подмассивы?\nНужно применить алгоритм сортировки с базовым и рекурсивным случаем к двум подмассивам, а как только наступит базовый случай – объединить результаты вычислений, получив итоговый отсортированный массив!\nЭто выглядит для примера выше так: ",[428,42725,42726],{},"quicksort([15, 10]) + [30] + quicksort([])  # => [10, 15, 30].",[415,42728,42729,42730,42732,42733,3228,42736,42739],{},"Также допустим, что изначально был выбран в качестве опорного элемента – элемент ",[428,42731,22026],{},".\nПри сравнении получаются два подмассива, которые состоят из одного элемента ",[428,42734,42735],{},"[10]",[428,42737,42738],{},"[30]",", а дальше всё то же самое, чтобы их объединить в один итоговый отсортированный массив.",[415,42741,42742],{},"Алгоритм для сортировки массива из трёх элементов следующий:",[1588,42744,42745,42748,42751],{},[700,42746,42747],{},"Выбрать опорный элемент",[700,42749,42750],{},"Разделить массив на два подмассива: элементы, меньше опорного, и элементы, больше опорного.",[700,42752,42753],{},"Рекурсивно применить быструю сортировку к двум подмассивам.",[415,42755,42756,42757,42760,42761,42763,42764,42767,42768,42771],{},"Рассмотрим массив из четырёх элементов? Пусть будет массив: ",[428,42758,42759],{},"[30, 10, 15, 5]",".\nПредположим, что опорным элементом снова выбрали ",[428,42762,19593],{},". Тогда левый подмассив: ",[428,42765,42766],{},"[10, 15, 5]",".\nДалее вы уже узнали как сортируется массив из трёх элементов(рекурсивно применить к нему снова быструю сортировку).\nСоответственно вы можете отсортировать массив из четырёх элементов и так далее, например из пяти элементов. Почему?\nДопустим имеется массив из 5 элементов: ",[428,42769,42770],{},"[3, 5, 2, 1, 4]",".\nВот как выглядят варианты разделения этого массива в зависимости от выбранного элемента:",[1588,42773,42774,42779,42784,42789,42794],{},[700,42775,42776],{},[428,42777,42778],{},"[] + [1] + [3, 2, 5, 4]",[700,42780,42781],{},[428,42782,42783],{},"[1] + [2] + [3, 5, 4]",[700,42785,42786],{},[428,42787,42788],{},"[2, 1] + [3] + [5, 4]",[700,42790,42791],{},[428,42792,42793],{},"[3, 2, 1] + [4] + [5]",[700,42795,42796],{},[428,42797,42798],{},"[3, 2, 1, 4] + [5] + []",[415,42800,42801],{},"Все эти подмассивы будут содержать от 0 до 4 элементов. И для них выполняется то же самое действие – рекурсивно запускаем алгоритм быстрой сортировки для каждого из подмассивов пока не достигнем базового случая, и наконец просто объединим все подмассивы в один отсортированный массив!\nИтак, решение работает независимо от выбора опорного элемента. Следуя такой же логике, вы можете отсортировать массив из 6 и более элементов по той же схеме и т.д.",[8839,42803,42804],{},[415,42805,42806,42807,42812],{},"Выше был описан метод доказательство по индукции. Это способ доказательства, что ваш алгоритм рабочий.\nКаждое индуктивное доказательство состоит из двух частей: базового и индукционного. Подробнее об этом методе вы можете почитать здесь: ",[1205,42808,42811],{"href":42809,"rel":42810},"https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002F%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%B8%D0%BD%D0%B4%D1%83%D0%BA%D1%86%D0%B8%D1%8F",[1209],"Математическая индукция.","\nЗдесь я лишь упомяну, что это интересный метод доказательства, который согласуется со стратегией \"разделяй и властвуй\".",[415,42814,42815],{},"Вот как выглядит наш код на Python для быстрой сортировки:",[422,42817,42819],{"className":424,"code":42818,"language":396,"meta":426,"style":426},"def quicksort(arr):\n  if len(arr) \u003C 2:  # базовый случай\n    return arr\n  # Далее рекурсивный случай\n  piv = arr[0]  # опорный элемент\n  less = [i for i in arr[1:] if i \u003C= piv]  # подмассив всех элементов меньше или равных опорному\n  great = [i for i in arr[1:] if i > piv]  # подмассив всех элементов больше опорного\n  return quicksort(less) + [piv] + quicksort(great)  # рекурсивный случай\n\nprint(quicksort([10, 5, 30, 15, 20]))  # => [5, 10, 15, 20, 30]\n",[428,42820,42821,42829,42846,42852,42857,42873,42906,42938,42958,42962],{"__ignoreMap":426},[431,42822,42823,42825,42827],{"class":433,"line":434},[431,42824,6330],{"class":654},[431,42826,42649],{"class":6333},[431,42828,41076],{"class":441},[431,42830,42831,42833,42835,42837,42839,42841,42843],{"class":433,"line":452},[431,42832,20480],{"class":654},[431,42834,4804],{"class":437},[431,42836,42660],{"class":441},[431,42838,8521],{"class":654},[431,42840,689],{"class":437},[431,42842,11639],{"class":441},[431,42844,42845],{"class":455},"# базовый случай\n",[431,42847,42848,42850],{"class":433,"line":578},[431,42849,6599],{"class":654},[431,42851,42673],{"class":441},[431,42853,42854],{"class":433,"line":584},[431,42855,42856],{"class":455},"  # Далее рекурсивный случай\n",[431,42858,42859,42862,42864,42866,42868,42870],{"class":433,"line":1244},[431,42860,42861],{"class":441},"  piv ",[431,42863,1189],{"class":654},[431,42865,41086],{"class":441},[431,42867,3302],{"class":437},[431,42869,3612],{"class":441},[431,42871,42872],{"class":455},"# опорный элемент\n",[431,42874,42875,42878,42880,42882,42884,42886,42888,42890,42892,42894,42896,42898,42900,42903],{"class":433,"line":1985},[431,42876,42877],{"class":441},"  less ",[431,42879,1189],{"class":654},[431,42881,30573],{"class":441},[431,42883,14329],{"class":654},[431,42885,12664],{"class":441},[431,42887,14421],{"class":654},[431,42889,41086],{"class":441},[431,42891,1192],{"class":437},[431,42893,24817],{"class":441},[431,42895,10399],{"class":654},[431,42897,12664],{"class":441},[431,42899,12667],{"class":654},[431,42901,42902],{"class":441}," piv]  ",[431,42904,42905],{"class":455},"# подмассив всех элементов меньше или равных опорному\n",[431,42907,42908,42911,42913,42915,42917,42919,42921,42923,42925,42927,42929,42931,42933,42935],{"class":433,"line":2041},[431,42909,42910],{"class":441},"  great ",[431,42912,1189],{"class":654},[431,42914,30573],{"class":441},[431,42916,14329],{"class":654},[431,42918,12664],{"class":441},[431,42920,14421],{"class":654},[431,42922,41086],{"class":441},[431,42924,1192],{"class":437},[431,42926,24817],{"class":441},[431,42928,10399],{"class":654},[431,42930,12664],{"class":441},[431,42932,8883],{"class":654},[431,42934,42902],{"class":441},[431,42936,42937],{"class":455},"# подмассив всех элементов больше опорного\n",[431,42939,42940,42942,42945,42947,42950,42952,42955],{"class":433,"line":4018},[431,42941,20132],{"class":654},[431,42943,42944],{"class":441}," quicksort(less) ",[431,42946,802],{"class":654},[431,42948,42949],{"class":441}," [piv] ",[431,42951,802],{"class":654},[431,42953,42954],{"class":441}," quicksort(great)  ",[431,42956,42957],{"class":455},"# рекурсивный случай\n",[431,42959,42960],{"class":433,"line":4030},[431,42961,1662],{"emptyLinePlaceholder":393},[431,42963,42964,42966,42969,42971,42973,42975,42977,42979,42981,42983,42985,42987,42989],{"class":433,"line":4419},[431,42965,438],{"class":437},[431,42967,42968],{"class":441},"(quicksort([",[431,42970,3565],{"class":437},[431,42972,4846],{"class":441},[431,42974,856],{"class":437},[431,42976,4846],{"class":441},[431,42978,19593],{"class":437},[431,42980,4846],{"class":441},[431,42982,22026],{"class":437},[431,42984,4846],{"class":441},[431,42986,19588],{"class":437},[431,42988,18747],{"class":441},[431,42990,42991],{"class":455},"# => [5, 10, 15, 20, 30]\n",[458,42993,34878],{"id":34877},[415,42995,42996],{},"Алгоритм быстрой сортировки уникален тем, что скорость его зависит от выбора опорного элемента.\nВспомним наиболее типовые варианты времени выполнения алгоритмов по концепции \"О-большое\":",[415,42998,42999],{},[15324,43000],{"alt":43001,"src":43002},"Примеры О-большого","\u002Fimages\u002Fblog\u002Fpython\u002Fst28\u002Fimg2.png",[415,43004,43005],{},"На изображении выше приведены примерные оценки времени выполнения при 10 операциях в секунду. Они не точны, а всего лишь дают представление о том, насколько различается время выполнением того или иного алгоритма.\nНа практике современный ПК конечно способен выполнять гораздо больше чем 10 операций в секунду.",[415,43007,43008,43009,43012,43013,43065,43066,43069,43070,43145,43146,43148,43149,43152,43153,43012,43155,43230],{},"Для каждого времени выполнения приведён также пример алгоритма.\nВ \"худшем\" случае ",[1355,43010,43011],{},"быстрая сортировка"," выполняется за время: ",[33809,43014,43016],{"className":43015,"jax":33813},[33812],[33815,43017,43020,43034],{"style":35005,"xmlns":33818,"width":43018,"height":37685,"role":15324,"focusable":33821,"viewBox":43019,"xmlnsXLink":33823},"6.461ex","0 -833.9 2855.6 1083.9",[33825,43021,43022,43024,43026,43028,43030,43032],{},[33828,43023],{"id":37720,"d":35014},[33828,43025],{"id":37691,"d":35018},[33828,43027],{"id":33846,"d":33847},[33828,43029],{"id":33842,"d":33843},[33828,43031],{"id":37708,"d":35031},[33828,43033],{"id":37723,"d":34245},[33849,43035,43036],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,43037,43038,43042,43046,43056,43060],{"dataMmlNode":33855},[33849,43039,43040],{"dataMmlNode":33858},[33860,43041],{"dataC":35053,"xLinkHref":37829},[33849,43043,43044],{"dataMmlNode":34206,"transform":35057},[33860,43045],{"dataC":35060,"xLinkHref":37732},[33849,43047,43048,43052],{"dataMmlNode":34252,"transform":35064},[33849,43049,43050],{"dataMmlNode":33858},[33860,43051],{"dataC":33894,"xLinkHref":33895},[33849,43053,43054],{"dataMmlNode":33883,"transform":40971},[33860,43055],{"dataC":33887,"xLinkHref":33888},[33849,43057,43058],{"dataMmlNode":34206,"transform":40976},[33860,43059],{"dataC":30851,"xLinkHref":37767},[33849,43061,43063],{"dataMmlNode":34206,"transform":43062},"translate(2577.6,0)",[33860,43064],{"dataC":34278,"xLinkHref":37878},"\nДругой алгоритм сортировки — ",[1355,43067,43068],{},"сортировка слиянием"," работает за время: ",[33809,43071,43073],{"className":43072,"jax":33813},[33812],[33815,43074,43077,43097],{"style":35005,"xmlns":33818,"width":43075,"height":35007,"role":15324,"focusable":33821,"viewBox":43076,"xmlnsXLink":33823},"11.818ex","0 -750 5223.4 1000",[33825,43078,43079,43081,43083,43085,43087,43089,43091,43093,43095],{},[33828,43080],{"id":37892,"d":35014},[33828,43082],{"id":37895,"d":35018},[33828,43084],{"id":40997,"d":33847},[33828,43086],{"id":41000,"d":41001},[33828,43088],{"id":33917,"d":33831},[33828,43090],{"id":33920,"d":33835},[33828,43092],{"id":33923,"d":33839},[33828,43094],{"id":37910,"d":35031},[33828,43096],{"id":37913,"d":34245},[33849,43098,43099],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,43100,43101,43105,43109,43113,43117,43121,43125,43130,43135,43140],{"dataMmlNode":33855},[33849,43102,43103],{"dataMmlNode":33858},[33860,43104],{"dataC":35053,"xLinkHref":37922},[33849,43106,43107],{"dataMmlNode":34206,"transform":35057},[33860,43108],{"dataC":35060,"xLinkHref":37927},[33849,43110,43111],{"dataMmlNode":33858,"transform":35064},[33860,43112],{"dataC":33894,"xLinkHref":41025},[33849,43114,43115],{"dataMmlNode":34206,"transform":41028},[33860,43116],{"dataC":41031,"xLinkHref":41032},[33849,43118,43119],{"dataMmlNode":33858,"transform":41035},[33860,43120],{"dataC":33862,"xLinkHref":33940},[33849,43122,43123],{"dataMmlNode":33858,"transform":41040},[33860,43124],{"dataC":33869,"xLinkHref":33945},[33849,43126,43128],{"dataMmlNode":33858,"transform":43127},"translate(3479.4,0)",[33860,43129],{"dataC":33879,"xLinkHref":33952},[33849,43131,43133],{"dataMmlNode":33858,"transform":43132},"translate(3956.4,0)",[33860,43134],{"dataC":33894,"xLinkHref":41025},[33849,43136,43138],{"dataMmlNode":34206,"transform":43137},"translate(4556.4,0)",[33860,43139],{"dataC":30851,"xLinkHref":37967},[33849,43141,43143],{"dataMmlNode":34206,"transform":43142},"translate(4945.4,0)",[33860,43144],{"dataC":34278,"xLinkHref":37973},"\nВыходит, что ",[1355,43147,43011],{}," ничуть не лучше ",[1355,43150,43151],{},"сортировки выбором","! Но это худший случай, а в \"среднем\" случае ",[1355,43154,43011],{},[33809,43156,43158],{"className":43157,"jax":33813},[33812],[33815,43159,43160,43183],{"style":35005,"xmlns":33818,"width":43075,"height":35007,"role":15324,"focusable":33821,"viewBox":43076,"xmlnsXLink":33823},[33825,43161,43162,43164,43166,43169,43172,43174,43176,43178,43180],{},[33828,43163],{"id":39806,"d":35014},[33828,43165],{"id":39809,"d":35018},[33828,43167],{"id":43168,"d":33847},"MJX-3-TEX-I-1D45B",[33828,43170],{"id":43171,"d":41001},"MJX-3-TEX-N-2217",[33828,43173],{"id":34031,"d":33831},[33828,43175],{"id":39820,"d":33835},[33828,43177],{"id":39823,"d":33839},[33828,43179],{"id":39826,"d":35031},[33828,43181],{"id":43182,"d":34245},"MJX-3-TEX-N-2E",[33849,43184,43185],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,43186,43187,43191,43195,43200,43205,43209,43213,43217,43221,43225],{"dataMmlNode":33855},[33849,43188,43189],{"dataMmlNode":33858},[33860,43190],{"dataC":35053,"xLinkHref":39839},[33849,43192,43193],{"dataMmlNode":34206,"transform":35057},[33860,43194],{"dataC":35060,"xLinkHref":39844},[33849,43196,43197],{"dataMmlNode":33858,"transform":35064},[33860,43198],{"dataC":33894,"xLinkHref":43199},"#MJX-3-TEX-I-1D45B",[33849,43201,43202],{"dataMmlNode":34206,"transform":41028},[33860,43203],{"dataC":41031,"xLinkHref":43204},"#MJX-3-TEX-N-2217",[33849,43206,43207],{"dataMmlNode":33858,"transform":41035},[33860,43208],{"dataC":33862,"xLinkHref":34050},[33849,43210,43211],{"dataMmlNode":33858,"transform":41040},[33860,43212],{"dataC":33869,"xLinkHref":39867},[33849,43214,43215],{"dataMmlNode":33858,"transform":43127},[33860,43216],{"dataC":33879,"xLinkHref":39872},[33849,43218,43219],{"dataMmlNode":33858,"transform":43132},[33860,43220],{"dataC":33894,"xLinkHref":43199},[33849,43222,43223],{"dataMmlNode":34206,"transform":43137},[33860,43224],{"dataC":30851,"xLinkHref":39881},[33849,43226,43227],{"dataMmlNode":34206,"transform":43142},[33860,43228],{"dataC":34278,"xLinkHref":43229},"#MJX-3-TEX-N-2E","\nВы можете спросить:",[697,43232,43233,43236],{},[700,43234,43235],{},"Что понимать под \"худшим\" и \"средним\" случаем?",[700,43237,10396,43238,43240,43241,43243,43244,43247],{},[1355,43239,43011],{}," в среднем выполняется за такое же время как и ",[1355,43242,43068],{},". То почему бы не использовать ",[1355,43245,43246],{},"сортировку слиянием"," всегда? Разве она не быстрее?",[458,43249,43251],{"id":43250},"сортировка-слиянием","Сортировка слиянием",[415,43253,43254],{},"Напишем простую функцию для вывода каждого элемента в списке:",[422,43256,43258],{"className":424,"code":43257,"language":396,"meta":426,"style":426},"def print_items(myList):\n  for item in myList:\n    print(item)\n",[428,43259,43260,43270,43281],{"__ignoreMap":426},[431,43261,43262,43264,43267],{"class":433,"line":434},[431,43263,6330],{"class":654},[431,43265,43266],{"class":6333}," print_items",[431,43268,43269],{"class":441},"(myList):\n",[431,43271,43272,43274,43276,43278],{"class":433,"line":452},[431,43273,20523],{"class":654},[431,43275,21014],{"class":441},[431,43277,14421],{"class":654},[431,43279,43280],{"class":441}," myList:\n",[431,43282,43283,43285],{"class":433,"line":578},[431,43284,6357],{"class":437},[431,43286,21645],{"class":441},[415,43288,43289,43290,43345],{},"Эта функция последовательно переберёт все элементы списка(массива) и выведет их на экран. Так функция перебирает весь список, за время: ",[33809,43291,43293],{"className":43292,"jax":33813},[33812],[33815,43294,43297,43314],{"style":35005,"xmlns":33818,"width":43295,"height":35007,"role":15324,"focusable":33821,"viewBox":43296,"xmlnsXLink":33823},"5.473ex","0 -750 2419 1000",[33825,43298,43299,43302,43305,43308,43311],{},[33828,43300],{"id":43301,"d":35014},"MJX-4-TEX-I-1D442",[33828,43303],{"id":43304,"d":35018},"MJX-4-TEX-N-28",[33828,43306],{"id":43307,"d":33847},"MJX-4-TEX-I-1D45B",[33828,43309],{"id":43310,"d":35031},"MJX-4-TEX-N-29",[33828,43312],{"id":43313,"d":34245},"MJX-4-TEX-N-2E",[33849,43315,43316],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,43317,43318,43323,43328,43333,43339],{"dataMmlNode":33855},[33849,43319,43320],{"dataMmlNode":33858},[33860,43321],{"dataC":35053,"xLinkHref":43322},"#MJX-4-TEX-I-1D442",[33849,43324,43325],{"dataMmlNode":34206,"transform":35057},[33860,43326],{"dataC":35060,"xLinkHref":43327},"#MJX-4-TEX-N-28",[33849,43329,43330],{"dataMmlNode":33858,"transform":35064},[33860,43331],{"dataC":33894,"xLinkHref":43332},"#MJX-4-TEX-I-1D45B",[33849,43334,43336],{"dataMmlNode":34206,"transform":43335},"translate(1752,0)",[33860,43337],{"dataC":30851,"xLinkHref":43338},"#MJX-4-TEX-N-29",[33849,43340,43342],{"dataMmlNode":34206,"transform":43341},"translate(2141,0)",[33860,43343],{"dataC":34278,"xLinkHref":43344},"#MJX-4-TEX-N-2E","\nПредположим далее вы изменили эту функцию и она \"засыпает\" или делает паузу в работе на 1 секунду перед выводом в консоль элемента списка.",[422,43347,43349],{"className":424,"code":43348,"language":396,"meta":426,"style":426},"from time import sleep\ndef print_items_sleep(myList):\n  for item in myList:\n    sleep(1)\n    print(item)\n",[428,43350,43351,43363,43372,43382,43391],{"__ignoreMap":426},[431,43352,43353,43355,43358,43360],{"class":433,"line":434},[431,43354,5373],{"class":654},[431,43356,43357],{"class":441}," time ",[431,43359,5379],{"class":654},[431,43361,43362],{"class":441}," sleep\n",[431,43364,43365,43367,43370],{"class":433,"line":452},[431,43366,6330],{"class":654},[431,43368,43369],{"class":6333}," print_items_sleep",[431,43371,43269],{"class":441},[431,43373,43374,43376,43378,43380],{"class":433,"line":578},[431,43375,20523],{"class":654},[431,43377,21014],{"class":441},[431,43379,14421],{"class":654},[431,43381,43280],{"class":441},[431,43383,43384,43387,43389],{"class":433,"line":584},[431,43385,43386],{"class":441},"    sleep(",[431,43388,1192],{"class":437},[431,43390,449],{"class":441},[431,43392,43393,43395],{"class":433,"line":1244},[431,43394,6357],{"class":437},[431,43396,21645],{"class":441},[415,43398,43399,43400,43403,43404,43479,43480,43484,43485,43488,43489,43491,43492,43495,43496,43500],{},"Обе функции проходят по списку один раз, и обе выполняются за время выполнения O(n). Но ",[428,43401,43402],{},"print_items"," работает намного быстрее, потому что она не делает паузу перед выводом каждого элемента.\nСледовательно, при том что обе функции имеют одинаковое \"О-большое\", реально print_items отрабатывает быстрее! Когда вы используете \"О-большое\" это означает следующее(для O(n)):\n",[33809,43405,43407],{"className":43406,"jax":33813},[33812],[33815,43408,43411,43435],{"style":35005,"xmlns":33818,"width":43409,"height":35007,"role":15324,"focusable":33821,"viewBox":43410,"xmlnsXLink":33823},"8.589ex","0 -750 3796.4 1000",[33825,43412,43413,43416,43419,43423,43426,43429,43432],{},[33828,43414],{"id":43415,"d":35014},"MJX-5-TEX-I-1D442",[33828,43417],{"id":43418,"d":35018},"MJX-5-TEX-N-28",[33828,43420],{"id":43421,"d":43422},"MJX-5-TEX-I-1D450","M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z",[33828,43424],{"id":43425,"d":41001},"MJX-5-TEX-N-2217",[33828,43427],{"id":43428,"d":33847},"MJX-5-TEX-I-1D45B",[33828,43430],{"id":43431,"d":35031},"MJX-5-TEX-N-29",[33828,43433],{"id":43434,"d":34245},"MJX-5-TEX-N-2E",[33849,43436,43437],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,43438,43439,43444,43449,43455,43461,43467,43473],{"dataMmlNode":33855},[33849,43440,43441],{"dataMmlNode":33858},[33860,43442],{"dataC":35053,"xLinkHref":43443},"#MJX-5-TEX-I-1D442",[33849,43445,43446],{"dataMmlNode":34206,"transform":35057},[33860,43447],{"dataC":35060,"xLinkHref":43448},"#MJX-5-TEX-N-28",[33849,43450,43451],{"dataMmlNode":33858,"transform":35064},[33860,43452],{"dataC":43453,"xLinkHref":43454},"1D450","#MJX-5-TEX-I-1D450",[33849,43456,43458],{"dataMmlNode":34206,"transform":43457},"translate(1807.2,0)",[33860,43459],{"dataC":41031,"xLinkHref":43460},"#MJX-5-TEX-N-2217",[33849,43462,43464],{"dataMmlNode":33858,"transform":43463},"translate(2529.4,0)",[33860,43465],{"dataC":33894,"xLinkHref":43466},"#MJX-5-TEX-I-1D45B",[33849,43468,43470],{"dataMmlNode":34206,"transform":43469},"translate(3129.4,0)",[33860,43471],{"dataC":30851,"xLinkHref":43472},"#MJX-5-TEX-N-29",[33849,43474,43476],{"dataMmlNode":34206,"transform":43475},"translate(3518.4,0)",[33860,43477],{"dataC":34278,"xLinkHref":43478},"#MJX-5-TEX-N-2E","\nЗдесь ",[800,43481,43482],{},[1355,43483,27268],{}," – некоторый фиксированный промежуток времени для вашего алгоритма. Он называется ",[1355,43486,43487],{},"константой",".\nВ функциях из примера время выполнения может составлять 10 миллисекунд * n для ",[428,43490,43402],{}," против 1,0010 секунды * n для ",[428,43493,43494],{},"print_items_sleep",".\nОбычно константа игнорируется, потому что если два алгоритма имеют разное время \"О-большое\", она роли не играет. Для примера возьмём бинарный поиск и простой поиск.\nДопустим, такие константы присутствуют в обоих алгоритмах: 10мс * n для простого поиска и 1сек * log n для бинарного поиска.\nНа первый взгляд раз константа намного меньше у простого поиска то мы можем подумать что алгоритм быстрее. Но стоит предположить что поиск ведётся по списку из 4 миллиардов элементов.\nТогда подставим данные ",[800,43497,43498],{},[1355,43499,33806],{}," в формулы мы получим, что время выполнения для простого поиска получится 463 дня, а для бинарного всего лишь 32 секунды(log(4 000 000 000) = 32)!",[415,43502,43503,43504,43509,43510,43513],{},"В некоторых иных случаях ",[1355,43505,43506,43507],{},"константа ",[800,43508,27268],{}," может иметь значение. Один из пример — быстрая сортировка и сортировка слиянием.\n",[1355,43511,43512],{},"У быстрой сортировки эта константа меньше, чем у сортировки слиянием. Поэтому быстрая сортировка всё равно отработает быстрее чем сортировка слиянием несмотря на \"О-большое\".","\nИ на практике быстрая сортировка срабатывает быстрее, потому что \"средний\" случай встречается намного чаще \"худшего\".\nЧто же такое \"средний\" случай по сравнению с \"худшим\"?",[12129,43515,43517],{"id":43516},"средний-и-худший-случай","Средний и худший случай",[415,43519,43520],{},"Быстродействие быстрой сортировки сильно зависит от выбранного опорного элемента.\nПредположим, опорным элементом выбирается первый элемент, а быстрая сортировка применяется к уже отсортированному массиву.\nБыстрая сортировка при этом не проверяет, отсортирован входной массив или нет, она всё равно пытается его отсортировать.\nПример стека вызовов, если в качестве опорного элемента всегда выбирать первый элемент:",[1588,43522,43523,43526,43529,43532,43535,43538,43541,43544],{},[700,43524,43525],{},"[1, 2, 3, 4, 5, 6, 7, 8]",[700,43527,43528],{},"[] + [1] + [2, 3, 4, 5, 6, 7, 8]",[700,43530,43531],{},"[] + [2] + [3, 4, 5, 6, 7, 8]",[700,43533,43534],{},"[] + [3] + [4, 5, 6, 7, 8]",[700,43536,43537],{},"[] + [4] + [5, 6, 7, 8]",[700,43539,43540],{},"[] + [5] + [6, 7, 8]",[700,43542,43543],{},"[] + [6] + [7, 8]",[700,43545,43546],{},"[] + [7] + [8]",[415,43548,43549],{},"Обратите внимание: массив не разделяется на две половины. Вместо этого один из двух подмассивов всегда пуст, так что стек рекурсивных вызовов функции получится очень длинным.\nТеперь предположим, что в качестве опорного всегда выбирается элемент посередине списка. Посмотрим как будет выглядеть стек вызовов функции в этом случае:",[1588,43551,43552,43554,43557,43560],{},[700,43553,43525],{},[700,43555,43556],{},"[1, 2, 3] + [4] + [5, 6, 7, 8]",[700,43558,43559],{},"[1] + [2] + [3]  |  [5] + [6] + [7, 8]",[700,43561,43562],{},"_____________|  [ ] + [7] + [8]",[415,43564,43565],{},"Стек в два раза короче! Список элементов каждый раз в два раза короче! И функция быстрее достигает базового случая!",[415,43567,43568,43569,43729,43730],{},"Первый пример это \"худший сценарий\". Второй – \"лучший\". В \"худшем\" случае размер стека описывается как O(n). В \"лучшем\" случае он составит O(log n).\nНо каким бы способом не был разделён массив – вы всегда обращаетесь к O(n) его элементам.\nПолучается, что \"лучшем\" случае весь алгоритм занимает время: ",[33809,43570,43572],{"className":43571,"jax":33813},[33812],[33815,43573,43576,43606],{"style":35005,"xmlns":33818,"width":43574,"height":35007,"role":15324,"focusable":33821,"viewBox":43575,"xmlnsXLink":33823},"29.51ex","0 -750 13043.4 1000",[33825,43577,43578,43581,43584,43587,43590,43593,43596,43599,43602,43604],{},[33828,43579],{"id":43580,"d":35014},"MJX-6-TEX-I-1D442",[33828,43582],{"id":43583,"d":35018},"MJX-6-TEX-N-28",[33828,43585],{"id":43586,"d":33847},"MJX-6-TEX-I-1D45B",[33828,43588],{"id":43589,"d":35031},"MJX-6-TEX-N-29",[33828,43591],{"id":43592,"d":41001},"MJX-6-TEX-N-2217",[33828,43594],{"id":43595,"d":33831},"MJX-6-TEX-I-1D459",[33828,43597],{"id":43598,"d":33835},"MJX-6-TEX-I-1D45C",[33828,43600],{"id":43601,"d":33839},"MJX-6-TEX-I-1D454",[33828,43603],{"id":34238,"d":34166},[33828,43605],{"id":34244,"d":34245},[33849,43607,43608],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,43609,43610,43615,43620,43625,43630,43636,43641,43646,43652,43658,43664,43669,43674,43679,43684,43689,43694,43699,43704,43709,43714,43719,43724],{"dataMmlNode":33855},[33849,43611,43612],{"dataMmlNode":33858},[33860,43613],{"dataC":35053,"xLinkHref":43614},"#MJX-6-TEX-I-1D442",[33849,43616,43617],{"dataMmlNode":34206,"transform":35057},[33860,43618],{"dataC":35060,"xLinkHref":43619},"#MJX-6-TEX-N-28",[33849,43621,43622],{"dataMmlNode":33858,"transform":35064},[33860,43623],{"dataC":33894,"xLinkHref":43624},"#MJX-6-TEX-I-1D45B",[33849,43626,43627],{"dataMmlNode":34206,"transform":43335},[33860,43628],{"dataC":30851,"xLinkHref":43629},"#MJX-6-TEX-N-29",[33849,43631,43633],{"dataMmlNode":34206,"transform":43632},"translate(2363.2,0)",[33860,43634],{"dataC":41031,"xLinkHref":43635},"#MJX-6-TEX-N-2217",[33849,43637,43639],{"dataMmlNode":33858,"transform":43638},"translate(3085.4,0)",[33860,43640],{"dataC":35053,"xLinkHref":43614},[33849,43642,43644],{"dataMmlNode":34206,"transform":43643},"translate(3848.4,0)",[33860,43645],{"dataC":35060,"xLinkHref":43619},[33849,43647,43649],{"dataMmlNode":33858,"transform":43648},"translate(4237.4,0)",[33860,43650],{"dataC":33862,"xLinkHref":43651},"#MJX-6-TEX-I-1D459",[33849,43653,43655],{"dataMmlNode":33858,"transform":43654},"translate(4535.4,0)",[33860,43656],{"dataC":33869,"xLinkHref":43657},"#MJX-6-TEX-I-1D45C",[33849,43659,43661],{"dataMmlNode":33858,"transform":43660},"translate(5020.4,0)",[33860,43662],{"dataC":33879,"xLinkHref":43663},"#MJX-6-TEX-I-1D454",[33849,43665,43667],{"dataMmlNode":33858,"transform":43666},"translate(5497.4,0)",[33860,43668],{"dataC":33894,"xLinkHref":43624},[33849,43670,43672],{"dataMmlNode":34206,"transform":43671},"translate(6097.4,0)",[33860,43673],{"dataC":30851,"xLinkHref":43629},[33849,43675,43677],{"dataMmlNode":34206,"transform":43676},"translate(6764.2,0)",[33860,43678],{"dataC":34210,"xLinkHref":34269},[33849,43680,43682],{"dataMmlNode":33858,"transform":43681},"translate(7820,0)",[33860,43683],{"dataC":35053,"xLinkHref":43614},[33849,43685,43687],{"dataMmlNode":34206,"transform":43686},"translate(8583,0)",[33860,43688],{"dataC":35060,"xLinkHref":43619},[33849,43690,43692],{"dataMmlNode":33858,"transform":43691},"translate(8972,0)",[33860,43693],{"dataC":33894,"xLinkHref":43624},[33849,43695,43697],{"dataMmlNode":34206,"transform":43696},"translate(9794.2,0)",[33860,43698],{"dataC":41031,"xLinkHref":43635},[33849,43700,43702],{"dataMmlNode":33858,"transform":43701},"translate(10516.4,0)",[33860,43703],{"dataC":33862,"xLinkHref":43651},[33849,43705,43707],{"dataMmlNode":33858,"transform":43706},"translate(10814.4,0)",[33860,43708],{"dataC":33869,"xLinkHref":43657},[33849,43710,43712],{"dataMmlNode":33858,"transform":43711},"translate(11299.4,0)",[33860,43713],{"dataC":33879,"xLinkHref":43663},[33849,43715,43717],{"dataMmlNode":33858,"transform":43716},"translate(11776.4,0)",[33860,43718],{"dataC":33894,"xLinkHref":43624},[33849,43720,43722],{"dataMmlNode":34206,"transform":43721},"translate(12376.4,0)",[33860,43723],{"dataC":30851,"xLinkHref":43629},[33849,43725,43727],{"dataMmlNode":34206,"transform":43726},"translate(12765.4,0)",[33860,43728],{"dataC":34278,"xLinkHref":34279},"\nВ \"худшем\" случае существуют O(n) уровней стека, поэтому алгоритм занимает время: ",[33809,43731,43733],{"className":43732,"jax":33813},[33812],[33815,43734,43737,43761],{"style":35005,"xmlns":33818,"width":43735,"height":37685,"role":15324,"focusable":33821,"viewBox":43736,"xmlnsXLink":33823},"21.302ex","0 -833.9 9415.6 1083.9",[33825,43738,43739,43742,43745,43748,43751,43754,43756,43758],{},[33828,43740],{"id":43741,"d":35014},"MJX-7-TEX-I-1D442",[33828,43743],{"id":43744,"d":35018},"MJX-7-TEX-N-28",[33828,43746],{"id":43747,"d":33847},"MJX-7-TEX-I-1D45B",[33828,43749],{"id":43750,"d":35031},"MJX-7-TEX-N-29",[33828,43752],{"id":43753,"d":41001},"MJX-7-TEX-N-2217",[33828,43755],{"id":34311,"d":34166},[33828,43757],{"id":34301,"d":33843},[33828,43759],{"id":43760,"d":34245},"MJX-7-TEX-N-2E",[33849,43762,43763],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,43764,43765,43770,43775,43780,43785,43790,43794,43798,43802,43807,43812,43817,43822,43833,43838],{"dataMmlNode":33855},[33849,43766,43767],{"dataMmlNode":33858},[33860,43768],{"dataC":35053,"xLinkHref":43769},"#MJX-7-TEX-I-1D442",[33849,43771,43772],{"dataMmlNode":34206,"transform":35057},[33860,43773],{"dataC":35060,"xLinkHref":43774},"#MJX-7-TEX-N-28",[33849,43776,43777],{"dataMmlNode":33858,"transform":35064},[33860,43778],{"dataC":33894,"xLinkHref":43779},"#MJX-7-TEX-I-1D45B",[33849,43781,43782],{"dataMmlNode":34206,"transform":43335},[33860,43783],{"dataC":30851,"xLinkHref":43784},"#MJX-7-TEX-N-29",[33849,43786,43787],{"dataMmlNode":34206,"transform":43632},[33860,43788],{"dataC":41031,"xLinkHref":43789},"#MJX-7-TEX-N-2217",[33849,43791,43792],{"dataMmlNode":33858,"transform":43638},[33860,43793],{"dataC":35053,"xLinkHref":43769},[33849,43795,43796],{"dataMmlNode":34206,"transform":43643},[33860,43797],{"dataC":35060,"xLinkHref":43774},[33849,43799,43800],{"dataMmlNode":33858,"transform":43648},[33860,43801],{"dataC":33894,"xLinkHref":43779},[33849,43803,43805],{"dataMmlNode":34206,"transform":43804},"translate(4837.4,0)",[33860,43806],{"dataC":30851,"xLinkHref":43784},[33849,43808,43810],{"dataMmlNode":34206,"transform":43809},"translate(5504.2,0)",[33860,43811],{"dataC":34210,"xLinkHref":34359},[33849,43813,43815],{"dataMmlNode":33858,"transform":43814},"translate(6560,0)",[33860,43816],{"dataC":35053,"xLinkHref":43769},[33849,43818,43820],{"dataMmlNode":34206,"transform":43819},"translate(7323,0)",[33860,43821],{"dataC":35060,"xLinkHref":43774},[33849,43823,43825,43829],{"dataMmlNode":34252,"transform":43824},"translate(7712,0)",[33849,43826,43827],{"dataMmlNode":33858},[33860,43828],{"dataC":33894,"xLinkHref":43779},[33849,43830,43831],{"dataMmlNode":33883,"transform":40971},[33860,43832],{"dataC":33887,"xLinkHref":34343},[33849,43834,43836],{"dataMmlNode":34206,"transform":43835},"translate(8748.6,0)",[33860,43837],{"dataC":30851,"xLinkHref":43784},[33849,43839,43841],{"dataMmlNode":34206,"transform":43840},"translate(9137.6,0)",[33860,43842],{"dataC":34278,"xLinkHref":43843},"#MJX-7-TEX-N-2E",[415,43845,43846],{},"А теперь главное: \"лучший\" случай это \"средний\" случай. Если вы всегда будите выбирать опорным элементом случайный элемент в массиве, то быстрая сортировка в среднем завершится за время O(n * logn).\nЗа одним исключением: если все элементы массива одинаковы, тогда время выполнения будет худшим. Но на сегодняшний день алгоритм быстрой сортировки – один из самых быстрых алгоритмов сортировки, который также является примером для стратегии \"разделяй и властвуй\".",[415,43848,34817,43849,1853,43851,1857],{},[800,43850,1852],{},[800,43852,1856],{},[1859,43854],{},[632,43856],{"id":426},[29386,43858],{":isAnswers":43859,":isList":43860,":startOl":1192,"isText":43861,"title":29391},"[\"O(n)\",\"O(n)\",\"O(1)\",\"O(n * n)\"]","[\"Вывод значения каждого элемента массива.\",\"Удвоение значения каждого элемента массива.\",\"Удвоение значения только первого элемента массива\",\"Создание таблицы умножения друг на друга для каждого из элементов массива.\"]","Определите \"О-большое\" для каждой из следующих операций",[458,43863],{"id":43864},"_1",[29130,43866],{":isList":43867,"title":30269},"[\"Стратегия \\\"разделяй и властвуй\\\" основана на разбиении задачи на подзадачи. Если эту стратегию использовать со списком или массивом, то базовым случаем, скорее всего будет пустой список или список из одного элемента;\",\"Если вы реализуете алгоритм быстрой сортировки, выберите в качестве опорного элемента случайный элемент;\",\"Из двух алгоритмов с одинаковым временем выполнения \\\"О-большое\\\" один может быть быстрее другого. Именно по этому быстрая сортировка быстрее сортировки слиянием;\",\"При сравнении простой сортировки и бинарной константа почти никогда не играет роли, потому что O(log n) слишком сильно превосходит O(n) по скорости при большом размере массива.\"]",[1862,43869,35276],{},[1862,43871,43872],{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":426,"searchDepth":452,"depth":1244,"links":43874},[43875],{"id":42228,"depth":452,"text":270,"children":43876},[43877,43878,43884],{"id":42251,"depth":578,"text":42252},{"id":42634,"depth":578,"text":270,"children":43879},[43880,43881],{"id":34877,"depth":584,"text":34878},{"id":43250,"depth":584,"text":43251,"children":43882},[43883],{"id":43516,"depth":1244,"text":43517},{"id":426,"depth":578,"text":426,"children":43885},[43886],{"id":43864,"depth":584,"text":426},"2025-11-27","Алгоритм быстрой сортировки массива. Стратегия \"Разделяй и властвуй\"","images\u002Fblog\u002Fpython\u002Fst28\u002Fimg.png",{},{"title":270,"description":43888},"2XcrqR_ezFvqUQ_zWDfB_LMsAH7FKRPbAR8FTiVuPcM",{"id":43894,"title":274,"author":43895,"body":43897,"date":44901,"description":44902,"extension":1887,"image":44903,"meta":44904,"minRead":8382,"navigation":393,"num":30788,"path":275,"seo":44905,"stem":276,"__hash__":44906},"python\u002Fblog\u002Fpython\u002Fst29.md",{"name":402,"avatar":43896},{"src":404,"alt":405},{"type":407,"value":43898,"toc":44887},[43899,43902,43906,43912,43915,43929,43938,43946,43949,43953,43959,43963,43977,43981,43987,44029,44036,44181,44188,44192,44198,44243,44253,44351,44358,44390,44393,44401,44404,44407,44766,44772,44774,44780,44782,44786,44797,44802,44805,44819,44826,44840,44854,44857,44879,44881,44884],[410,43900,274],{"id":43901},"поиск-в-ширину",[29130,43903],{":isList":43904,"title":43905},"[\"Научитесь моделировать сети при помощи новой абстрактной структуры данных – графов.\",\"Освоите алгоритм поиск в ширину – BFS(Breadth-First Search). Примените его в задаче на поиск кратчайшего пути. \",\"Изучите алгоритм топологической сортировки, раскрывающий связи между узлами.\",\"\"]","Из этой статьи вы",[415,43907,43908,43909],{},"До начала чтения основной информации из данной статьи необходимо разобраться, что такое граф. Подробнее о графах и какими они бывают вы можете узнать из другой статьи:\n",[1205,43910,43911],{"href":380},"Теория графов.",[415,43913,43914],{},"После того как вы знаете что такое графы и разобрались с базовым синтаксисом по программированию на Python – можно приступать к изучению алгоритма поиска в ширину!\nАлгоритм поиска в ширину или алгоритм BFS(Breadth-First Search) позволяет найти кратчайшее расстояние между двумя объектами.\nОднако термин \"кратчайшее расстояние\" может иметь много трактовок и значений в разных задачах! Например, с помощью алгоритма поиска в ширину можно:",[697,43916,43917,43920,43923,43926],{},[700,43918,43919],{},"реализовать проверку правописания через минимальное количество изменений, преобразующих ошибочно написанное слово в правильное.",[700,43921,43922],{},"Например: АЛГОРИФМ → АЛГОРИТМ – одно изменение;",[700,43924,43925],{},"найти ближайшего к вам врача с помощью анализа карты в виде графа;",[700,43927,43928],{},"создать поиск или поискового робота.",[415,43930,43931,43932,3228,43935,43937],{},"Одни из самых полезных алгоритмов известных мне, работают с графами.\nРанее был рассмотрен алгоритм бинарного поиска в других двух статьях на сайте: ",[1205,43933,43934],{"href":255},"Реализация алгоритма бинарного поиска",[1205,43936,258],{"href":259},".\nПоиск в ширину также относится к категории алгоритмов поиска, но он работает с графами. Он помогает ответить на вопросы двух типов:",[697,43939,43940,43943],{},[700,43941,43942],{},"тип 1: существует ли путь от узла А к узлу В?",[700,43944,43945],{},"тип 2: как выглядит кратчайший путь от узла А к узлу В?",[415,43947,43948],{},"Начнём с типа 1. Представьте что вы выращиваете яблоки. Вы ищите продавца, который будет продавать их.\nА может продавец найдётся среди ваших друзей во вконтакте? Для начала стоит поискать среди друзей.\nПоиск происходит вполне тривиально.\nСначала нужно построить список ближайших друзей для поиска.\nЗатем обратиться к каждому другу в списке и проверить, продает ли этот друг яблоки.\nДопустим, что ни один из ваших друзей не продаёт яблоки. Теперь поиск продолжается среди друзей ваших друзей.\nКаждый раз, когда вы проверяете кого-то из списка, вы добавляете в список всех его друзей.\nВ таком случае поиск ведётся не только среди друзей, но и среди друзей ваших друзей тоже.\nНапомню: нужно найти в сети хотя бы одного продавца яблок.\nЕсли например, друг Иван, не продаёт яблоки, то в список добавляются его друзья.\nЭто означает, что со временем вы проверите всех его друзей, а потом их друзей и т.д.\nС этим алгоритмом поиск рано или поздно пройдёт по всей сети, пока вы все-таки не наткнетесь на продавца яблок.\nТакой алгоритм и называется поиском в ширину.",[632,43950,43952],{"id":43951},"поиск-кратчайшего-пути","Поиск кратчайшего пути",[415,43954,43955,43956,2699],{},"Удастся ли вам найти ближайшего продавца яблок?\nБудем считать, что ваши друзья — это связи первого уровня, а друзья ваших друзей — связи второго уровня и т.д.\nСвязи первого уровня предпочтительнее связей второго уровня, а связи второго уровня предпочтительнее третьего и т.д.\nОтсюда следует, что поиск по контактам второго уровня не должен производиться, пока вы не будите полностью уверены в том,\nчто среди связей первого уровня нет ни одного продавца яблок.\nПоиск в ширину именно означает, что связи первого уровня будут проверены до связей второго уровня.\nТакже можно объяснить это иначе: связи первого уровня будут добавлены в очередь или список поиска раньше связей второго уровня.\nВы двигаетесь при поиске по списку и по очереди проверяете каждого человека, является ли он продавцом яблок.\nСвязи первого уровня будут проверены до связей второго уровня, так что вы найдёте продавца яблок, ближайшего к вам.\nПоиск в ширину находит не только существует ли путь из точки А в точку В, но и кратчайший путь.\nОбратите внимание: это условие выполняется только в том случае, если поиск осуществляется в порядке добавления людей.\nСледовательно, проверять связи необходимо в порядке их добавления.\nДля операций такого рода существует специальная структура данных, которая называется ",[800,43957,43958],{},"очередью",[458,43960,43962],{"id":43961},"очереди","Очереди",[415,43964,43965,43966,43969,43970,3228,43973,43976],{},"Очередь в программировании работает точно также, как и в реальной жизни.\nПредположим, вы с другом стоите в очереди метро.\nЕсли вы стоите ближе к началу очереди, то первыми сядете в метро.\nСтруктура данных очереди работает аналогично.\nОчереди похожи на ",[1355,43967,43968],{},"стеки",": вы не можете выполнить действия над произвольным элементом.\nВместо этого поддерживаются только две операции: ",[1355,43971,43972],{},"постановка в очередь",[1355,43974,43975],{},"извлечение из очереди",".\nОчередь относится к категории структур данных FIFO(First In, First Out) \"первым вошёл, первым вышел\".\nА стек принадлежит к числу структур данных LIFO(Last In, First Out) \"последним вошёл, первым вышел\".\nЕсли вы поставите в очередь два элемента, то элемент, добавленный первым, будет извлечён из очереди раньше второго.\nЭто можно использовать для реализации списка поиска людей.\nЛюди, добавленные в список первыми, будут извлечены из очереди и проверены первыми.\nТеперь когда вы понимаете, как работает очередь, можно приступать к реализации алгоритма поиска в ширину!",[632,43978,43980],{"id":43979},"реализация-графа","Реализация графа",[415,43982,43983,43984,43986],{},"Для начала необходимо реализовать граф на программном уровне. Граф состоит из нескольких узлов.\nИ каждый узел соединяется с соседними узлами. Как выразить отношения вы и ваши друзья?\nВам уже должна быть знакома такая структура данных как: ",[1355,43985,29235],{},".\nВспомните: хеш-таблица связывает ключ со значением. В данном случае узел должен быть связан со всеми его внешними соседями.\nВот как это на Python:",[422,43988,43990],{"className":424,"code":43989,"language":396,"meta":426,"style":426},"graph = {}\ngraph[\"вы\"] = [\"Иван\", \"Пётр\", \"Нина\"]\n",[428,43991,43992,44001],{"__ignoreMap":426},[431,43993,43994,43997,43999],{"class":433,"line":434},[431,43995,43996],{"class":441},"graph ",[431,43998,1189],{"class":654},[431,44000,29580],{"class":441},[431,44002,44003,44006,44009,44011,44013,44015,44017,44019,44022,44024,44027],{"class":433,"line":452},[431,44004,44005],{"class":441},"graph[",[431,44007,44008],{"class":445},"\"вы\"",[431,44010,4049],{"class":441},[431,44012,1189],{"class":654},[431,44014,17401],{"class":441},[431,44016,29905],{"class":445},[431,44018,4846],{"class":441},[431,44020,44021],{"class":445},"\"Пётр\"",[431,44023,4846],{"class":441},[431,44025,44026],{"class":445},"\"Нина\"",[431,44028,3568],{"class":441},[415,44030,44031,44032,44035],{},"Обратите внимание: элемент \"вы\" отображается на массив.\nСледовательно, результатом выражения ",[428,44033,44034],{},"graph[\"вы\"]"," является массив всех ваших внешних соседей.\nПомните, что внешние соседи — это узлы, к которым обращается узел \"вы\".\nГраф — всего лишь набор узлов и рёбер, поэтому для представления графа на Python ничего больше не потребуется.\nА как насчёт большего графа? Например такого:",[422,44037,44039],{"className":424,"code":44038,"language":396,"meta":426,"style":426},"graph = {}\ngraph[\"вы\"] = [\"Иван\", \"Пётр\", \"Нина\"]\ngraph[\"Иван\"] = [\"Владимир\", \"Степан\"]\ngraph[\"Пётр\"] = [\"Семён\", \"Светлана\"]\ngraph[\"Нина\"] = [\"Светлана\"]\ngraph[\"Владимир\"] = []\ngraph[\"Светлана\"] = []\ngraph[\"Семён\"] = []\ngraph[\"Степан\"] = []\n",[428,44040,44041,44049,44073,44095,44117,44133,44145,44157,44169],{"__ignoreMap":426},[431,44042,44043,44045,44047],{"class":433,"line":434},[431,44044,43996],{"class":441},[431,44046,1189],{"class":654},[431,44048,29580],{"class":441},[431,44050,44051,44053,44055,44057,44059,44061,44063,44065,44067,44069,44071],{"class":433,"line":452},[431,44052,44005],{"class":441},[431,44054,44008],{"class":445},[431,44056,4049],{"class":441},[431,44058,1189],{"class":654},[431,44060,17401],{"class":441},[431,44062,29905],{"class":445},[431,44064,4846],{"class":441},[431,44066,44021],{"class":445},[431,44068,4846],{"class":441},[431,44070,44026],{"class":445},[431,44072,3568],{"class":441},[431,44074,44075,44077,44079,44081,44083,44085,44088,44090,44093],{"class":433,"line":578},[431,44076,44005],{"class":441},[431,44078,29905],{"class":445},[431,44080,4049],{"class":441},[431,44082,1189],{"class":654},[431,44084,17401],{"class":441},[431,44086,44087],{"class":445},"\"Владимир\"",[431,44089,4846],{"class":441},[431,44091,44092],{"class":445},"\"Степан\"",[431,44094,3568],{"class":441},[431,44096,44097,44099,44101,44103,44105,44107,44110,44112,44115],{"class":433,"line":584},[431,44098,44005],{"class":441},[431,44100,44021],{"class":445},[431,44102,4049],{"class":441},[431,44104,1189],{"class":654},[431,44106,17401],{"class":441},[431,44108,44109],{"class":445},"\"Семён\"",[431,44111,4846],{"class":441},[431,44113,44114],{"class":445},"\"Светлана\"",[431,44116,3568],{"class":441},[431,44118,44119,44121,44123,44125,44127,44129,44131],{"class":433,"line":1244},[431,44120,44005],{"class":441},[431,44122,44026],{"class":445},[431,44124,4049],{"class":441},[431,44126,1189],{"class":654},[431,44128,17401],{"class":441},[431,44130,44114],{"class":445},[431,44132,3568],{"class":441},[431,44134,44135,44137,44139,44141,44143],{"class":433,"line":1985},[431,44136,44005],{"class":441},[431,44138,44087],{"class":445},[431,44140,4049],{"class":441},[431,44142,1189],{"class":654},[431,44144,21007],{"class":441},[431,44146,44147,44149,44151,44153,44155],{"class":433,"line":2041},[431,44148,44005],{"class":441},[431,44150,44114],{"class":445},[431,44152,4049],{"class":441},[431,44154,1189],{"class":654},[431,44156,21007],{"class":441},[431,44158,44159,44161,44163,44165,44167],{"class":433,"line":4018},[431,44160,44005],{"class":441},[431,44162,44109],{"class":445},[431,44164,4049],{"class":441},[431,44166,1189],{"class":654},[431,44168,21007],{"class":441},[431,44170,44171,44173,44175,44177,44179],{"class":433,"line":4030},[431,44172,44005],{"class":441},[431,44174,44092],{"class":445},[431,44176,4049],{"class":441},[431,44178,1189],{"class":654},[431,44180,21007],{"class":441},[415,44182,44183,44184,44187],{},"Важен ли порядок добавления пар \"ключ\" — \"значение\"? Нет, не важен. В хеш-таблице(или словарь Python) элементы не упорядочены,\nпоэтому добавлять пары \"ключ — значение\" можно в любом порядке.\nУ Владимира, Светланы, Семёна и Степана внешних соседей нет.\nУ них есть внутренние соседи, поскольку линии со стрелками указывают на них, но не существует стрелок от них к другим узлам.\nТакой граф называется ",[1355,44185,44186],{},"направленным"," — отношения действуют только в одну сторону. В ненаправленном графе стрелок нет.\nНапример, оба следующих графа эквиваленты.\nВ ненаправленных графах не существует деления соседей на \"внутренних\" и \"внешних\" — это просто \"соседи\".",[632,44189,44191],{"id":44190},"реализация-алгоритма","Реализация алгоритма",[415,44193,44194,44195,3562],{},"Всё начинается с создания очереди. В Python создания двусторонней очереди(\"дека\") используется функция ",[428,44196,44197],{},"deque",[422,44199,44201],{"className":424,"code":44200,"language":396,"meta":426,"style":426},"from collections import deque\nsearch_queue = deque() # Создание очереди\nsearch_queue += graph[\"вы\"] # Все соседи добавляются в очередь поиска\n",[428,44202,44203,44214,44227],{"__ignoreMap":426},[431,44204,44205,44207,44209,44211],{"class":433,"line":434},[431,44206,5373],{"class":654},[431,44208,27435],{"class":441},[431,44210,5379],{"class":654},[431,44212,44213],{"class":441}," deque\n",[431,44215,44216,44219,44221,44224],{"class":433,"line":452},[431,44217,44218],{"class":441},"search_queue ",[431,44220,1189],{"class":654},[431,44222,44223],{"class":441}," deque() ",[431,44225,44226],{"class":455},"# Создание очереди\n",[431,44228,44229,44231,44233,44236,44238,44240],{"class":433,"line":578},[431,44230,44218],{"class":441},[431,44232,12563],{"class":654},[431,44234,44235],{"class":441}," graph[",[431,44237,44008],{"class":445},[431,44239,4049],{"class":441},[431,44241,44242],{"class":455},"# Все соседи добавляются в очередь поиска\n",[415,44244,44245,44246,44248,44249,44252],{},"Выражение ",[428,44247,44034],{}," вернёт список всех ваших соседей, например ",[428,44250,44251],{},"[\"Иван\", \"Пётр\", \"Нина\"]",".\nВсе они добавляются в очередь поиска.\nДалее рассмотрим остальное:",[422,44254,44256],{"className":424,"code":44255,"language":396,"meta":426,"style":426},"while search_queue: # пока очередь не опустеет\n    person = search_queue.popleft() # из очереди извлекается первый стоящий в ней элемент\n    # Проверка, не проверяли ли мы уже этого человека(элемент из очереди)\n    if person in searched:  # Отдельное множество элементов searched, в котором храним уже проверенные элементы\n        continue\n    if is_seller(person): # Проверяем является ли этот человек продавцом(является ли элемент тем, который мы ищем)\n        print(person + \" это продавец яблок!\")\n    search_queue += graph[person] # Нет, не является. Все соседи этого элемента добавляются в очередь.\n    # Отмечаем что мы проверяли текущий элемент\n    searched.add(person)\n",[428,44257,44258,44268,44281,44286,44300,44304,44314,44328,44341,44346],{"__ignoreMap":426},[431,44259,44260,44262,44265],{"class":433,"line":434},[431,44261,12737],{"class":654},[431,44263,44264],{"class":441}," search_queue: ",[431,44266,44267],{"class":455},"# пока очередь не опустеет\n",[431,44269,44270,44273,44275,44278],{"class":433,"line":452},[431,44271,44272],{"class":441},"    person ",[431,44274,1189],{"class":654},[431,44276,44277],{"class":441}," search_queue.popleft() ",[431,44279,44280],{"class":455},"# из очереди извлекается первый стоящий в ней элемент\n",[431,44282,44283],{"class":433,"line":578},[431,44284,44285],{"class":455},"    # Проверка, не проверяли ли мы уже этого человека(элемент из очереди)\n",[431,44287,44288,44290,44292,44294,44297],{"class":433,"line":584},[431,44289,10438],{"class":654},[431,44291,17261],{"class":441},[431,44293,14421],{"class":654},[431,44295,44296],{"class":441}," searched:  ",[431,44298,44299],{"class":455},"# Отдельное множество элементов searched, в котором храним уже проверенные элементы\n",[431,44301,44302],{"class":433,"line":1244},[431,44303,22138],{"class":654},[431,44305,44306,44308,44311],{"class":433,"line":1985},[431,44307,10438],{"class":654},[431,44309,44310],{"class":441}," is_seller(person): ",[431,44312,44313],{"class":455},"# Проверяем является ли этот человек продавцом(является ли элемент тем, который мы ищем)\n",[431,44315,44316,44318,44321,44323,44326],{"class":433,"line":2041},[431,44317,11353],{"class":437},[431,44319,44320],{"class":441},"(person ",[431,44322,802],{"class":654},[431,44324,44325],{"class":445}," \" это продавец яблок!\"",[431,44327,449],{"class":441},[431,44329,44330,44333,44335,44338],{"class":433,"line":4018},[431,44331,44332],{"class":441},"    search_queue ",[431,44334,12563],{"class":654},[431,44336,44337],{"class":441}," graph[person] ",[431,44339,44340],{"class":455},"# Нет, не является. Все соседи этого элемента добавляются в очередь.\n",[431,44342,44343],{"class":433,"line":4030},[431,44344,44345],{"class":455},"    # Отмечаем что мы проверяли текущий элемент\n",[431,44347,44348],{"class":433,"line":4419},[431,44349,44350],{"class":441},"    searched.add(person)\n",[415,44352,44353,44354,44357],{},"Затем нужно определить функцию проверки, в нашем примере пусть она называется: ",[428,44355,44356],{},"is_seller",".\nПусть она определит просто является ли человек продавцом яблок или нет. Например, пусть функция будет выглядеть так:",[422,44359,44361],{"className":424,"code":44360,"language":396,"meta":426,"style":426},"def is_seller(name):\n      return name[-1] == 'а'\n",[428,44362,44363,44372],{"__ignoreMap":426},[431,44364,44365,44367,44370],{"class":433,"line":434},[431,44366,6330],{"class":654},[431,44368,44369],{"class":6333}," is_seller",[431,44371,13557],{"class":441},[431,44373,44374,44376,44379,44381,44383,44385,44387],{"class":433,"line":452},[431,44375,22936],{"class":654},[431,44377,44378],{"class":441}," name[",[431,44380,853],{"class":654},[431,44382,1192],{"class":437},[431,44384,4049],{"class":441},[431,44386,8409],{"class":654},[431,44388,44389],{"class":445}," 'а'\n",[415,44391,44392],{},"Проверка довольно-таки глупая, но она здесь просто для примера.\nЭта функция проверяет, заканчивается ли имя человека на букву 'а', и если заканчивается, будем считать его продавцом яблок.\nАлгоритм будет работать до тех пор, пока:",[697,44394,44395,44398],{},[700,44396,44397],{},"не будет найден продавец яблок;",[700,44399,44400],{},"очередь не опустеет(в этом случае продавца не нашли).",[415,44402,44403],{},"Также стоить отметить, что при добавлении друзей(элементов) в очередь может возникнуть ситуация когда такой элемент уже был добавлен в очередь и уже проверялся в цикле.\nЕсли проверять одно и тоже дважды, а то и трижды, вы выполните лишнюю работу, ненужную никому, ни вам ни вашему ПК.\nСледовательно, после проверки человека(элемента из очереди) нужно отметить его как уже проверенного.\nЕсли этого не сделать, может возникнуть бесконечный цикл.\nПоэтому, прежде чем проверять человека, следует убедиться в том, что он не был проверен ранее.\nДля этого мы будем вести множество уже проверенных людей. \"Завернём\" также наш цикл в функцию.",[415,44405,44406],{},"Ну и наконец посмотрим на окончательную версию кода поиска в ширину, в которой учтены все обстоятельства:",[422,44408,44410],{"className":424,"code":44409,"language":396,"meta":426,"style":426},"from collections import deque\n\ndef is_seller(name):\n      return name[-1] == 'а'\n\ngraph = {}\ngraph[\"вы\"] = [\"Иван\", \"Пётр\", \"Нина\"]\ngraph[\"Иван\"] = [\"Владимир\", \"Степан\"]\ngraph[\"Пётр\"] = [\"Семён\", \"Светлана\"]\ngraph[\"Нина\"] = [\"Светлана\"]\ngraph[\"Владимир\"] = []\ngraph[\"Светлана\"] = []\ngraph[\"Семён\"] = []\ngraph[\"Степан\"] = []\n\ndef search(name):\n    search_queue = deque() # Создание очереди\n    search_queue += [name] # Все соседи добавляются в очередь поиска\n    \n    # Через множество, вы можете отслеживать, кого из людей вы уже проверяли ранее\n    searched = set()\n    \n    while search_queue: # пока очередь не опустеет\n        person = search_queue.popleft() # из очереди извлекается первый стоящий в ней элемент\n        # Проверка, не проверяли ли мы уже этого человека(элемент из очереди)\n        if person in searched:\n            continue # начинаем новую итерацию цикла\n        if is_seller(person): # Проверяем является ли этот человек продавцом(является ли элемент тем, который мы ищем)\n            print(person + \" это продавец яблок!\")\n            return True # выходим из функции так как нашли то что искали\n        search_queue += graph[person] # Нет, не является. Все соседи этого элемента добавляются в очередь.\n        # Отмечаем что мы проверяли текущий элемент\n        searched.add(person)\n    return False  # Возвращаем по окончанию цикла False, т.к. не нашли то что искали\n\nsearch(\"вы\")  # Пример запуска функции поиска в ширину\n",[428,44411,44412,44422,44426,44434,44450,44454,44462,44486,44506,44526,44542,44554,44566,44578,44590,44594,44603,44613,44624,44628,44633,44644,44648,44656,44667,44672,44683,44691,44699,44711,44720,44731,44736,44741,44750,44754],{"__ignoreMap":426},[431,44413,44414,44416,44418,44420],{"class":433,"line":434},[431,44415,5373],{"class":654},[431,44417,27435],{"class":441},[431,44419,5379],{"class":654},[431,44421,44213],{"class":441},[431,44423,44424],{"class":433,"line":452},[431,44425,1662],{"emptyLinePlaceholder":393},[431,44427,44428,44430,44432],{"class":433,"line":578},[431,44429,6330],{"class":654},[431,44431,44369],{"class":6333},[431,44433,13557],{"class":441},[431,44435,44436,44438,44440,44442,44444,44446,44448],{"class":433,"line":584},[431,44437,22936],{"class":654},[431,44439,44378],{"class":441},[431,44441,853],{"class":654},[431,44443,1192],{"class":437},[431,44445,4049],{"class":441},[431,44447,8409],{"class":654},[431,44449,44389],{"class":445},[431,44451,44452],{"class":433,"line":1244},[431,44453,1662],{"emptyLinePlaceholder":393},[431,44455,44456,44458,44460],{"class":433,"line":1985},[431,44457,43996],{"class":441},[431,44459,1189],{"class":654},[431,44461,29580],{"class":441},[431,44463,44464,44466,44468,44470,44472,44474,44476,44478,44480,44482,44484],{"class":433,"line":2041},[431,44465,44005],{"class":441},[431,44467,44008],{"class":445},[431,44469,4049],{"class":441},[431,44471,1189],{"class":654},[431,44473,17401],{"class":441},[431,44475,29905],{"class":445},[431,44477,4846],{"class":441},[431,44479,44021],{"class":445},[431,44481,4846],{"class":441},[431,44483,44026],{"class":445},[431,44485,3568],{"class":441},[431,44487,44488,44490,44492,44494,44496,44498,44500,44502,44504],{"class":433,"line":4018},[431,44489,44005],{"class":441},[431,44491,29905],{"class":445},[431,44493,4049],{"class":441},[431,44495,1189],{"class":654},[431,44497,17401],{"class":441},[431,44499,44087],{"class":445},[431,44501,4846],{"class":441},[431,44503,44092],{"class":445},[431,44505,3568],{"class":441},[431,44507,44508,44510,44512,44514,44516,44518,44520,44522,44524],{"class":433,"line":4030},[431,44509,44005],{"class":441},[431,44511,44021],{"class":445},[431,44513,4049],{"class":441},[431,44515,1189],{"class":654},[431,44517,17401],{"class":441},[431,44519,44109],{"class":445},[431,44521,4846],{"class":441},[431,44523,44114],{"class":445},[431,44525,3568],{"class":441},[431,44527,44528,44530,44532,44534,44536,44538,44540],{"class":433,"line":4419},[431,44529,44005],{"class":441},[431,44531,44026],{"class":445},[431,44533,4049],{"class":441},[431,44535,1189],{"class":654},[431,44537,17401],{"class":441},[431,44539,44114],{"class":445},[431,44541,3568],{"class":441},[431,44543,44544,44546,44548,44550,44552],{"class":433,"line":4436},[431,44545,44005],{"class":441},[431,44547,44087],{"class":445},[431,44549,4049],{"class":441},[431,44551,1189],{"class":654},[431,44553,21007],{"class":441},[431,44555,44556,44558,44560,44562,44564],{"class":433,"line":4446},[431,44557,44005],{"class":441},[431,44559,44114],{"class":445},[431,44561,4049],{"class":441},[431,44563,1189],{"class":654},[431,44565,21007],{"class":441},[431,44567,44568,44570,44572,44574,44576],{"class":433,"line":4451},[431,44569,44005],{"class":441},[431,44571,44109],{"class":445},[431,44573,4049],{"class":441},[431,44575,1189],{"class":654},[431,44577,21007],{"class":441},[431,44579,44580,44582,44584,44586,44588],{"class":433,"line":4086},[431,44581,44005],{"class":441},[431,44583,44092],{"class":445},[431,44585,4049],{"class":441},[431,44587,1189],{"class":654},[431,44589,21007],{"class":441},[431,44591,44592],{"class":433,"line":4477},[431,44593,1662],{"emptyLinePlaceholder":393},[431,44595,44596,44598,44601],{"class":433,"line":4482},[431,44597,6330],{"class":654},[431,44599,44600],{"class":6333}," search",[431,44602,13557],{"class":441},[431,44604,44605,44607,44609,44611],{"class":433,"line":4488},[431,44606,44332],{"class":441},[431,44608,1189],{"class":654},[431,44610,44223],{"class":441},[431,44612,44226],{"class":455},[431,44614,44615,44617,44619,44622],{"class":433,"line":4505},[431,44616,44332],{"class":441},[431,44618,12563],{"class":654},[431,44620,44621],{"class":441}," [name] ",[431,44623,44242],{"class":455},[431,44625,44626],{"class":433,"line":12871},[431,44627,31028],{"class":441},[431,44629,44630],{"class":433,"line":2874},[431,44631,44632],{"class":455},"    # Через множество, вы можете отслеживать, кого из людей вы уже проверяли ранее\n",[431,44634,44635,44638,44640,44642],{"class":433,"line":12887},[431,44636,44637],{"class":441},"    searched ",[431,44639,1189],{"class":654},[431,44641,27951],{"class":437},[431,44643,5728],{"class":441},[431,44645,44646],{"class":433,"line":12892},[431,44647,31028],{"class":441},[431,44649,44650,44652,44654],{"class":433,"line":12898},[431,44651,12537],{"class":654},[431,44653,44264],{"class":441},[431,44655,44267],{"class":455},[431,44657,44658,44661,44663,44665],{"class":433,"line":12904},[431,44659,44660],{"class":441},"        person ",[431,44662,1189],{"class":654},[431,44664,44277],{"class":441},[431,44666,44280],{"class":455},[431,44668,44669],{"class":433,"line":8382},[431,44670,44671],{"class":455},"        # Проверка, не проверяли ли мы уже этого человека(элемент из очереди)\n",[431,44673,44674,44676,44678,44680],{"class":433,"line":25829},[431,44675,11471],{"class":654},[431,44677,17261],{"class":441},[431,44679,14421],{"class":654},[431,44681,44682],{"class":441}," searched:\n",[431,44684,44685,44688],{"class":433,"line":25838},[431,44686,44687],{"class":654},"            continue",[431,44689,44690],{"class":455}," # начинаем новую итерацию цикла\n",[431,44692,44693,44695,44697],{"class":433,"line":1890},[431,44694,11471],{"class":654},[431,44696,44310],{"class":441},[431,44698,44313],{"class":455},[431,44700,44701,44703,44705,44707,44709],{"class":433,"line":30788},[431,44702,11484],{"class":437},[431,44704,44320],{"class":441},[431,44706,802],{"class":654},[431,44708,44325],{"class":445},[431,44710,449],{"class":441},[431,44712,44713,44715,44717],{"class":433,"line":31619},[431,44714,11924],{"class":654},[431,44716,9395],{"class":437},[431,44718,44719],{"class":455}," # выходим из функции так как нашли то что искали\n",[431,44721,44722,44725,44727,44729],{"class":433,"line":31664},[431,44723,44724],{"class":441},"        search_queue ",[431,44726,12563],{"class":654},[431,44728,44337],{"class":441},[431,44730,44340],{"class":455},[431,44732,44733],{"class":433,"line":15016},[431,44734,44735],{"class":455},"        # Отмечаем что мы проверяли текущий элемент\n",[431,44737,44738],{"class":433,"line":32022},[431,44739,44740],{"class":441},"        searched.add(person)\n",[431,44742,44743,44745,44747],{"class":433,"line":32027},[431,44744,6599],{"class":654},[431,44746,9405],{"class":437},[431,44748,44749],{"class":455},"  # Возвращаем по окончанию цикла False, т.к. не нашли то что искали\n",[431,44751,44752],{"class":433,"line":32032},[431,44753,1662],{"emptyLinePlaceholder":393},[431,44755,44756,44759,44761,44763],{"class":433,"line":32037},[431,44757,44758],{"class":441},"search(",[431,44760,44008],{"class":445},[431,44762,526],{"class":441},[431,44764,44765],{"class":455},"# Пример запуска функции поиска в ширину\n",[415,44767,44768,44769,44771],{},"Выполните этот код самостоятельно. Замените функцию ",[428,44770,44356],{}," чем-то более содержательным и посмотрите, определит ли она то что вы ожидали.",[458,44773],{"id":426},[415,44775,34817,44776,1853,44778,1857],{},[800,44777,1852],{},[800,44779,1856],{},[1859,44781],{},[458,44783,44785],{"id":44784},"топологическая-сортировка","Топологическая сортировка",[415,44787,44788,44789,44792,44793,44796],{},"Итак, подведём некоторый итог по данному алгоритму. Рассмотрим такое понятие как топологическая сортировка.\n",[800,44790,44791],{},"Алгоритм поиска в ширину (BFS, Breadth-First Search)"," может использоваться для ",[1355,44794,44795],{},"топологической сортировки"," — упорядочивания вершин ориентированного графа так, чтобы каждое ребро u → v шло от более ранней вершины к более поздней.\nИначе говоря, если вершина v зависит от u, то в порядке прохождения u всегда стоит перед v.",[415,44798,44799,44801],{},[1355,44800,44785],{}," — термин из теории графов, который означает линейное упорядочивание вершин ориентированного ациклического графа (DAG — Directed Acyclic Graph).\nТопологическая сортировка возможна только для направленных ациклических графов (DAG).\nЕсли в графе есть цикл, корректного топологического порядка не существует.",[415,44803,44804],{},"Существует два основных алгоритма построения топологической сортировки:",[697,44806,44807,44813],{},[700,44808,44809,44812],{},[800,44810,44811],{},"Алгоритм Кана",". Находит все вершины с нулевой входящей степенью (то есть те, от которых ничего не зависит), добавляет их в очередь. Удаляет вершину из графа, уменьшая входящие степени её соседей. Повторяет процесс, пока не обработаны все вершины. Если в процессе остаются вершины с ненулевой входящей степенью, значит, в графе есть цикл — топологическая сортировка невозможна.",[700,44814,44815,44818],{},[800,44816,44817],{},"Алгоритм на основе поиска в глубину (DFS)",". Обходит граф в глубину, после обработки всех соседей вершины добавляет её в стек. Финальный порядок — это обратный порядок извлечения из стека.",[8839,44820,44821],{},[415,44822,44823,44824],{},"В следующей статье рассмотрен Алгоритм DFS. ",[1205,44825,282],{"href":283},[415,44827,44828,44839],{},[1355,44829,44830,44831,44834,44835,44838],{},"Для топологической сортировки с помощью ",[800,44832,44833],{},"BFS"," используется ",[800,44836,44837],{},"алгоритм Кана",". Этот алгоритм мы и реализовали в примере выше.","\nЕщё раз пропишем его шаги:",[1588,44841,44842,44845,44848,44851],{},[700,44843,44844],{},"Вычислить степень каждой вершины — количество входящих рёбер.",[700,44846,44847],{},"Добавить в очередь все вершины со степенью 0, так как они могут появиться первыми в порядке.",[700,44849,44850],{},"Повторяемо удалять вершину из очереди, добавлять её в список результата и уменьшать степень всех её смежных вершин. Если у какой-то из этих вершин теперь степень 0, её добавляют в очередь.",[700,44852,44853],{},"Этот процесс продолжается, пока очередь не станет пустой, и полученный порядок представляет один допустимый топологический порядок графа.",[458,44855,44856],{"id":36153},"Время выполнения алгоритма",[415,44858,44859,44860,44863,44864,44866,44867,44870,44871,44874,44875,44878],{},"Если поиск продавца яблок был выполнен по всей сети, значит, вы прошли по каждому ребру графа из очереди.\nТаким образом, время выполнения составляет как минимум ",[1355,44861,44862],{},"O(количество рёбер)",".\nТакже в программе должна храниться очередь поиска. Добавление одного элемента в очередь выполняется за постоянное время: ",[1355,44865,40883],{},".\nВыполнение операции для каждого элемента потребует суммарного времени ",[1355,44868,44869],{},"O(количество элементов)",".\nПоиск в ширину выполняется за время ",[1355,44872,44873],{},"O(количество элементов + количество рёбер)",", что обычно записывается в форме ",[1355,44876,44877],{},"O(V + E)",".\nV — количество элементов или вершин; E — количество рёбер или связей между вершинами.",[458,44880],{"id":43864},[29130,44882],{":isList":44883,"title":30269},"[\"Поиск в ширину позволяет определить, существует ли путь из А в В;\",\"Если путь существует, то поиск в ширину находит кратчайший путь;\",\"Если в вашей задаче требуется найти \\\"кратчайшее X\\\", попробуйте смоделировать задачу графом и воспользоваться поиском в ширину для её решения;\",\"В направленных графах есть стрелки, а отношения действуют в направлении стрелки.\",\"В ненаправленных графах стрелок нет, а отношение идёт в обе стороны.\",\"Очередь относится к категории FIFO(\\\"первым вошёл, первым вышел\\\");\",\"Стек относится к категории LIFO(последним пришёл, первым вышел);\",\"Элементы следует проверять в порядке их добавления в список поиска, поэтому он должен быть оформлен в виде очереди, иначе найденный путь не будет кратчайшим;\",\"Позаботьтесь о том, чтобы уже проверенный элемент не проверялся заново, иначе возможен безконечный цикл.\"]",[1862,44885,44886],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":426,"searchDepth":452,"depth":1244,"links":44888},[44889],{"id":43901,"depth":452,"text":274,"children":44890},[44891,44894,44895],{"id":43951,"depth":578,"text":43952,"children":44892},[44893],{"id":43961,"depth":584,"text":43962},{"id":43979,"depth":578,"text":43980},{"id":44190,"depth":578,"text":44191,"children":44896},[44897,44898,44899,44900],{"id":426,"depth":584,"text":426},{"id":44784,"depth":584,"text":44785},{"id":36153,"depth":584,"text":44856},{"id":43864,"depth":584,"text":426},"2026-02-24","Алгоритм поиска в ширину на графах для поиска кратчайших путей. Топологическая сортировка.","images\u002Fblog\u002Fpython\u002Fst29\u002Fimg.png",{},{"title":274,"description":44902},"x1_Bfz8IZ1CpgXvsUXqKysHTVtbqvrj1Lfc41Ak88Ec",{"id":44908,"title":282,"author":44909,"body":44911,"date":45549,"description":45550,"extension":1887,"image":45551,"meta":45552,"minRead":8382,"navigation":393,"num":31619,"path":283,"seo":45553,"stem":284,"__hash__":45554},"python\u002Fblog\u002Fpython\u002Fst30.md",{"name":402,"avatar":44910},{"src":404,"alt":405},{"type":407,"value":44912,"toc":45535},[44913,44916,44919,44922,44926,44929,44932,44938,44941,44945,44952,44963,44966,45157,45160,45173,45175,45178,45313,45316,45320,45327,45331,45338,45342,45361,45366,45370,45375,45379,45393,45401,45404,45412,45420,45425,45430,45436,45441,45446,45451,45456,45462,45468,45477,45494,45511,45518,45527,45529,45532],[410,44914,282],{"id":44915},"поиск-в-глубину",[29130,44917],{":isList":44918,"title":43905},"[\"Узнаете, что такое дерево и чем дерево отличается от графа.\",\"Освоите выполнения алгоритмов с деревьями.\",\"Реализуете алгоритм поиска в глубину DFS (Depth-First Search) и узнаете, чем он отличается от алгоритма поиска в ширину BFS(Breadth-First Search).\",\"Познакомитесь с кодом Хаффмана — алгоритмом сжатия, использующим деревья.\"]",[415,44920,44921],{},"Что общего у алгоритмов сжатия и хранения информации в базе данных?\nВ их основе часто лежит дерево, выполняющее всю работу.\nДеревья составляют подмножество графов. Деревья стоит рассматривать отдельно, так как у них есть много специализированных разновидностей.\nНапример, в коде Хаффмана применяются бинарные деревья.\nМногие базы данных используют сбалансированные деревья(например B-деревья). Видов деревьев довольно много.\nЧтобы вам легче было разобраться в них далее будет описаны некоторые из них с необходимой терминологией и концепциями.",[632,44923,44925],{"id":44924},"дерево","Дерево",[415,44927,44928],{},"Дерево — это разновидность графа. Более подробное определение дадим позже, а пока рассмотрим пример.",[415,44930,44931],{},"Как и граф, дерево состоит из узлов и рёбер.",[415,44933,44934],{},[15324,44935],{"alt":44936,"src":44937},"Пример дерева","\u002Fimages\u002Fblog\u002Fpython\u002Fst30\u002Fimg_1.png",[415,44939,44940],{},"Мы будем работать с однокоренными деревьями.\nЭто означает, что у корневого дерева имеется один узел, от которого можно перейти к любому другому узлу.\nТак что говоря о дереве, я имею в виду корневое дерево.\nУ узлов могут быть дочерние узлы, а у дочерних узлов может быть родительский узел.\nВ дереве узлы имеют по крайней мере одного родителя.\nСуществует только один узел без родителя — это корневой узел.\nУзлы, не имеющие дочерних узлов, называются листовыми узлами (листьями).\nЕсли вы поняли, что такое корень, лист, родительский и дочерний узел, значит, можно читать дальше!",[458,44942,44944],{"id":44943},"каталоги-файлов","Каталоги файлов",[415,44946,44947,44948,44951],{},"Так как дерево является разновидностью графа, к нему можно применить алгоритм работающий с графом.\n",[1205,44949,44950],{"href":275},"В предыдущей статье был рассмотрен алгоритм поиска в ширину.","\nПоиск в ширину можно использовать и с деревом.\nНапример, каталог файлов представляет собой дерево, с которым каждый кто работает за ПК сталкивается.\nПредставьте, что у вас есть некий каталог и по нему требуется вывести имена всех файлов в каталоге, включая все его подкаталоги.\nВ данном случае существует только один подкаталог. Тогда такую задачу можно решить поиск в ширину.\nэАлгоритм поиска в ширину можно использовать не только как инструмент собственно поиска.\nПоиск в ширину является также алгоритмом обхода: он посещает каждый узел дерева(\"обходит\" его).\nВ случае с выводом всех имён файлов в подкаталогах — это то что нужно!\nНам нужен алгоритм, который перейдёт до каждого файла в дереве и выведет его имя. Логика такая:",[1588,44953,44954,44957,44960],{},[700,44955,44956],{},"Посетить каждый узел в дереве.",[700,44958,44959],{},"Если узел является файлом, вывести его имя.",[700,44961,44962],{},"Если узел является каталогом, добавить его в очередь, чтобы затем поискать находящиеся в нём файлы.",[415,44964,44965],{},"Ниже приведён код реализации такой программы(он похож на код для поиска \"продавца яблок\" из прошлой статьи):",[422,44967,44969],{"className":424,"code":44968,"language":396,"meta":426,"style":426},"from os import listdir\nfrom os.path import isfile, join\nfrom collection import deque\n\ndef print_file_names(dir):\n    # Очередь используется для отслеживания каталогов, в которых потом производится поиск\n    s_deque = deque()\n    s_deque.append(dir) \n    while s_deque: # Пока очередь не пуста нужно извлекать из неё каталог для проверки\n      dr = s_deque.popleft() # Извлечь каталог из очереди\n      for file in sorted(listdir(dr)): # Перебрать все файлы и каталоги в извлечённом каталоге\n        f_path = join(dr, file) # Формируем полный путь к файлу\n        if isfile(f_path): # Если файл значит выводим его имя \n          print(file)\n        else:\n          s_deque.append(f_path) # Если каталог то добавляем её в конец очереди для обхода\n\nprint_file_names(\"docs\") # Запуск в качестве примера для некоторого каталога docs\n",[428,44970,44971,44983,44995,45006,45010,45020,45025,45035,45046,45056,45069,45087,45105,45115,45126,45132,45140,45144],{"__ignoreMap":426},[431,44972,44973,44975,44978,44980],{"class":433,"line":434},[431,44974,5373],{"class":654},[431,44976,44977],{"class":441}," os ",[431,44979,5379],{"class":654},[431,44981,44982],{"class":441}," listdir\n",[431,44984,44985,44987,44990,44992],{"class":433,"line":452},[431,44986,5373],{"class":654},[431,44988,44989],{"class":441}," os.path ",[431,44991,5379],{"class":654},[431,44993,44994],{"class":441}," isfile, join\n",[431,44996,44997,44999,45002,45004],{"class":433,"line":578},[431,44998,5373],{"class":654},[431,45000,45001],{"class":441}," collection ",[431,45003,5379],{"class":654},[431,45005,44213],{"class":441},[431,45007,45008],{"class":433,"line":584},[431,45009,1662],{"emptyLinePlaceholder":393},[431,45011,45012,45014,45017],{"class":433,"line":1244},[431,45013,6330],{"class":654},[431,45015,45016],{"class":6333}," print_file_names",[431,45018,45019],{"class":441},"(dir):\n",[431,45021,45022],{"class":433,"line":1985},[431,45023,45024],{"class":455},"    # Очередь используется для отслеживания каталогов, в которых потом производится поиск\n",[431,45026,45027,45030,45032],{"class":433,"line":2041},[431,45028,45029],{"class":441},"    s_deque ",[431,45031,1189],{"class":654},[431,45033,45034],{"class":441}," deque()\n",[431,45036,45037,45040,45043],{"class":433,"line":4018},[431,45038,45039],{"class":441},"    s_deque.append(",[431,45041,45042],{"class":437},"dir",[431,45044,45045],{"class":441},") \n",[431,45047,45048,45050,45053],{"class":433,"line":4030},[431,45049,12537],{"class":654},[431,45051,45052],{"class":441}," s_deque: ",[431,45054,45055],{"class":455},"# Пока очередь не пуста нужно извлекать из неё каталог для проверки\n",[431,45057,45058,45061,45063,45066],{"class":433,"line":4419},[431,45059,45060],{"class":441},"      dr ",[431,45062,1189],{"class":654},[431,45064,45065],{"class":441}," s_deque.popleft() ",[431,45067,45068],{"class":455},"# Извлечь каталог из очереди\n",[431,45070,45071,45073,45076,45078,45081,45084],{"class":433,"line":4436},[431,45072,40536],{"class":654},[431,45074,45075],{"class":7849}," file",[431,45077,21531],{"class":654},[431,45079,45080],{"class":437}," sorted",[431,45082,45083],{"class":441},"(listdir(dr)): ",[431,45085,45086],{"class":455},"# Перебрать все файлы и каталоги в извлечённом каталоге\n",[431,45088,45089,45092,45094,45097,45100,45102],{"class":433,"line":4446},[431,45090,45091],{"class":441},"        f_path ",[431,45093,1189],{"class":654},[431,45095,45096],{"class":441}," join(dr, ",[431,45098,45099],{"class":7849},"file",[431,45101,1014],{"class":441},[431,45103,45104],{"class":455},"# Формируем полный путь к файлу\n",[431,45106,45107,45109,45112],{"class":433,"line":4451},[431,45108,11471],{"class":654},[431,45110,45111],{"class":441}," isfile(f_path): ",[431,45113,45114],{"class":455},"# Если файл значит выводим его имя \n",[431,45116,45117,45120,45122,45124],{"class":433,"line":4086},[431,45118,45119],{"class":437},"          print",[431,45121,442],{"class":441},[431,45123,45099],{"class":7849},[431,45125,449],{"class":441},[431,45127,45128,45130],{"class":433,"line":4477},[431,45129,24030],{"class":654},[431,45131,8102],{"class":441},[431,45133,45134,45137],{"class":433,"line":4482},[431,45135,45136],{"class":441},"          s_deque.append(f_path) ",[431,45138,45139],{"class":455},"# Если каталог то добавляем её в конец очереди для обхода\n",[431,45141,45142],{"class":433,"line":4488},[431,45143,1662],{"emptyLinePlaceholder":393},[431,45145,45146,45149,45152,45154],{"class":433,"line":4505},[431,45147,45148],{"class":441},"print_file_names(",[431,45150,45151],{"class":445},"\"docs\"",[431,45153,1014],{"class":441},[431,45155,45156],{"class":455},"# Запуск в качестве примера для некоторого каталога docs\n",[415,45158,45159],{},"В очереди хранится информация о том, в каких ещё каталогах нужно провести \"обход\" и найти имена файлов.\nВ этом примере присутствует отличие от примера поиска в ширину из прошлой статьи.\nВ примере из статьи про поиск в ширину про \"продавца яблок\" необходимо было следить, проводился ли уже поиск с конкретным человеком(элементом поиска).\nЗдесь этого делать не нужно. В деревьях нет циклов, и в данном случае у каждого узла только один родитель в виде каталога.\nМы здесь не рассматриваем и не сможем случайно ввести программу в бесконечный цикл при обходе подкаталогов, поэтому и нет необходимости отслеживать, в каких каталогах уже был поиск.\nЭто важный вывод который стоит использовать: в деревьях не бывает циклов.",[8839,45161,45162],{},[415,45163,45164,45165,45172],{},"О символических ссылках. Пару слов для тех, кто не знает. Создание символических ссылок открывает возможность создания циклов в каталогах.\nСимволическую ссылку можно создать двумя известными способами в Linux или macOS командой: ln -s \u003Cпуть каталога> \u003Cпуть каталога>\nДля Windows это команда: mklink \u002Fd \u003Cпуть каталога> \u003Cпуть каталога>\nПолучается, что с помощью символической ссылки можно по двум путям попадать фактически в один каталог с файлами.\nКогда система или приложение обращается к символической ссылке, она автоматически перенаправляет запрос к целевому файлу или директории, указанному в ссылке.\nПри представлении такого каталога в виде дерева — каталог уже не будет являться деревом! В примере выше мы такую ситуацию не рассматриваем.\nК слову Python достаточно сообразителен поэтому в бесконечный цикл мы с символическими ссылками не попадаем а получаем в программе ошибку:\n",[1355,45166,45167,45168,45171],{},"OSError: ",[431,45169,45170],{},"Errno 62"," Too many levels of symbolic links"," — т.е. слишком много уровней символических ссылок.",[632,45174,44191],{"id":44190},[415,45176,45177],{},"Обойдём каталог файлов на этот раз рекурсивно:",[422,45179,45181],{"className":424,"code":45180,"language":396,"meta":426,"style":426},"from os import listdir\nfrom os.path import isfile, join\n\ndef print_file_names(dir):\n    # Перебрать все файлы и подкаталоги\n    for file in sorted(listdir(dir)):\n        f_path = join(dir, file) # Формируем полный путь к файлу\n        if isfile(f_path): \n            # Если файл значит выводим его имя \n            print(file)\n        else:\n            # Если каталог то вызываем функцию рекурсивно\n            # Чтобы снова провести обход файлов в подкаталоге как в основном каталоге поиска\n            print_file_names(fullpath)\n\nprint_file_names(\"pics\")\n",[428,45182,45183,45193,45203,45207,45215,45220,45238,45257,45264,45269,45279,45285,45290,45295,45300,45304],{"__ignoreMap":426},[431,45184,45185,45187,45189,45191],{"class":433,"line":434},[431,45186,5373],{"class":654},[431,45188,44977],{"class":441},[431,45190,5379],{"class":654},[431,45192,44982],{"class":441},[431,45194,45195,45197,45199,45201],{"class":433,"line":452},[431,45196,5373],{"class":654},[431,45198,44989],{"class":441},[431,45200,5379],{"class":654},[431,45202,44994],{"class":441},[431,45204,45205],{"class":433,"line":578},[431,45206,1662],{"emptyLinePlaceholder":393},[431,45208,45209,45211,45213],{"class":433,"line":584},[431,45210,6330],{"class":654},[431,45212,45016],{"class":6333},[431,45214,45019],{"class":441},[431,45216,45217],{"class":433,"line":1244},[431,45218,45219],{"class":455},"    # Перебрать все файлы и подкаталоги\n",[431,45221,45222,45224,45226,45228,45230,45233,45235],{"class":433,"line":1985},[431,45223,14745],{"class":654},[431,45225,45075],{"class":7849},[431,45227,21531],{"class":654},[431,45229,45080],{"class":437},[431,45231,45232],{"class":441},"(listdir(",[431,45234,45042],{"class":437},[431,45236,45237],{"class":441},")):\n",[431,45239,45240,45242,45244,45247,45249,45251,45253,45255],{"class":433,"line":2041},[431,45241,45091],{"class":441},[431,45243,1189],{"class":654},[431,45245,45246],{"class":441}," join(",[431,45248,45042],{"class":437},[431,45250,4846],{"class":441},[431,45252,45099],{"class":7849},[431,45254,1014],{"class":441},[431,45256,45104],{"class":455},[431,45258,45259,45261],{"class":433,"line":4018},[431,45260,11471],{"class":654},[431,45262,45263],{"class":441}," isfile(f_path): \n",[431,45265,45266],{"class":433,"line":4030},[431,45267,45268],{"class":455},"            # Если файл значит выводим его имя \n",[431,45270,45271,45273,45275,45277],{"class":433,"line":4419},[431,45272,11484],{"class":437},[431,45274,442],{"class":441},[431,45276,45099],{"class":7849},[431,45278,449],{"class":441},[431,45280,45281,45283],{"class":433,"line":4436},[431,45282,24030],{"class":654},[431,45284,8102],{"class":441},[431,45286,45287],{"class":433,"line":4446},[431,45288,45289],{"class":455},"            # Если каталог то вызываем функцию рекурсивно\n",[431,45291,45292],{"class":433,"line":4451},[431,45293,45294],{"class":455},"            # Чтобы снова провести обход файлов в подкаталоге как в основном каталоге поиска\n",[431,45296,45297],{"class":433,"line":4086},[431,45298,45299],{"class":441},"            print_file_names(fullpath)\n",[431,45301,45302],{"class":433,"line":4477},[431,45303,1662],{"emptyLinePlaceholder":393},[431,45305,45306,45308,45311],{"class":433,"line":4482},[431,45307,45148],{"class":441},[431,45309,45310],{"class":445},"\"pics\"",[431,45312,449],{"class":441},[415,45314,45315],{},"Обратите внимание на этот раз очередь не используется.\nВместо этого алгоритм при обнаружении подкаталога сразу же заходит в него.\nЕстественно что этот второй способ поиска в глубину будет выводить имена файлов в другом порядке, нежели алгоритм с поиском в ширину.\nПоиск в глубину тоже работает с графом и представляет собой алгоритм обхода дерева.\nОтличие от поиска в ширину то что алгоритм поиска в глубину не добавляет подкаталог поиска в очередь, а сразу же заходит в него и ищет в нём файлы.\nПоиск в ширину и поиск в глубину тесно связаны друг с другом. Однако между ними существует важное различие.\nПоиск в глубину не может использоваться для нахождения кратчайшего пути!\nИменно потому что поиск в глубину сразу заходит на максимально возможную глубину по дереву.\nОба алгоритма могут быть использованы для обхода деревьев, но для поиска кратчайшего пути подходит только алгоритм поиска в ширину.\nУ алгоритма поиска в глубину больше применений в топологической сортировке(о ней также было упомянуто в прошлой статье).",[12129,45317,45319],{"id":45318},"определение-дерева","Определение дерева",[415,45321,45322,45323,45326],{},"После рассмотрения примера можно привести более точное определение дерева. Дерево представляет собой ",[1355,45324,45325],{},"связанный ациклический граф.","\nРабота алгоритма поиск в глубину идёт исключительно с корневыми деревьями и связанными графами.\nГлавное, что следует помнить — не должно быть циклов в деревьях которые \"обходит\" алгоритм.",[458,45328,45330],{"id":45329},"бинарные-деревья","Бинарные деревья",[415,45332,45333,45334,45337],{},"Существует множество разных типов деревьев. Бинарные деревья используются исключительно часто.\nБинарное дерево представляет собой особую разновидность дерева, узлы которого могут иметь не более двух дочерних узлов (отсюда и название бинарные или двоичные деревья).\nДочерние узлы традиционно называют ",[1355,45335,45336],{},"левым и правым узлами",".\nПример бинарного дерева — генеалогическое древо, так как у каждого узла имеются два биологических родителя.\nВ таком дереве между узлами существует чёткая связь — все они составляют одну семью.\nОднако данные могут быть произвольными. Важно то, что ни у одного узла не может быть больше двух дочерних узлов.\nИногда встречаются термины \"левое поддерево\" и \"правое поддерево\".\nДалее рассмотрен пример,в котором используется бинарное дерево.",[632,45339,45341],{"id":45340},"код-хаффмана","Код Хаффмана",[415,45343,45344,45345,45350,45351,45354,45355,45358,45359,3562],{},"Код Хаффмана — хороший пример использования бинарных деревьев. Он лежит в основе алгоритмов сжатия текста.\nРазберём как он работает и как в нём применяются деревья.\nПрежде необходимо понять как работает сжатие, и знать, сколько места занимает текстовый файл.\nПредставим файл, содержащий всего одно слово: ",[1355,45346,45347],{},[800,45348,45349],{},"dart",". Сколько места он занимает?\nЧтобы узнать это, можно воспользоваться командой ",[800,45352,45353],{},"stat"," в Unix системах.\nСохраните слово в файле с именем ",[800,45356,45357],{},"test.txt",", а затем воспользуемся командой ",[800,45360,45353],{},[415,45362,45363],{},[428,45364,45365],{},"$ cat test.txt",[415,45367,45368],{},[428,45369,45349],{},[415,45371,45372],{},[428,45373,45374],{},"$ stat -c %s test.txt",[415,45376,45377],{},[428,45378,762],{},[415,45380,45381,45382,45385,45386,45389,45390,45392],{},"Итак, файл занимает 4 байта: по 1 байту на символ.\nВыглядит логично. Если предположить, что мы используем кодировку ISO-8859-1. Каждая буква в ней занимает ровно 1 байт.\nНапример, буква ",[1355,45383,45384],{},"t"," в ISO-8859-1 соответствует код 116, который в двоичной системе записывается в виде 01110100, — итого 8 бит.\nКоды ISO-8859-1 содержатся в интервале от 00000000, что соответствует нуль-символу, до 11111111, что соответствует символу ",[1355,45387,45388],{},"ÿ","(латинская буква ",[1355,45391,39163],{}," в нижнем регистре с тремой).\nВсего существует 256 возможных 8-битовых комбинаций из 0 и 1, так что кодировка ISO-8859-1 способна представить до 256 букв.",[8839,45394,45395],{},[415,45396,45397,45400],{},[800,45398,45399],{},"Кодировки.","\nСуществует множество способов кодирования символов. Можно букву записать в двоичной форме разными способами.\nВсё началось с кодировки ASCII, которая была создана ещё в 1960-х годах в США. ASCII является 7-битной кодировкой.\nК сожалению в неё не вошли многие символы и распространённые обозначения, например, обозначения валют.\nПозже была создана 8 битная кодировка ISO-8859-1, а в дальнейшем выделилось целое семейство ISO-8859.\nВ этой кодировке уже было вдвое больше символов чем в ASCII! Вместо 7 битной из 128 символов стало доступно 256!\nТем не менее этого было недостаточно, и многие страны стали создавать собственные кодировки.\nТак как ISO-8859-1 и ASCII были ориентированы на европейские языки.\nХаос с кодировками при прочтении и отправке текстовых файлов и писем по электронной почте нарастал, пока не появился Юникод!\nЮникод — стандарт кодирования символов который поддерживает символы всех языков.\nЮникод версии 16 по данным на сентябрь 2024 года включает 154 998 символов — большой шаг вперёд по сравнению с 256! Более 1000 это так называемые символы эмодзи.\nВ настоящее время самой популярной кодировкой такого рода считается UTF-8.\nЭта кодировка с переменной длиной кодирования символов; представление одного символа может занимать от 1 до 4 байт(8-32 бит).",[415,45402,45403],{},"Данный пример я специально упростил назвав кодировку ISO-8859-1 с 8-битным представлением символов, — это удобно за счёт постоянной длины кодирования.\nВыделим основное, что из выше изложенного нужно понимать:",[697,45405,45406,45409],{},[700,45407,45408],{},"Алгоритмы сжатия сокращают количество бит, необходимых для представления символов;",[700,45410,45411],{},"UTF-8 современный стандарт кодирования по умолчанию.",[415,45413,45414,45415,45419],{},"Декодируем наше слово ",[1355,45416,45417],{},[800,45418,45349],{}," в двоичное представление: 01100100 01100001 01110010 01110100.\nМожно воспользоваться таблицей кодировки ISO-8859-1 или преобразователем двоичной записи, чтобы упростить задачу.\nТакже при декодировании мы знаем что одна буква занимает 8 бит, поэтому разделяем последовательность на 8-битные блоки, чтобы её проще было читать.\nДля просмотра двоичного кода текста можно воспользоваться утилитой Unix систем.\nВызываем команду xxd для файла test.txt в котором сохранён текст python(предварительно пакет xxd должен быть установлен в системе).\nВот так это выглядит:",[415,45421,45422],{},[428,45423,45424],{},"$ xxd -b test.txt",[415,45426,45427],{},[428,45428,45429],{},"00000000: 01100100 01100001 01110010 01110100 dart",[415,45431,45432,45433,45435],{},"Далее используется сжатие. Для слова ",[1355,45434,45349],{}," не нужны все 256 возможных букв, достаточно четырёх.\nТаким образом, для представления буквы не требуется 8 бит, можно обойтись двумя.\nМожно определить собственную 2-битную кодировку для этих четырёх букв:",[415,45437,45438],{},[428,45439,45440],{},"d = 00",[415,45442,45443],{},[428,45444,45445],{},"a = 01",[415,45447,45448],{},[428,45449,45450],{},"r = 10",[415,45452,45453],{},[428,45454,45455],{},"t = 11",[415,45457,45458,45459,45461],{},"В таком случае можно записать слово ",[1355,45460,45349],{}," в новой нашей кодировке: 00 01 10 11.\nТак работает алгоритм Хаффмана: он ищет все символы в тексте и использует для их представления менее 8 бит.\nВ результате происходит сжатие данных.\nКод Хаффмана генерирует дерево и по этому дереву можно узнать код каждой буквы, начиная с корневого узла.\nКоды букв в кодировке Хаффмана не обязательно должны иметь одинаковую длину.\nЭто важный момент, поэтому рассмотрим ещё один пример.\nПостроим дерево, сгенерированное алгоритмом Хаффмана для фразы \"android paranoid\", будет выглядеть так:",[415,45463,45464],{},[15324,45465],{"alt":45466,"src":45467},"Пример дерева по алгоритму Хаффмана","\u002Fimages\u002Fblog\u002Fpython\u002Fst30\u002Fimg_2.png",[415,45469,45470,45471,45473,45474,45476],{},"Здесь мы видим что код для буквы ",[1355,45472,415],{}," это 0001. А для буквы ",[1355,45475,7989],{}," это уже 10.\nВ данном случае вообще используется три разные длины кодирования символов! Представьте, что вам нужно раскодировать данные: 000101010.\nВ данном случае код может состоять из 2, 3 или 4 цифр! Так как длина кода постоянно может меняться, разбить его на равные фрагменты сразу невозможно.\nЧтобы декодировать, придётся перебирать каждую цифру по отдельности, словно нам их показывают по очереди.\nВот как будем разбирать эту последовательность 000101010 по нашему дереву.",[1588,45478,45479,45482,45485,45488,45491],{},[700,45480,45481],{},"Первая цифра ноль, поэтому идём налево;",[700,45483,45484],{},"Вторая цифра снова ноль, снова идём налево;",[700,45486,45487],{},"Третья также ноль, налево;",[700,45489,45490],{},"Четвёртая цифра 1, мы пришли к букве p по нашему дереву.",[700,45492,45493],{},"Остались данные: 01010. Снова начинаем с корневого узла, чтобы найти остальные буквы.",[415,45495,45496,45497,45500,45501,45504,45505,45507,45508,45510],{},"Нашли закодированное слово? Да, это слова ",[1355,45498,45499],{},"pad"," (с английского ",[1355,45502,45503],{},"блокнот","). Здесь мы видим принципиальное отличие кода Хаффмана от кодировки ISO-8859.\nДлины кодов могут изменяться, поэтому декодирование должно выполняться по-другому.\nУ такой схемы есть своё преимущество. Те буквы которые чаще встречаются в тексте — имеют более короткие коды.\nБуква ",[1355,45506,7989],{}," встречается в тексте три раза, а буква ",[1355,45509,415],{}," всего один раз.\nВместо того чтобы кодировать все буквы 4 битами, алгоритм применяет повышенное сжатие или сокращение кодов для часто используемых в тексте букв!\nВ длинном тексте это обеспечит большой выйгрыш в памяти!",[415,45512,45513,45514,45517],{},"С кодом Хаффмана нет проблемы \"наложения кодов друг на друга\", потому что буквы помещаются только в листовых узлах.\nИ от корневого узла к каждому листовому существует только один уникальный путь — это одно из уникальных свойств деревьев!\nЭто свойство также гарантирует, что каждой букве будет соответствовать только один код.\nКогда декодируются код по одной цифре, предполагается, что в конечном итоге получается буква.\nЕсли бы в графе присутствовал цикл, то такое предположение не работало бы из-за риска попасть в этот самый цикл.\nНо в дереве циклы заведомо отсутствуют, так что алгоритм гарантированно придёт к какой-нибудь букве.\nА также используется корневое дерево и всегда известно с чего начинать декодирование.\nС другой стороны не каждый граф будет иметь корневой узел.\nНаконец, дерево, используемое в алгоритме называется ",[1355,45515,45516],{},"бинарным.","\nУзлы в бинарных деревьях имеют не более двух дочерних узлов — левый и правый, так как в двоичной записи только две цифры 0 и 1.",[8839,45519,45520],{},[415,45521,45522,45523,45526],{},"В следующей статье описаны ",[1205,45524,45525],{"href":287},"сбалансированные деревья"," и их возможные применения.",[458,45528],{"id":426},[29130,45530],{":isList":45531,"title":30269},"[\"Деревья — это разновидность графов, но в деревьях не может быть циклов;\",\"Поиск в глубину — алгоритм обхода графа. Он не подходит для поиска кратчайшего пути(подходит для топологической сортировки).\",\"Бинарное дерево — разновидность дерева, у которого каждый узел может иметь не более двух дочерних узлов;\",\"Unicode является международным стандартом кодирования символов, а кодировка UTF-8 — самая популярная.\"]",[1862,45533,45534],{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":426,"searchDepth":452,"depth":1244,"links":45536},[45537],{"id":44915,"depth":452,"text":282,"children":45538},[45539,45542,45546],{"id":44924,"depth":578,"text":44925,"children":45540},[45541],{"id":44943,"depth":584,"text":44944},{"id":44190,"depth":578,"text":44191,"children":45543},[45544,45545],{"id":45318,"depth":1244,"text":45319},{"id":45329,"depth":584,"text":45330},{"id":45340,"depth":578,"text":45341,"children":45547},[45548],{"id":426,"depth":584,"text":426},"2026-02-27","Алгоритмы с деревьями. Алгоритм поиска в глубину(DFS) на деревьях. Алгоритм Хаффмана.","images\u002Fblog\u002Fpython\u002Fst30\u002Fimg.png",{},{"title":282,"description":45550},"pHes4uqZEfPuofzZ7TsLtY_klwTQzbFdbLSu1BWIDQ8",{"id":45556,"title":286,"author":45557,"body":45559,"date":45957,"description":45958,"extension":1887,"image":45959,"meta":45960,"minRead":12898,"navigation":393,"num":31664,"path":287,"seo":45961,"stem":288,"__hash__":45962},"python\u002Fblog\u002Fpython\u002Fst31.md",{"name":402,"avatar":45558},{"src":404,"alt":405},{"type":407,"value":45560,"toc":45941},[45561,45564,45567,45579,45582,45586,45605,45609,45612,45617,45624,45627,45630,45642,45650,45667,45671,45680,45684,45687,45693,45696,45701,45704,45709,45712,45717,45720,45725,45728,45733,45736,45740,45747,45753,45756,45759,45764,45767,45772,45775,45780,45783,45788,45791,45799,45802,45842,45846,45865,45869,45872,45878,45881,45889,45892,45896,45903,45906,45909,45912,45915,45920,45923,45926,45936,45938],[410,45562,286],{"id":45563},"сбалансированные-деревья",[29130,45565],{":isList":45566,"title":43905},"[\"Узнаете о структуре данных, называемой бинарным деревом поиска (BST, Binary Search Tree).\",\"Разберётесь почему сбалансированные деревья часто бывают эффективнее массивов и связанных списков.\",\"Узнаете о АВЛ-деревьях — разновидности сбалансированного дерева BST.\"]",[8839,45568,45569],{},[415,45570,45571,45572,3228,45575,45578],{},"В предыдущих статьях были рассмотрены два подхода и алгоритмы для поиска по деревьям: ",[1205,45573,45574],{"href":275},"поиск в ширину",[1205,45576,45577],{"href":283},"поиск в глубину",".\nЗдесь далее текст пойдёт о сбалансированных деревьях.",[415,45580,45581],{},"Если связанные списки и массивы не дают нужной производительности, целесообразно обратиться к структуре графов.\nРассмотрим, какой производительности можно добиться с помощью деревьев.\nОтличную производительность могут обеспечивать так называемые сбалансированные деревья.",[632,45583,45585],{"id":45584},"балансировка","Балансировка",[415,45587,45588,45589,45592,45593,45595,45596,45598,45599,45601,45602,45604],{},"Помните бинарный поиск?\nС его помощью можно найти информацию намного быстрее, чем простым поиском — со сложностью ",[1355,45590,45591],{},"O(log n)"," вместо ",[1355,45594,34864],{},".\nНо, есть одна проблема: вставка.\nКонечно, поиск занимает время ",[1355,45597,45591],{},", но массив должен быть отсортирован.\nЕсли требуется вставить новое число в отсортированный массив, это займёт время ",[1355,45600,34864],{},".\nПроблема здесь в том, чтобы найти место для нового значения.\nПридётся передвинуть несколько элементов, чтобы освободить для него место.\nВот если бы вставку можно было выполнить как в связанном списке, где достаточно поменять пару указателей...\nНо минус связанного списка в том, что поиск выполняется за линейное время ",[1355,45603,34864],{},".\nКак взять и использовать только лучшие стороны обоих решений из массивов и связанных списков?",[458,45606,45608],{"id":45607},"скорость-вставки-в-деревьях","Скорость вставки в деревьях",[415,45610,45611],{},"Нам понадобится структура данных объединяющая идеи вставки и поиска.\nЭта структура называется сбалансированное бинарное дерево поиска (BST).\nBST это разновидность бинарного дерева. Рассмотрим пример:",[415,45613,45614],{},[15324,45615],{"alt":44936,"src":45616},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_1.png",[415,45618,45619,45620,45623],{},"Как и в бинарном дереве, каждый узел имеет до двух дочерних узлов: левый и правый.\nНо у этого дерева есть одно свойство, относящее его к BST: ",[1355,45621,45622],{},"значение левого дочернего узла всегда меньше, чем значение узла, а значение правого дочернего узла всегда больше.","\nТаким образом, для корневого узла 10 левый дочерний узел имеет меньшее значение 4, а правый дочерний узел — большее значение 15.\nК тому же, все числа в поддереве левого дочернего узла меньше самого узла!\nЭто особое свойство означает, что поиск будет выполняться очень быстро.",[415,45625,45626],{},"Давайте посмотрим на алгоритм, содержится ли число 6 в этом дереве? Начнём с корневого узла.\nЧисло 6 меньше 10, поэтому проверяем левое поддерево.\nПомните: все узлы с меньшими значениями находятся в левом поддереве, а все узлы с большими значениями — в правом.\nСледовательно, мы сразу понимаем, что проверять узлы справа не нужно, потому что 6 там не будет.\nОпускаясь по левому поддереву от 10, переходим к узлу 4.\nЧисло 6 больше 4, поэтому далее идём направо.\nИ вот мы нашли число 6. Теперь поищем другое число — 8. Поиск происходит аналогично по такому же пути.",[415,45628,45629],{},"Собственно, все рассуждения о деревьях обусловлены одной необходимостью: знать, работают ли они быстрее массивов и связанных списков.\nРассмотрим производительность деревьев, но для этого необходимо учитывать их высоту. Короткие деревья работают быстрее.\nВ лучшем случае высота дерева равна 2. Это означает, что к любому узлу можно перейти от корневого узла максимум за 2 шага.\nВысота дерева для худшего случая с теми же данными будет равна 6.\nЭто означает, что к любому узлу можно перейти от корневого узла максимум за 6 шагов.\nПомните игру с отгадыванием чисел?\nЧтобы угадать число из набора 100 чисел, бинарный поиск потребует максимум 7 попыток, а простому может потребоваться все 100 попыток.\nНечто похожее происходит и с деревьями.",[415,45631,45632,45633,45635,45636,45639,45640],{},"Дерево для худшего случая содержит больше уровней и у него хуже с производительностью.\nВ нём все узлы выстроены в одну линию. Дерево имеет высоту ",[1355,45634,34864],{},", так что поиск будет выполняться за время ",[1355,45637,45638],{},"O(n).","\nПредставить можно так: дерево напоминает связанный список, так как один узел содержит ссылку на другой.\nПоиск по связанному списку выполняется за время ",[1355,45641,45638],{},[415,45643,45644,45645,45647,45648,2699],{},"Дерево для худшего случая имеет высоту ",[1355,45646,45591],{},", а поиск по нему занимает время ",[1355,45649,45591],{},[415,45651,45652,45653,45656,45657,45659,45660,45662,45663,45666],{},"Таким образом, ситуация очень похожа на сравнение бинарного поиска с простым линейным поиском!\nЕсли высота дерева всегда будет обеспечиваться как ",[1355,45654,45655],{},"log n",", то поиск будет выполнятся за время ",[1355,45658,45591],{},".\nНо как добиться, чтобы высота составляла ",[1355,45661,45591],{},"? Кратчайшее время для BST может составлять ",[1355,45664,45665],{},"O(log n).","\nЧтобы этого добиться, нужно сбалансировать дерево. Рассмотрим сбалансированное дерево BST.",[458,45668,45670],{"id":45669},"авл-деревья","АВЛ-деревья",[415,45672,45673,45674,45676,45677,45679],{},"АВЛ-деревья (АВЛ аббревиатура образована от фамилий ученых придумавших эту структуру данных: Адельсон, Вельский, Ландис)\nсоставляют разновидность \"самобалансируемых\" BST.\nЭто означает, что АВЛ-деревья сохраняют высоту ",[1355,45675,45591],{},".\nКаждый раз, когда дерево \"разбалансируется\", то есть его высота становится отличной от O(log n), оно корректирует себя.\nАВЛ-дерево обеспечивает нужную высоту ",[1355,45678,45591],{}," за счёт самобалансировки и поворотов.",[12129,45681,45683],{"id":45682},"повороты-авл-дерева","Повороты АВЛ-дерева",[415,45685,45686],{},"Повороты — популярный метод балансировки деревьев. Представьте, что имеется дерево с тремя узлами.\nЛюбой из них может быть корневым. В результате поворота набор узлов смещается, образуя новую конфигурацию.\nНачнем с двух узлов, рассмотрим поворот:",[415,45688,45689],{},[15324,45690],{"alt":45691,"src":45692},"Пример АВЛ-дерева","\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_2.png",[415,45694,45695],{},"Высоты дочерних узлов неодинаковы: разность между ними не превышает 1.\nОднако разность в 1 уровень приемлема для АВЛ-деревьев. Теперь добавим ещё один узел.",[415,45697,45698],{},[15324,45699],{"alt":45691,"src":45700},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_3.png",[415,45702,45703],{},"Дерево \"разбалансировалось\". Нужно его повернуть.",[415,45705,45706],{},[15324,45707],{"alt":45691,"src":45708},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_4.png",[415,45710,45711],{},"Выполнили поворот влево, теперь дерево снова сбалансировано.\nДобавим ещё один узел.",[415,45713,45714],{},[15324,45715],{"alt":45691,"src":45716},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_5.png",[415,45718,45719],{},"И ещё один.",[415,45721,45722],{},[15324,45723],{"alt":45691,"src":45724},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_6.png",[415,45726,45727],{},"Снова выполним поворот.",[415,45729,45730],{},[15324,45731],{"alt":45691,"src":45732},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_7.png",[415,45734,45735],{},"После поворота АВЛ-деревья перебалансируются.\nЗаметим, что в последнем повороте вместо узла 15 поворачивался узел 30. Разберёмся далее почему так.",[12129,45737,45739],{"id":45738},"как-авл-дерево-узнает-что-требуется-поворот","Как АВЛ-дерево узнает, что требуется поворот?",[415,45741,45742,45743,45746],{},"Чтобы дерево знало, когда требуется самобалансировка, оно должно хранить дополнительную информацию.\nВ каждом узле хранится один или два вида информации: значение высоты или значение, которое иногда называют ",[1355,45744,45745],{},"коэффициентом балансировки",".\nЭтот коэффициент должен быть равен -1, 0 или 1.",[415,45748,45749],{},[15324,45750],{"alt":45751,"src":45752},"Пример АВЛ-деревьев","\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_8.png",[415,45754,45755],{},"Выше на рисунке приведены коэффициенты балансировки только для корневых узлов, но может понадобиться хранить коэффициент балансировки для каждого узла.",[415,45757,45758],{},"Коэффициент балансировки сообщает, какой дочерний узел выше и насколько.\nПо коэффициенту балансировки дерево может определить, когда следует проводить перебалансировку.\nЗначение 0 означает, что дерево сбалансировано.\nСо значениями -1 или 1 все нормально, потому что, АВЛ-деревья не обязаны быть идеально сбалансированы: разность 1 допустима.\nНо если коэффициент балансировки падает ниже -1 или поднимается выше 1, дерево нуждается в перебалансировке.\nНиже пример двух таких деревьев:",[415,45760,45761],{},[15324,45762],{"alt":45751,"src":45763},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_9.png",[415,45765,45766],{},"В каждом узле должна храниться либо высота, либо коэффициент балансировки. Можно хранить и то и другое.\nЕсли известны высоты каждого поддерева, то легко вычисляется коэффициент балансировки.\nРассмотрим пример:",[415,45768,45769],{},[15324,45770],{"alt":45691,"src":45771},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_10.png",[415,45773,45774],{},"Для начала запишем высоту и коэффициент балансировки для каждого узла.\nНа этой схеме В – высота, а К – коэффициент балансировки.\nХраним в данном примере два значения, но достаточно в реализации хранить только одно.\nУ всех корневых узлов коэффициент балансировки равен 0: у них нет дочерних узлов, поэтому и поддерживать баланс не нужно.\nДобавим в дерево новый узел:",[415,45776,45777],{},[15324,45778],{"alt":45691,"src":45779},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_11.png",[415,45781,45782],{},"После того как узел был добавлен, необходимо задать для него высоту и коэффициент балансировки.\nЗатем следует подняться вверх по дереву, обновляя высоты и коэффициенты балансировки для всех его предков.\nПосле вставки нового элемента в дерево — обновляются все коэффициенты балансировки для предков вставленного узла.\nАВЛ-дерево проверяет коэффициент балансировки, чтобы после выполнять перебалансировку.\nВ данном примере выше присутствует коэффициент балансировки -2, это означает что узел в дереве нужно повернуть!\nПовернём узел 10:",[415,45784,45785],{},[15324,45786],{"alt":45691,"src":45787},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_12.png",[415,45789,45790],{},"Теперь дерево сбалансировано. Если продолжить движение вверх по дереву то также ничего балансировать уже будет не нужно.\nДвигаться от \"перебалансированного\" узла вверх по дереву необязательно, потому что АВЛ-деревья требуют не более одной \"перебалансировки\".",[415,45792,45793,45794,45796,45797,2699],{},"Итак, АВЛ-деревья хороши, если требуется сбалансированное дерево BST. АВЛ-деревья обеспечивают производительность поиска ",[1355,45795,45591],{},".\nА что со вставкой? Вставка сводится к поиску места для вставки узла и добавления указателя, как в связанном списке.\nНапример, если необходимо вставить элемент в сбалансированное АВЛ-дерево, то необходимо сначала определить, где добавить указатель.\nИ таким образом, вставка тоже выполняется за время ",[1355,45798,45591],{},[415,45800,45801],{},"Получается что структура данных АВЛ-дерево или сбалансированное дерево BST обеспечивает и быструю вставку и быстрый поиск!\nОбщая информация по трём структурам данных в таблице ниже:",[9256,45803,45804,45819],{},[9259,45805,45806],{},[9262,45807,45808,45810,45813,45816],{},[9265,45809,40868],{},[9265,45811,45812],{},"Отсортированный массив",[9265,45814,45815],{},"Связанный список",[9265,45817,45818],{},"АВЛ-дерево",[9275,45820,45821,45832],{},[9262,45822,45823,45826,45828,45830],{},[9280,45824,45825],{},"Поиск",[9280,45827,45591],{},[9280,45829,34864],{},[9280,45831,45591],{},[9262,45833,45834,45836,45838,45840],{},[9280,45835,40890],{},[9280,45837,34864],{},[9280,45839,40883],{},[9280,45841,45591],{},[458,45843,45845],{"id":45844},"косые-деревья","Косые деревья",[415,45847,45848,45849,45851,45852,45855,45856,45858,45859,45861,45862,45864],{},"Косые деревья или Splay-деревья представляют другой подход к сбалансированным деревьям BST.\nИх самое лучшее свойство в том, что если был произведён недавно поиск какого-то элемента, то следующий поиск будет быстрее.\nЭто свойство интуитивно рассматривается положительно.\nПредставьте, что необходимо реализовать работу с программой, которая получает почтовый индекс и находит по нему город.\nИ также представьте, что необходимо многократно каждый раз получать и проводить поиск одного и того же почтового индекса.\nПочему бы не запомнить прошлый результат поиска? Косые деревья позволяют это сделать.\nКогда происходит поиск в косом дереве, он становится после нахождения новым корневым узлом.\nТак при повторном поиске этот же узел будет найден сразу же!\nВ общем случае узлы, которые недавно искали, группируются ближе к корню и находятся быстрее.\nС другой стороны, дерево заведомо не будет сбалансировано, а значит, некоторые операции поиска будут занимать время, большее чем ",[1355,45850,45591],{},", и даже достигать линейного времени!\nКроме того, может потребоваться повернуть узел до корневой позиции, если он ещё некорневой,а это тоже потребует времени.\nНо в целом рассматривая реализацию конкретной задачи, нас должно устраивать, что дерево не будет сбалансировано постоянно.\nГлавное, что при проведении n операций поиска общее время ",[1355,45853,45854],{},"O(n log n)"," гарантированно — т.е. ",[1355,45857,45591],{}," на один поиск.\nТаким образом, хотя один поиск может занять время, превышающее ",[1355,45860,45591],{},", в среднем все операции поиска сходятся ко времени ",[1355,45863,45591],{},", а цель как раз и есть ускорение поиска.",[458,45866,45868],{"id":45867},"b-деревья","B-деревья",[415,45870,45871],{},"B-деревья представляют собой обобщённую форму бинарных деревьев.\nОни часто используются для построения баз данных.\nНиже представлен пример B-дерева:",[415,45873,45874],{},[15324,45875],{"alt":45876,"src":45877},"Пример В-дерева","\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_13.png",[415,45879,45880],{},"Выглядит интересно, правда? Можно заметить, что некоторые узлы имеют более двух дочерних узлов.\nВ отличие от других деревьев поиска (например, двоичного дерева, АВЛ‑дерева),\nгде каждый узел хранит один ключ и максимум двух потомков, в B‑дереве:",[697,45882,45883,45886],{},[700,45884,45885],{},"узел может содержать несколько ключей;",[700,45887,45888],{},"узел может иметь более двух потомков.",[415,45890,45891],{},"B-дерево — это обобщенная форма бинарного дерева поиска.",[12129,45893,45895],{"id":45894},"какие-преимущества-есть-у-b-деревьев","Какие преимущества есть у B-деревьев?",[415,45897,45898,45899,45902],{},"Для B-деревьев существует оптимизация, интересная тем, что применяется на физическом уровне.\nПри поиске по дереву получение данных требует перемещения механических компонентов оборудования (например, считывающей головки HDD диска).\nВремя получения данных называется ",[1355,45900,45901],{},"временем поиска",". Оно может быть важным фактором, определяющим, насколько быстро или медленно работает алгоритм.",[415,45904,45905],{},"Ситуация можно сравнить с посещением магазина. Вы можете покупать продукты по одному. Представьте, что вы решаете купить яблоки.\nВернувшись из магазина, вы понимаете, что было бы неплохо купить ещё и апельсины, и возвращаетесь в магазин.\nПо возвращении вы видите, что у вас закончился шоколад, и снова поход в магазин... Это крайне неэффективно!\nНамного лучше зайти в магазин и купить за раз все необходимые товары, находясь в нём.\nВремя похода в магазин и возвращения из него представляет собой время поиска.",[415,45907,45908],{},"Фундаментальная концепция B-деревьев заключается в том, что после выполнения поиска можно прочитать дополнительные данные в память.\nЭто как сходить в магазин и купить сразу всё необходимое чтобы не ходить в него снова.",[415,45910,45911],{},"В B-деревьях используются большие узлы; каждый узел может иметь больше ключей и дочерних узлов, чем бинарное дерево.\nТаким образом, чтение каждого узла займёт больше времени.\nС другой стороны, поиск при больших данных ускоряется, потому что за один раз читается больший объём данных.\nИменно это обстоятельство обеспечивает высокую скорость работы с B-деревом.",[415,45913,45914],{},"Структура B-деревьев популярна в реализациях баз данных.\nИ это не удивительно, ведь в базах данных много времени занимает чтение с дисков.\nКак происходит обход B-дерева? Начинается всё с нижнего крайнего левого или правого узла.\nА дальше змейкой обход остальных узлов.",[415,45916,45917],{},[15324,45918],{"alt":45876,"src":45919},"\u002Fimages\u002Fblog\u002Fpython\u002Fst31\u002Fimg_14.png",[415,45921,45922],{},"Обратите внимание на свойство как у BST деревьев. Для каждого ключа значения ключей в левом поддереве меньше, а значения ключей в правом поддереве — больше него.\nНапример, для ключа 6 левое поддерево состоит из ключей 4 и 5, а правое поддерево из ключей 7 и 8.\nТакже количество дочерних узлов на 1 больше количества ключей. Таким образом, корневой узел имеет один ключ и два дочерних узла.\nКаждый из дочерних узлов имеет два ключа и три дочерних узла.",[415,45924,45925],{},"На этом можно завершить изучение деревьев.\nВам вряд ли придётся реализовывать их самостоятельно, но важно знать, что деревья — это разновидность графов и они обладают отличной производительностью.",[8839,45927,45928],{},[415,45929,45930,45931,26306,45934,2699],{},"В следующей статье можно узнать о популярном алгоритме на ",[1355,45932,45933],{},"взвешенных графах",[1205,45935,290],{"href":291},[458,45937],{"id":426},[29130,45939],{":isList":45940,"title":30269},"[\"Сбалансированные бинарные деревья поиска (BST) обеспечивают такую же производительность в нотации \\\"О-большое\\\", как массивы, и лучшую производительность вставки;\",\"Высота дерева влияет на его производительность;\",\"АВЛ-деревья — популярная разновидность сбалансированных деревьев BST. Как и большинство сбалансированных деревьев, АВЛ-деревья балансируются поворотом;\",\"В-деревья представляют собой обобщенные деревья BST, у которых каждый узел может иметь несколько ключей и несколько дочерний узлов;\",\"Время поиска можно сравнить со временем похода в магазин. В-деревья минимизируют время поиска за счёт чтения большего объёма данных за одну операцию.\"]",{"title":426,"searchDepth":452,"depth":1244,"links":45942},[45943],{"id":45563,"depth":452,"text":286,"children":45944},[45945],{"id":45584,"depth":578,"text":45585,"children":45946},[45947,45948,45952,45953,45956],{"id":45607,"depth":584,"text":45608},{"id":45669,"depth":584,"text":45670,"children":45949},[45950,45951],{"id":45682,"depth":1244,"text":45683},{"id":45738,"depth":1244,"text":45739},{"id":45844,"depth":584,"text":45845},{"id":45867,"depth":584,"text":45868,"children":45954},[45955],{"id":45894,"depth":1244,"text":45895},{"id":426,"depth":584,"text":426},"2026-03-18","Бинарное дерево поиска. Сбалансированные деревья. АВЛ-деревья. B-деревья.","images\u002Fblog\u002Fpython\u002Fst31\u002Fimg.png",{},{"title":286,"description":45958},"U1JZbz1ZiGqCuuRYsDPrQcc7-GS52-4dE_HCYVSoFwg",{"id":45964,"title":290,"author":45965,"body":45967,"date":47529,"description":47530,"extension":1887,"image":47531,"meta":47532,"minRead":25838,"navigation":393,"num":15016,"path":291,"seo":47533,"stem":292,"__hash__":47534},"python\u002Fblog\u002Fpython\u002Fst32.md",{"name":402,"avatar":45966},{"src":404,"alt":405},{"type":407,"value":45968,"toc":47518},[45969,45972,45975,45983,45989,45995,45999,46002,46008,46011,46025,46031,46034,46040,46043,46051,46057,46060,46063,46074,46077,46083,46088,46091,46093,46099,46105,46116,46119,46122,46125,46129,46132,46138,46141,46144,46150,46153,46158,46163,46169,46172,46178,46184,46190,46200,46203,46206,46216,46219,46229,46232,46235,46238,46244,46247,46251,46254,46260,46263,46269,46272,46278,46281,46287,46290,46296,46311,46315,46318,46324,46327,46340,46343,46394,46401,46427,46430,46467,46470,46563,46570,46639,46642,46694,46697,46713,46716,46870,46877,46988,46991,46994,47494,47502,47504,47507,47513,47515],[410,45970,290],{"id":45971},"алгоритм-дейкстры",[29130,45973],{":isList":45974,"title":43905},"[\"Узнаете о взвешенных графах, где рёбрам назначаются большие или меньшие веса.\",\"Изучите алгоритм Дейкстры, который позволяет получить ответ на вопрос: \\\"Как выглядит кратчайший путь к X?\\\" на взвешенных графах.\",\"Узнаете о циклах в графах, для которых алгоритм Дейкстры не работает.\"]",[8839,45976,45977],{},[415,45978,45979,45980,45982],{},"В предыдущей статье были рассмотрены сбалансированные деревья: ",[1205,45981,286],{"href":287},".\nЗдесь далее текст пойдёт о взвешенных графах и алгоритме Эдсгера Дейкстры.",[415,45984,45985,45986,45988],{},"В статье про ",[1205,45987,45574],{"href":275}," можно увидеть, как найти путь из точки А в точку В.\nНайденный путь не обязательно окажется самым быстрым.\nЭтот путь считается кратчайшим только потому что состоит из наименьшего числа сегментов(рёбер).\nНо представим, что с каждым сегментом связывается продолжительность перемещения.\nИ тогда может выясниться, что существует не самый кратчайший, но более быстрый путь.",[415,45990,45991,45992,2699],{},"Алгоритм поиска в ширину находит путь с минимальным количеством сегментов(рёбер у графа).\nА если необходимо найти самый быстрый путь? Быстрее всего его найти при помощи ",[1355,45993,45994],{},"алгоритма Дейкстры",[632,45996,45998],{"id":45997},"работа-алгоритма-дейкстры","Работа алгоритма Дейкстры",[415,46000,46001],{},"Посмотрим на граф и как алгоритм Дейкстры поработает с таким графом.",[415,46003,46004],{},[15324,46005],{"alt":46006,"src":46007},"Пример взвешенного графа","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_1.png",[415,46009,46010],{},"Каждому ребру назначается время перемещения, например, в минутах.\nАлгоритм Дейкстры используется для поиска пути от начальной точки к конечной за кратчайшее возможное время.\nПрименив к этому графу поиск в ширину, вы получите следующий кратчайший путь: начало → А → конец.\nЭтот путь занимает 7 минут.\nА может существовать путь, который займёт меньше времени? Алгоритм Дейкстры состоит из четырёх шагов:",[1588,46012,46013,46016,46019,46022],{},[700,46014,46015],{},"Найти узел с наименьшей стоимостью (т.е. узел, до которого можно добраться за минимальное время);",[700,46017,46018],{},"Обновить стоимости соседей этого узла;",[700,46020,46021],{},"Повторять, пока это не будет сделано для всех узлов графа;",[700,46023,46024],{},"Вычислить итоговый путь.",[415,46026,46027,46030],{},[1355,46028,46029],{},"Шаг 1:"," найти узел с наименьшей стоимость. В самом начале выбираем, куда направиться: к узлу A или узлу B?\nСколько времени необходимо, чтобы добраться до каждого из этих узлов?",[415,46032,46033],{},"До узла A – 7 минут, а до узла B – 3 минуты. Что касается остальных узлов, о них алгоритм пока ничего не знает.\nТак как время достижения конечного узла остаётся неизвестным, считается, что оно бесконечно.\nУзел B – ближайший, т.к. до него всего 3 минуты.",[415,46035,46036,46039],{},[1355,46037,46038],{},"Шаг 2:"," вычислить, сколько времени потребуется для того, чтобы добраться до всех внешних соседей B при переходе по ребру из B.\nПри этом обнаруживается более короткий путь к узлу A. Ранее до перехода к нему требовалось 7 минут, теперь же 6.",[415,46041,46042],{},"Если находится таким способом, более короткий путь для соседа B, то необходимо обновить его стоимость.\nВ данном случае найдено:",[697,46044,46045,46048],{},[700,46046,46047],{},"более короткий путь к A (сокращение с 7 до 6 минут);",[700,46049,46050],{},"первый путь к конечному узлу до 8 минут.",[415,46052,46053,46056],{},[1355,46054,46055],{},"Шаг 3:"," повторение.",[415,46058,46059],{},"Снова выполняется шаг 1. С узлом B работа закончена, поэтому наименьшая оценка по времени производится по узлу A.",[415,46061,46062],{},"Снова выполняется шаг 2. Обновляем стоимости внешних соседей для узла A.\nАлгоритм вычисляет, что путь до конечного узла теперь занимает 7 минут! Алгоритм на этом завершается.\nК моменту завершения работы алгоритма становится известно:",[697,46064,46065,46068,46071],{},[700,46066,46067],{},"Чтобы добраться до узла B, нужно 3 минуты;",[700,46069,46070],{},"Чтобы добрать до узла A, нужно 6 минут;",[700,46072,46073],{},"Чтобы добраться до конечного узла, нужно 7 минут.",[415,46075,46076],{},"Последний шаг – вычисление итогового пути(разберёмся с ним ниже). А пока просто посмотрим как выглядит итоговой путь:",[415,46078,46079],{},[15324,46080],{"alt":46081,"src":46082},"Пример взвешенного графа: итоговый путь","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_2.png",[8839,46084,46085],{},[415,46086,46087],{},"Алгоритм поиска в ширину не найдёт этот путь как кратчайший, потому что он состоит из трёх рёбер, а от начального до конечного можно добраться всего по двум рёбрам графа.",[415,46089,46090],{},"В предыдущей статье было описание использования алгоритма поиска в ширину для нахождения кратчайшего пути на графе между двумя точками.\nВ той статье под \"кратчайшим путём\" понимался путь с минимальным количеством сегментов.\nС другой стороны, в алгоритме Дейкстры каждому сегменту(ребру графа) присваивается число(вес), а алгоритм Дейкстры находит путь с наименьшим суммарным весом.",[632,46092,40823],{"id":40822},[415,46094,46095,46096,2699],{},"Разберёмся с терминологией.\nКогда используется алгоритм Дейкстры, с каждым ребром графа связывается число, называемое ",[1355,46097,46098],{},"весом",[415,46100,46101],{},[15324,46102],{"alt":46103,"src":46104},"Пример взвешенного графа: веса","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_3.png",[415,46106,46107,46108,46111,46112,46115],{},"Граф с весами называется ",[1355,46109,46110],{},"взвешенным графом",". Граф без весов называется ",[1355,46113,46114],{},"невзвешенным графом",".\nДля вычисления кратчайшего пути в невзвешенном графе используется алгоритм поиска в ширину.\nКратчайшие пути во взвешенном графе вычисляются по алгоритму Дейкстры.",[415,46117,46118],{},"В графах также могут присутствовать циклы.\nЭто означает, что можно из некоторого узла, перемещаться по графу, а потом снова оказаться в том же узле.\nЕсть ли смысл перемещаться по циклу для поиска кратчайшего пути? Правильнее будет использовать путь без прохождения цикла.\nЕсли алгоритму обхода графа пройти по циклу и снова оказаться в том же узле, то цикл лишь добавит лишний вес.\nМожно обойти цикл и два и трижды и т.д., но это лишь добавит лишний вес и увеличит суммарный вес для всего пути.\nСледовательно, путь обхода через цикл или используя цикл — никогда не будет кратчайшим.",[415,46120,46121],{},"Наконец, существует понятие направленных и ненаправленных графов.\nСамо понятие ненаправленного графа означает, что каждый из двух узлов соединённых путём фактически ведёт к другому узлу. Это может быть и цикл.\nВ ненаправленном графе каждое новое ребро добавляет ещё один цикл.\nАлгоритм Дейкстры работает только с графами, в которых нет циклов и где все рёбра неотрицательны.",[415,46123,46124],{},"Далее речь пойдёт о ребрах с положительными весами.",[632,46126,46128],{"id":46127},"история-одного-обмена","История одного обмена",[415,46130,46131],{},"Рассмотрим конкретный пример. Допустим вы хотите поменять свою книгу на планшет.\nЧтобы успешно произвести такой обмен, необходимо понять как потратить наименьшую сумму по цепочке обменов.\nДопустим у нас есть некоторые предложения от других людей. Изобразим выдуманный пример в виде графа:",[415,46133,46134],{},[15324,46135],{"alt":46136,"src":46137},"Пример взвешенного графа обмена","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_4.png",[415,46139,46140],{},"Узлы графа – это предметы, на которые можно поменяться. Веса рёбер представляют сумму доплаты за обмен.\nТаким образом, можно поменять картину на гитару за 300 рублей или же куртку на гитару за 150 рублей(условные суммы).",[415,46142,46143],{},"Как нам вычислить путь от книги до планшета, при котором потратиться наименьшая сумма?\nНа помощь приходит алгоритм Дейкстры! Выполним все 4 шага алгоритма и в конце вычислим итоговый путь по графу.\nПрежде чем начинать, необходимо построить таблицу со стоимостями всех узлов. Таблица будет обновляться по мере работы алгоритма.",[415,46145,46146],{},[15324,46147],{"alt":46148,"src":46149},"Таблица взвешенного графа обмена","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_5.png",[415,46151,46152],{},"Для вычисления итогового пути добавляется столбец – родитель. Итак, приступим к выполнению алгоритма:",[415,46154,46155,46157],{},[1355,46156,46029],{}," найти узел с наименьшей стоимостью. В данном случае самый дешёвый вариант обмена с доплатой 0 рублей это картина.\nВозможно ли получить картину с меньшими затратами?\nЭто очень важный момент.\nУдастся ли найти серию обменов, при которой мы получим картину менее чем за 0 рублей(точнее нам ещё заплатят)?\nПравильный ответ: в данном графе это не удастся.\nТак как картина это узел с наименьшей стоимостью, до которого можно добраться и снизить его заданную стоимость нельзя.\nВ этом заключается суть и идея алгоритма Дейкстры: в графе ищется всегда путь с наименьшей стоимостью.\nПути к этому с картиной с меньшими затратами не существует!",[415,46159,46160,46162],{},[1355,46161,46038],{}," вычислить, сколько времени потребуется для того, чтобы добраться до всех соседей(стоимость).",[415,46164,46165],{},[15324,46166],{"alt":46167,"src":46168},"Пример взвешенного графа обмена: 2 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_6.png",[415,46170,46171],{},"Стоимости гитары и барабана заносятся в таблицу.\nОни были заданы при переходе через узел картины, поэтому картина указывается как их родитель.\nЭто означает, что для того, чтобы добраться до гитары, вы проходите по ребру от картины; то же самое происходит с барабаном.",[415,46173,46174],{},[15324,46175],{"alt":46176,"src":46177},"Таблица взвешенного графа обмена: 2 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_7.png",[415,46179,46180,46183],{},[1355,46181,46182],{},"Снова шаг 1:"," куртка – следующий по стоимости узел(50 рублей).",[415,46185,46186,46189],{},[1355,46187,46188],{},"Снова шаг 2:"," обновляются значения всех его соседей.",[415,46191,46192,46196],{},[15324,46193],{"alt":46194,"src":46195},"Пример взвешенного графа обмена: 4 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_8.png",[15324,46197],{"alt":46198,"src":46199},"Пример взвешенного таблицы обмена: 4 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_9.png",[415,46201,46202],{},"Смотрите, стоимости барабана и гитары обновились!\nЭто означает, что к барабану и гитаре дешевле перейти через ребро, идущее от куртки.\nСоответственно, куртка назначается новым родителем обоих инструментов.",[415,46204,46205],{},"Следующий по стоимости узел – гитара. Обновите данные его соседей.",[415,46207,46208,46212],{},[15324,46209],{"alt":46210,"src":46211},"Пример взвешенного графа обмена: 6 шагов","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_10.png",[15324,46213],{"alt":46214,"src":46215},"Пример взвешенного таблицы обмена: 6 шагов","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_11.png",[415,46217,46218],{},"Наконец-то мы вычислили стоимость для планшета при условии обмена гитары на планшет.\nСоответственно, гитара назначается родителем.\nНаконец, задается стоимость последнего узла – барабана.",[415,46220,46221,46225],{},[15324,46222],{"alt":46223,"src":46224},"Пример взвешенного графа обмена: 8 шагов","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_12.png",[15324,46226],{"alt":46227,"src":46228},"Пример взвешенного таблицы обмена: 8 шагов","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_13.png",[415,46230,46231],{},"Оказывается, вы можете получить планшет дешевле, поменяв барабан на планшет.\nТаким образом, самая дешёвая цепочка обменов обойдётся в 350 рублей.",[415,46233,46234],{},"Теперь, осталось вычислить итоговый путь.\nК этому моменту мы(алгоритм) знаем, что кратчайший путь обойдётся в 350 рублей, но как этот путь определить?",[415,46236,46237],{},"Для начала возьмём родителя для узла \"планшет\".\nВ качестве родителя узла \"планшет\" указан узел \"барабан\".\nА в качестве родителя узла \"барабан\" указан узел \"куртка\".\nСледовательно, вы обмениваете куртку на барабан. И конечно, в самом начале вы меняете книгу на куртку.\nПроходя по родительским узлам в обратном направлении получается полный путь:",[415,46239,46240],{},[15324,46241],{"alt":46242,"src":46243},"Пример взвешенного графа обмена: полный путь","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_14.png",[415,46245,46246],{},"Целью этого примера было показать, что кратчайший путь не всегда связывается с физическим расстоянием:\nон может решать задачу минимизации какой-либо характеристики благодаря тому же алгоритму Дейкстры!",[632,46248,46250],{"id":46249},"рёбра-с-отрицательным-весом","Рёбра с отрицательным весом",[415,46252,46253],{},"Изменим пример выше. Предположим, что существует обмен куртки на картину и при этом вам ещё заплатят 70 рублей.\nВы ничего не тратите при таком обмене, вместо этого вы наоборот получаете!\nИзобразим это на графе:",[415,46255,46256],{},[15324,46257],{"alt":46258,"src":46259},"Пример взвешенного графа обмена: с отрицательным ребром","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_15.png",[415,46261,46262],{},"Ребро, ведущее от куртки к картине, имеет отрицательный вес! Получается также, что к картине можно добраться двумя способами.\nА значит что на обмене с отрицательным весом(когда платите не вы, а вам) появляется смысл – вы получите ещё 20 рублей от начальной суммы.\nТеперь, если вы помните, вы можете обменять картину на барабан. И до этого обмена существуют два пути:\nВторой путь обойдётся на 20 рублей дешевле, поэтому нужно выбрать этот путь.\nНо если применить алгоритм Дейкстры к этому графе, то алгоритм выберет неверный путь!\nАлгоритм пойдёт по более длинному пути.\nАлгоритм Дейкстры не может использоваться при наличии рёбер, имеющих отрицательный вес.\nТакие рёбра нарушают работу алгоритма Дейкстры. Посмотрим на пример: начиная с таблицы стоимостей.",[415,46264,46265],{},[15324,46266],{"alt":46267,"src":46268},"Пример таблицы обмена: для графа с отрицательным ребром","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_16.png",[415,46270,46271],{},"Теперь найдём узел с наименьшей стоимостью и обновим стоимости его соседей.\nВ этом случае картина оказывается узлом с наименьшей стоимостью.\nВ соответствии с алгоритмом Дейкстры, к картине невозможно перейти более дешёвым способом, чем обменом её на вашу книгу(а видя весь граф вы знаете что это неверно!).\nКак бы то ни было, продолжая пример обновим стоимости соседей картины.",[415,46273,46274],{},[15324,46275],{"alt":46276,"src":46277},"Пример таблицы обмена: для графа с отрицательным ребром 2 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_17.png",[415,46279,46280],{},"Получается, что теперь стоимость барабана составляет 350 рублей.\nПерейдём к следующему по стоимости узлу, который ещё не был обработан – это куртка. Обновим стоимости её соседей.",[415,46282,46283],{},[15324,46284],{"alt":46285,"src":46286},"Пример таблицы обмена: для графа с отрицательным ребром 4 шага","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_18.png",[415,46288,46289],{},"Узел \"картина\" уже был обработан, однако алгоритм обновляет его стоимость.\nЭто очень плохой признак – обработка узла означает, что к нему невозможно добраться с меньшими затратами.\nНо вы самостоятельно уже нашли более \"дешёвый\" путь к картине.\nУ барабана соседей нет, поэтому работа алгоритма завершается.\nНиже покажем итоговые стоимости согласно алгоритму Дейкстры:",[415,46291,46292],{},[15324,46293],{"alt":46294,"src":46295},"Пример таблицы обмена: для графа с отрицательным ребром итог","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_19.png",[415,46297,46298,46299,46304,46305,46310],{},"Чтобы добраться до барабана, вам потребовалось 350 рублей.\nВы знаете, что существует путь, который стоит всего 330 рублей, но алгоритм Дейкстры его не находит.\nАлгоритм Дейкстры сразу предположил, что, поскольку вы обрабатываете узел \"картина\", к этому узлу невозможно добраться быстрее!\nЭто предположение работает только в том случае, если рёбер с отрицательным весом не существует.\nСледовательно, ",[800,46300,46301],{},[1355,46302,46303],{},"использование алгоритма Дейкстры с графом, содержащим рёбра с отрицательным весом — невозможно",".\nВ случае с отрицательными весами понадобится алгоритм ",[1205,46306,46309],{"href":46307,"rel":46308},"https:\u002F\u002Fru.wikipedia.org\u002Fwiki\u002F%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BB%D0%BB%D0%BC%D0%B0%D0%BD%D0%B0_%E2%80%94_%D0%A4%D0%BE%D1%80%D0%B4%D0%B0",[1209],"Беллмана — Форда",".\nРассмотрение алгоритма Беллмана — Форда выходит за рамки этой статьи.\nЗаймёмся теперь реализацией алгоритма Дейкстры.",[632,46312,46314],{"id":46313},"реализация-алгоритма-дейкстры","Реализация алгоритма Дейкстры",[415,46316,46317],{},"Ниже изображён граф, который будет использоваться в примере с кодом:",[415,46319,46320],{},[15324,46321],{"alt":46322,"src":46323},"Пример взвешенного графа: реализация","\u002Fimages\u002Fblog\u002Fpython\u002Fst32\u002Fimg_20.png",[415,46325,46326],{},"Для реализации понадобятся три хеш-таблицы или три словаря в Python.\nСловари стоимостей и родителей будут обновляться по ходу работы алгоритма.\nСначала необходимо реализовать словарь для графа:",[422,46328,46330],{"className":424,"code":46329,"language":396,"meta":426,"style":426},"graph = {}\n",[428,46331,46332],{"__ignoreMap":426},[431,46333,46334,46336,46338],{"class":433,"line":434},[431,46335,43996],{"class":441},[431,46337,1189],{"class":654},[431,46339,29580],{"class":441},[415,46341,46342],{},"Необходимо сохранить соседей и стоимость перехода. Судя по графу у начального узла есть два соседа, A и B.\nВеса рёбер графа также представим виде хеш-таблицы или словаря:",[422,46344,46346],{"className":424,"code":46345,"language":396,"meta":426,"style":426},"graph[\"start\"] = {}\ngraph[\"start\"][\"a\"] = 6\ngraph[\"start\"][\"b\"] = 2\n",[428,46347,46348,46361,46378],{"__ignoreMap":426},[431,46349,46350,46352,46355,46357,46359],{"class":433,"line":434},[431,46351,44005],{"class":441},[431,46353,46354],{"class":445},"\"start\"",[431,46356,4049],{"class":441},[431,46358,1189],{"class":654},[431,46360,29580],{"class":441},[431,46362,46363,46365,46367,46369,46371,46373,46375],{"class":433,"line":452},[431,46364,44005],{"class":441},[431,46366,46354],{"class":445},[431,46368,22465],{"class":441},[431,46370,26597],{"class":445},[431,46372,4049],{"class":441},[431,46374,1189],{"class":654},[431,46376,46377],{"class":437}," 6\n",[431,46379,46380,46382,46384,46386,46388,46390,46392],{"class":433,"line":578},[431,46381,44005],{"class":441},[431,46383,46354],{"class":445},[431,46385,22465],{"class":441},[431,46387,26606],{"class":445},[431,46389,4049],{"class":441},[431,46391,1189],{"class":654},[431,46393,658],{"class":437},[415,46395,46396,46397,46400],{},"Итак, ",[428,46398,46399],{},"graph[\"start\"]"," является словарём. Для получения всех соседей узла можно воспользоваться следующим выражением:",[422,46402,46404],{"className":424,"code":46403,"language":396,"meta":426,"style":426},"print(list(graph[\"start\"].keys()))\n# [\"a\", \"b\"]\n",[428,46405,46406,46422],{"__ignoreMap":426},[431,46407,46408,46410,46412,46414,46417,46419],{"class":433,"line":434},[431,46409,438],{"class":437},[431,46411,442],{"class":441},[431,46413,24005],{"class":437},[431,46415,46416],{"class":441},"(graph[",[431,46418,46354],{"class":445},[431,46420,46421],{"class":441},"].keys()))\n",[431,46423,46424],{"class":433,"line":452},[431,46425,46426],{"class":455},"# [\"a\", \"b\"]\n",[415,46428,46429],{},"Одно ребро ведёт из начального узла в A, а другое из начального узла в B. Веса узнать этих рёбер можно так:",[422,46431,46433],{"className":424,"code":46432,"language":396,"meta":426,"style":426},"print(graph[\"start\"][\"a\"]) # 6\nprint(graph[\"start\"][\"b\"]) # 2\n",[428,46434,46435,46451],{"__ignoreMap":426},[431,46436,46437,46439,46441,46443,46445,46447,46449],{"class":433,"line":434},[431,46438,438],{"class":437},[431,46440,46416],{"class":441},[431,46442,46354],{"class":445},[431,46444,22465],{"class":441},[431,46446,26597],{"class":445},[431,46448,18021],{"class":441},[431,46450,5314],{"class":455},[431,46452,46453,46455,46457,46459,46461,46463,46465],{"class":433,"line":452},[431,46454,438],{"class":437},[431,46456,46416],{"class":441},[431,46458,46354],{"class":445},[431,46460,22465],{"class":441},[431,46462,26606],{"class":445},[431,46464,18021],{"class":441},[431,46466,5652],{"class":455},[415,46468,46469],{},"Допишем в граф остальные узлы:",[422,46471,46473],{"className":424,"code":46472,"language":396,"meta":426,"style":426},"graph[\"a\"] = {}\ngraph[\"a\"][\"final\"] = 1\ngraph[\"b\"] = {}\ngraph[\"b\"][\"a\"] = 3\ngraph[\"b\"][\"final\"] = 5\ngraph[\"final\"] = {}  # У конечного узла соседей нет\n",[428,46474,46475,46487,46504,46516,46532,46548],{"__ignoreMap":426},[431,46476,46477,46479,46481,46483,46485],{"class":433,"line":434},[431,46478,44005],{"class":441},[431,46480,26597],{"class":445},[431,46482,4049],{"class":441},[431,46484,1189],{"class":654},[431,46486,29580],{"class":441},[431,46488,46489,46491,46493,46495,46498,46500,46502],{"class":433,"line":452},[431,46490,44005],{"class":441},[431,46492,26597],{"class":445},[431,46494,22465],{"class":441},[431,46496,46497],{"class":445},"\"final\"",[431,46499,4049],{"class":441},[431,46501,1189],{"class":654},[431,46503,3916],{"class":437},[431,46505,46506,46508,46510,46512,46514],{"class":433,"line":578},[431,46507,44005],{"class":441},[431,46509,26606],{"class":445},[431,46511,4049],{"class":441},[431,46513,1189],{"class":654},[431,46515,29580],{"class":441},[431,46517,46518,46520,46522,46524,46526,46528,46530],{"class":433,"line":584},[431,46519,44005],{"class":441},[431,46521,26606],{"class":445},[431,46523,22465],{"class":441},[431,46525,26597],{"class":445},[431,46527,4049],{"class":441},[431,46529,1189],{"class":654},[431,46531,1197],{"class":437},[431,46533,46534,46536,46538,46540,46542,46544,46546],{"class":433,"line":1244},[431,46535,44005],{"class":441},[431,46537,26606],{"class":445},[431,46539,22465],{"class":441},[431,46541,46497],{"class":445},[431,46543,4049],{"class":441},[431,46545,1189],{"class":654},[431,46547,3926],{"class":437},[431,46549,46550,46552,46554,46556,46558,46560],{"class":433,"line":1985},[431,46551,44005],{"class":441},[431,46553,46497],{"class":445},[431,46555,4049],{"class":441},[431,46557,1189],{"class":654},[431,46559,26783],{"class":441},[431,46561,46562],{"class":455},"# У конечного узла соседей нет\n",[415,46564,46565,46566,46569],{},"Стоимость узла определяет, сколько времени потребуется для перехода к этому узлу от начального узла.\nВы не знаете, сколько времени потребуется для достижения конечного узла. Если стоимость ещё неизвестна, она считается бесконечной.\nКак представить бесконечно в Python? Есть следующий вариант: ",[428,46567,46568],{},"infinity = math.inf",".\nКод создания словаря стоимостей:",[422,46571,46573],{"className":424,"code":46572,"language":396,"meta":426,"style":426},"import math\ninfinity = math.inf\ncosts = {}\ncosts[\"a\"] = 6\ncosts[\"b\"] = 2\ncosts[\"final\"] = infinity\n",[428,46574,46575,46582,46592,46601,46614,46626],{"__ignoreMap":426},[431,46576,46577,46579],{"class":433,"line":434},[431,46578,5379],{"class":654},[431,46580,46581],{"class":441}," math\n",[431,46583,46584,46587,46589],{"class":433,"line":452},[431,46585,46586],{"class":441},"infinity ",[431,46588,1189],{"class":654},[431,46590,46591],{"class":441}," math.inf\n",[431,46593,46594,46597,46599],{"class":433,"line":578},[431,46595,46596],{"class":441},"costs ",[431,46598,1189],{"class":654},[431,46600,29580],{"class":441},[431,46602,46603,46606,46608,46610,46612],{"class":433,"line":584},[431,46604,46605],{"class":441},"costs[",[431,46607,26597],{"class":445},[431,46609,4049],{"class":441},[431,46611,1189],{"class":654},[431,46613,46377],{"class":437},[431,46615,46616,46618,46620,46622,46624],{"class":433,"line":1244},[431,46617,46605],{"class":441},[431,46619,26606],{"class":445},[431,46621,4049],{"class":441},[431,46623,1189],{"class":654},[431,46625,658],{"class":437},[431,46627,46628,46630,46632,46634,46636],{"class":433,"line":1985},[431,46629,46605],{"class":441},[431,46631,46497],{"class":445},[431,46633,4049],{"class":441},[431,46635,1189],{"class":654},[431,46637,46638],{"class":441}," infinity\n",[415,46640,46641],{},"Для родителей также создадим отдельный словарь. Код представлен ниже:",[422,46643,46645],{"className":424,"code":46644,"language":396,"meta":426,"style":426},"parents = {}\nparents[\"a\"] = \"start\"\nparents[\"b\"] = \"start\"\nparents[\"final\"] = None\n",[428,46646,46647,46656,46670,46682],{"__ignoreMap":426},[431,46648,46649,46652,46654],{"class":433,"line":434},[431,46650,46651],{"class":441},"parents ",[431,46653,1189],{"class":654},[431,46655,29580],{"class":441},[431,46657,46658,46661,46663,46665,46667],{"class":433,"line":452},[431,46659,46660],{"class":441},"parents[",[431,46662,26597],{"class":445},[431,46664,4049],{"class":441},[431,46666,1189],{"class":654},[431,46668,46669],{"class":445}," \"start\"\n",[431,46671,46672,46674,46676,46678,46680],{"class":433,"line":578},[431,46673,46660],{"class":441},[431,46675,26606],{"class":445},[431,46677,4049],{"class":441},[431,46679,1189],{"class":654},[431,46681,46669],{"class":445},[431,46683,46684,46686,46688,46690,46692],{"class":433,"line":584},[431,46685,46660],{"class":441},[431,46687,46497],{"class":445},[431,46689,4049],{"class":441},[431,46691,1189],{"class":654},[431,46693,11872],{"class":437},[415,46695,46696],{},"Наконец, нужно множество для отслеживания всех уже обработанных узлов, так как один узел не должен обрабатываться многократно:",[422,46698,46700],{"className":424,"code":46699,"language":396,"meta":426,"style":426},"processed = set()\n",[428,46701,46702],{"__ignoreMap":426},[431,46703,46704,46707,46709,46711],{"class":433,"line":434},[431,46705,46706],{"class":441},"processed ",[431,46708,1189],{"class":654},[431,46710,27951],{"class":437},[431,46712,5728],{"class":441},[415,46714,46715],{},"На этом подготовка для данных завершена. Ниже напишем код алгоритма:",[422,46717,46719],{"className":424,"code":46718,"language":396,"meta":426,"style":426},"node = find_lowest_cost(costs) # Найти узел с наименьшей стоимостью среди необработанных\nwhile node is not None: # Обрабатываем все узлы\n  cost = costs[node] # Получить стоимость\n  neighbors = graph[node] # Получить соседей узла\n  for n in neighbors.keys(): # Перебор всех соседей текущего узла\n    new_cost = cost + neighbors[n] # Вычисляем стоимость пути перехода\n    if costs[n] > new_cost: # Если к соседу можно добрать быстрее через текущий узел\n      costs[n] = new_cost # Обновить стоимость узла\n      parents[n] = node # Этот узел становится новым родителем для соседа\n  processed.add(node) # Узел помечается как обработанный\n  node = find_lowest_cost(costs) # Найти следующий узел для обработки\n",[428,46720,46721,46734,46752,46765,46778,46792,46810,46825,46838,46850,46858],{"__ignoreMap":426},[431,46722,46723,46726,46728,46731],{"class":433,"line":434},[431,46724,46725],{"class":441},"node ",[431,46727,1189],{"class":654},[431,46729,46730],{"class":441}," find_lowest_cost(costs) ",[431,46732,46733],{"class":455},"# Найти узел с наименьшей стоимостью среди необработанных\n",[431,46735,46736,46738,46741,46743,46745,46747,46749],{"class":433,"line":452},[431,46737,12737],{"class":654},[431,46739,46740],{"class":441}," node ",[431,46742,19884],{"class":654},[431,46744,9498],{"class":654},[431,46746,21032],{"class":437},[431,46748,26306],{"class":441},[431,46750,46751],{"class":455},"# Обрабатываем все узлы\n",[431,46753,46754,46757,46759,46762],{"class":433,"line":578},[431,46755,46756],{"class":441},"  cost ",[431,46758,1189],{"class":654},[431,46760,46761],{"class":441}," costs[node] ",[431,46763,46764],{"class":455},"# Получить стоимость\n",[431,46766,46767,46770,46772,46775],{"class":433,"line":584},[431,46768,46769],{"class":441},"  neighbors ",[431,46771,1189],{"class":654},[431,46773,46774],{"class":441}," graph[node] ",[431,46776,46777],{"class":455},"# Получить соседей узла\n",[431,46779,46780,46782,46784,46786,46789],{"class":433,"line":1244},[431,46781,20523],{"class":654},[431,46783,8150],{"class":441},[431,46785,14421],{"class":654},[431,46787,46788],{"class":441}," neighbors.keys(): ",[431,46790,46791],{"class":455},"# Перебор всех соседей текущего узла\n",[431,46793,46794,46797,46799,46802,46804,46807],{"class":433,"line":1985},[431,46795,46796],{"class":441},"    new_cost ",[431,46798,1189],{"class":654},[431,46800,46801],{"class":441}," cost ",[431,46803,802],{"class":654},[431,46805,46806],{"class":441}," neighbors[n] ",[431,46808,46809],{"class":455},"# Вычисляем стоимость пути перехода\n",[431,46811,46812,46814,46817,46819,46822],{"class":433,"line":2041},[431,46813,10438],{"class":654},[431,46815,46816],{"class":441}," costs[n] ",[431,46818,8883],{"class":654},[431,46820,46821],{"class":441}," new_cost: ",[431,46823,46824],{"class":455},"# Если к соседу можно добрать быстрее через текущий узел\n",[431,46826,46827,46830,46832,46835],{"class":433,"line":4018},[431,46828,46829],{"class":441},"      costs[n] ",[431,46831,1189],{"class":654},[431,46833,46834],{"class":441}," new_cost ",[431,46836,46837],{"class":455},"# Обновить стоимость узла\n",[431,46839,46840,46843,46845,46847],{"class":433,"line":4030},[431,46841,46842],{"class":441},"      parents[n] ",[431,46844,1189],{"class":654},[431,46846,46740],{"class":441},[431,46848,46849],{"class":455},"# Этот узел становится новым родителем для соседа\n",[431,46851,46852,46855],{"class":433,"line":4419},[431,46853,46854],{"class":441},"  processed.add(node) ",[431,46856,46857],{"class":455},"# Узел помечается как обработанный\n",[431,46859,46860,46863,46865,46867],{"class":433,"line":4436},[431,46861,46862],{"class":441},"  node ",[431,46864,1189],{"class":654},[431,46866,46730],{"class":441},[431,46868,46869],{"class":455},"# Найти следующий узел для обработки\n",[415,46871,46872,46873,46876],{},"После того как все узлы будут обработаны, алгоритм завершается. Код функции ",[428,46874,46875],{},"find_lowest_cost(costs)"," приведём ниже:",[422,46878,46880],{"className":424,"code":46879,"language":396,"meta":426,"style":426},"def find_lowest_cost(costs):\n  lowest_cost = math.inf\n  lowest_cost_node = None\n  for node in costs: # Перебираем все узлы\n    cost = costs[node]\n    if cost \u003C lowest_cost and node not in processed: # Если узел с наименьшей стоимость и ещё не был обработан\n      lowest_cost = cost # он назначается новым узлом с наименьшей стоимостью\n      lowest_cost_node = node\n  return lowest_cost_node\n",[428,46881,46882,46892,46901,46910,46924,46934,46959,46971,46981],{"__ignoreMap":426},[431,46883,46884,46886,46889],{"class":433,"line":434},[431,46885,6330],{"class":654},[431,46887,46888],{"class":6333}," find_lowest_cost",[431,46890,46891],{"class":441},"(costs):\n",[431,46893,46894,46897,46899],{"class":433,"line":452},[431,46895,46896],{"class":441},"  lowest_cost ",[431,46898,1189],{"class":654},[431,46900,46591],{"class":441},[431,46902,46903,46906,46908],{"class":433,"line":578},[431,46904,46905],{"class":441},"  lowest_cost_node ",[431,46907,1189],{"class":654},[431,46909,11872],{"class":437},[431,46911,46912,46914,46916,46918,46921],{"class":433,"line":584},[431,46913,20523],{"class":654},[431,46915,46740],{"class":441},[431,46917,14421],{"class":654},[431,46919,46920],{"class":441}," costs: ",[431,46922,46923],{"class":455},"# Перебираем все узлы\n",[431,46925,46926,46929,46931],{"class":433,"line":1244},[431,46927,46928],{"class":441},"    cost ",[431,46930,1189],{"class":654},[431,46932,46933],{"class":441}," costs[node]\n",[431,46935,46936,46938,46940,46942,46945,46947,46949,46951,46953,46956],{"class":433,"line":1985},[431,46937,10438],{"class":654},[431,46939,46801],{"class":441},[431,46941,8521],{"class":654},[431,46943,46944],{"class":441}," lowest_cost ",[431,46946,8946],{"class":654},[431,46948,46740],{"class":441},[431,46950,9369],{"class":654},[431,46952,21531],{"class":654},[431,46954,46955],{"class":441}," processed: ",[431,46957,46958],{"class":455},"# Если узел с наименьшей стоимость и ещё не был обработан\n",[431,46960,46961,46964,46966,46968],{"class":433,"line":2041},[431,46962,46963],{"class":441},"      lowest_cost ",[431,46965,1189],{"class":654},[431,46967,46801],{"class":441},[431,46969,46970],{"class":455},"# он назначается новым узлом с наименьшей стоимостью\n",[431,46972,46973,46976,46978],{"class":433,"line":4018},[431,46974,46975],{"class":441},"      lowest_cost_node ",[431,46977,1189],{"class":654},[431,46979,46980],{"class":441}," node\n",[431,46982,46983,46985],{"class":433,"line":4030},[431,46984,20132],{"class":654},[431,46986,46987],{"class":441}," lowest_cost_node\n",[415,46989,46990],{},"Чтобы найти узел с наименьшей стоимостью, мы каждый раз перебираем все узлы. Существует более эффективный вариант этого алгоритма.\nОн использует структуру данных, называемую очередью с приоритетом. Эта очередь строится на основе другой структуры данных — кучи.\nЕсли вам интересны очереди с приоритетом и кучи, об этом будет далее статья.",[415,46992,46993],{},"Объединим весь код:",[422,46995,46997],{"className":424,"code":46996,"language":396,"meta":426,"style":426},"import math\n\ngraph = {}\ngraph[\"start\"] = {}\ngraph[\"start\"][\"a\"] = 6\ngraph[\"start\"][\"b\"] = 2\ngraph[\"a\"] = {}\ngraph[\"a\"][\"final\"] = 1\ngraph[\"b\"] = {}\ngraph[\"b\"][\"a\"] = 3\ngraph[\"b\"][\"final\"] = 5\ngraph[\"final\"] = {}\n\ninfinity = math.inf\ncosts = {}\ncosts[\"a\"] = 6\ncosts[\"b\"] = 2\ncosts[\"final\"] = infinity\n\nparents = {}\nparents[\"a\"] = \"start\"\nparents[\"b\"] = \"start\"\nparents[\"final\"] = None\n\nprocessed = set()\n\ndef find_lowest_cost(costs):\n  lowest_cost = math.inf\n  lowest_cost_node = None\n  for node in costs:\n    cost = costs[node]\n    if cost \u003C lowest_cost and node not in processed:\n      lowest_cost = cost\n      lowest_cost_node = node\n  return lowest_cost_node\n\nnode = find_lowest_cost(costs)\nwhile node is not None:\n  cost = costs[node]\n  neighbors = graph[node]\n  for n in neighbors.keys():\n    new_cost = cost + neighbors[n]\n    if costs[n] > new_cost:\n      costs[n] = new_cost\n      parents[n] = node\n  processed.add(node)\n  node = find_lowest_cost(costs)\n\nprint(\"Стоимость от начала до каждого узла:\")\nprint(costs)\n",[428,46998,46999,47005,47009,47017,47029,47045,47061,47073,47089,47101,47117,47133,47145,47149,47157,47165,47177,47189,47201,47205,47213,47225,47237,47249,47253,47263,47267,47275,47283,47291,47302,47310,47331,47340,47348,47354,47358,47367,47381,47389,47398,47409,47423,47435,47445,47454,47460,47469,47474,47486],{"__ignoreMap":426},[431,47000,47001,47003],{"class":433,"line":434},[431,47002,5379],{"class":654},[431,47004,46581],{"class":441},[431,47006,47007],{"class":433,"line":452},[431,47008,1662],{"emptyLinePlaceholder":393},[431,47010,47011,47013,47015],{"class":433,"line":578},[431,47012,43996],{"class":441},[431,47014,1189],{"class":654},[431,47016,29580],{"class":441},[431,47018,47019,47021,47023,47025,47027],{"class":433,"line":584},[431,47020,44005],{"class":441},[431,47022,46354],{"class":445},[431,47024,4049],{"class":441},[431,47026,1189],{"class":654},[431,47028,29580],{"class":441},[431,47030,47031,47033,47035,47037,47039,47041,47043],{"class":433,"line":1244},[431,47032,44005],{"class":441},[431,47034,46354],{"class":445},[431,47036,22465],{"class":441},[431,47038,26597],{"class":445},[431,47040,4049],{"class":441},[431,47042,1189],{"class":654},[431,47044,46377],{"class":437},[431,47046,47047,47049,47051,47053,47055,47057,47059],{"class":433,"line":1985},[431,47048,44005],{"class":441},[431,47050,46354],{"class":445},[431,47052,22465],{"class":441},[431,47054,26606],{"class":445},[431,47056,4049],{"class":441},[431,47058,1189],{"class":654},[431,47060,658],{"class":437},[431,47062,47063,47065,47067,47069,47071],{"class":433,"line":2041},[431,47064,44005],{"class":441},[431,47066,26597],{"class":445},[431,47068,4049],{"class":441},[431,47070,1189],{"class":654},[431,47072,29580],{"class":441},[431,47074,47075,47077,47079,47081,47083,47085,47087],{"class":433,"line":4018},[431,47076,44005],{"class":441},[431,47078,26597],{"class":445},[431,47080,22465],{"class":441},[431,47082,46497],{"class":445},[431,47084,4049],{"class":441},[431,47086,1189],{"class":654},[431,47088,3916],{"class":437},[431,47090,47091,47093,47095,47097,47099],{"class":433,"line":4030},[431,47092,44005],{"class":441},[431,47094,26606],{"class":445},[431,47096,4049],{"class":441},[431,47098,1189],{"class":654},[431,47100,29580],{"class":441},[431,47102,47103,47105,47107,47109,47111,47113,47115],{"class":433,"line":4419},[431,47104,44005],{"class":441},[431,47106,26606],{"class":445},[431,47108,22465],{"class":441},[431,47110,26597],{"class":445},[431,47112,4049],{"class":441},[431,47114,1189],{"class":654},[431,47116,1197],{"class":437},[431,47118,47119,47121,47123,47125,47127,47129,47131],{"class":433,"line":4436},[431,47120,44005],{"class":441},[431,47122,26606],{"class":445},[431,47124,22465],{"class":441},[431,47126,46497],{"class":445},[431,47128,4049],{"class":441},[431,47130,1189],{"class":654},[431,47132,3926],{"class":437},[431,47134,47135,47137,47139,47141,47143],{"class":433,"line":4446},[431,47136,44005],{"class":441},[431,47138,46497],{"class":445},[431,47140,4049],{"class":441},[431,47142,1189],{"class":654},[431,47144,29580],{"class":441},[431,47146,47147],{"class":433,"line":4451},[431,47148,1662],{"emptyLinePlaceholder":393},[431,47150,47151,47153,47155],{"class":433,"line":4086},[431,47152,46586],{"class":441},[431,47154,1189],{"class":654},[431,47156,46591],{"class":441},[431,47158,47159,47161,47163],{"class":433,"line":4477},[431,47160,46596],{"class":441},[431,47162,1189],{"class":654},[431,47164,29580],{"class":441},[431,47166,47167,47169,47171,47173,47175],{"class":433,"line":4482},[431,47168,46605],{"class":441},[431,47170,26597],{"class":445},[431,47172,4049],{"class":441},[431,47174,1189],{"class":654},[431,47176,46377],{"class":437},[431,47178,47179,47181,47183,47185,47187],{"class":433,"line":4488},[431,47180,46605],{"class":441},[431,47182,26606],{"class":445},[431,47184,4049],{"class":441},[431,47186,1189],{"class":654},[431,47188,658],{"class":437},[431,47190,47191,47193,47195,47197,47199],{"class":433,"line":4505},[431,47192,46605],{"class":441},[431,47194,46497],{"class":445},[431,47196,4049],{"class":441},[431,47198,1189],{"class":654},[431,47200,46638],{"class":441},[431,47202,47203],{"class":433,"line":12871},[431,47204,1662],{"emptyLinePlaceholder":393},[431,47206,47207,47209,47211],{"class":433,"line":2874},[431,47208,46651],{"class":441},[431,47210,1189],{"class":654},[431,47212,29580],{"class":441},[431,47214,47215,47217,47219,47221,47223],{"class":433,"line":12887},[431,47216,46660],{"class":441},[431,47218,26597],{"class":445},[431,47220,4049],{"class":441},[431,47222,1189],{"class":654},[431,47224,46669],{"class":445},[431,47226,47227,47229,47231,47233,47235],{"class":433,"line":12892},[431,47228,46660],{"class":441},[431,47230,26606],{"class":445},[431,47232,4049],{"class":441},[431,47234,1189],{"class":654},[431,47236,46669],{"class":445},[431,47238,47239,47241,47243,47245,47247],{"class":433,"line":12898},[431,47240,46660],{"class":441},[431,47242,46497],{"class":445},[431,47244,4049],{"class":441},[431,47246,1189],{"class":654},[431,47248,11872],{"class":437},[431,47250,47251],{"class":433,"line":12904},[431,47252,1662],{"emptyLinePlaceholder":393},[431,47254,47255,47257,47259,47261],{"class":433,"line":8382},[431,47256,46706],{"class":441},[431,47258,1189],{"class":654},[431,47260,27951],{"class":437},[431,47262,5728],{"class":441},[431,47264,47265],{"class":433,"line":25829},[431,47266,1662],{"emptyLinePlaceholder":393},[431,47268,47269,47271,47273],{"class":433,"line":25838},[431,47270,6330],{"class":654},[431,47272,46888],{"class":6333},[431,47274,46891],{"class":441},[431,47276,47277,47279,47281],{"class":433,"line":1890},[431,47278,46896],{"class":441},[431,47280,1189],{"class":654},[431,47282,46591],{"class":441},[431,47284,47285,47287,47289],{"class":433,"line":30788},[431,47286,46905],{"class":441},[431,47288,1189],{"class":654},[431,47290,11872],{"class":437},[431,47292,47293,47295,47297,47299],{"class":433,"line":31619},[431,47294,20523],{"class":654},[431,47296,46740],{"class":441},[431,47298,14421],{"class":654},[431,47300,47301],{"class":441}," costs:\n",[431,47303,47304,47306,47308],{"class":433,"line":31664},[431,47305,46928],{"class":441},[431,47307,1189],{"class":654},[431,47309,46933],{"class":441},[431,47311,47312,47314,47316,47318,47320,47322,47324,47326,47328],{"class":433,"line":15016},[431,47313,10438],{"class":654},[431,47315,46801],{"class":441},[431,47317,8521],{"class":654},[431,47319,46944],{"class":441},[431,47321,8946],{"class":654},[431,47323,46740],{"class":441},[431,47325,9369],{"class":654},[431,47327,21531],{"class":654},[431,47329,47330],{"class":441}," processed:\n",[431,47332,47333,47335,47337],{"class":433,"line":32022},[431,47334,46963],{"class":441},[431,47336,1189],{"class":654},[431,47338,47339],{"class":441}," cost\n",[431,47341,47342,47344,47346],{"class":433,"line":32027},[431,47343,46975],{"class":441},[431,47345,1189],{"class":654},[431,47347,46980],{"class":441},[431,47349,47350,47352],{"class":433,"line":32032},[431,47351,20132],{"class":654},[431,47353,46987],{"class":441},[431,47355,47356],{"class":433,"line":32037},[431,47357,1662],{"emptyLinePlaceholder":393},[431,47359,47360,47362,47364],{"class":433,"line":32053},[431,47361,46725],{"class":441},[431,47363,1189],{"class":654},[431,47365,47366],{"class":441}," find_lowest_cost(costs)\n",[431,47368,47369,47371,47373,47375,47377,47379],{"class":433,"line":32069},[431,47370,12737],{"class":654},[431,47372,46740],{"class":441},[431,47374,19884],{"class":654},[431,47376,9498],{"class":654},[431,47378,21032],{"class":437},[431,47380,8102],{"class":441},[431,47382,47383,47385,47387],{"class":433,"line":32079},[431,47384,46756],{"class":441},[431,47386,1189],{"class":654},[431,47388,46933],{"class":441},[431,47390,47391,47393,47395],{"class":433,"line":12482},[431,47392,46769],{"class":441},[431,47394,1189],{"class":654},[431,47396,47397],{"class":441}," graph[node]\n",[431,47399,47400,47402,47404,47406],{"class":433,"line":30476},[431,47401,20523],{"class":654},[431,47403,8150],{"class":441},[431,47405,14421],{"class":654},[431,47407,47408],{"class":441}," neighbors.keys():\n",[431,47410,47412,47414,47416,47418,47420],{"class":433,"line":47411},42,[431,47413,46796],{"class":441},[431,47415,1189],{"class":654},[431,47417,46801],{"class":441},[431,47419,802],{"class":654},[431,47421,47422],{"class":441}," neighbors[n]\n",[431,47424,47426,47428,47430,47432],{"class":433,"line":47425},43,[431,47427,10438],{"class":654},[431,47429,46816],{"class":441},[431,47431,8883],{"class":654},[431,47433,47434],{"class":441}," new_cost:\n",[431,47436,47438,47440,47442],{"class":433,"line":47437},44,[431,47439,46829],{"class":441},[431,47441,1189],{"class":654},[431,47443,47444],{"class":441}," new_cost\n",[431,47446,47448,47450,47452],{"class":433,"line":47447},45,[431,47449,46842],{"class":441},[431,47451,1189],{"class":654},[431,47453,46980],{"class":441},[431,47455,47457],{"class":433,"line":47456},46,[431,47458,47459],{"class":441},"  processed.add(node)\n",[431,47461,47463,47465,47467],{"class":433,"line":47462},47,[431,47464,46862],{"class":441},[431,47466,1189],{"class":654},[431,47468,47366],{"class":441},[431,47470,47472],{"class":433,"line":47471},48,[431,47473,1662],{"emptyLinePlaceholder":393},[431,47475,47477,47479,47481,47484],{"class":433,"line":47476},49,[431,47478,438],{"class":437},[431,47480,442],{"class":441},[431,47482,47483],{"class":445},"\"Стоимость от начала до каждого узла:\"",[431,47485,449],{"class":441},[431,47487,47489,47491],{"class":433,"line":47488},50,[431,47490,438],{"class":437},[431,47492,47493],{"class":441},"(costs)\n",[8839,47495,47496],{},[415,47497,47498,47499,2699],{},"В следующей статье информация про ",[1205,47500,47501],{"href":295},"жадные алгоритмы",[458,47503],{"id":426},[29130,47505],{":isList":47506,"title":30269},"[\"Поиск в ширину вычисляет кратчайший путь в невзвешенном графе;\",\"Алгоритм Дейкстры вычисляет кратчайший путь во взвешенном графе;\",\"Алгоритм Дейкстры работает только в том случае, если все веса положительны;\",\"При наличии отрицательных весов используйте алгоритм Беллмана – Форда.\"]",[415,47508,34817,47509,1853,47511,1857],{},[800,47510,1852],{},[800,47512,1856],{},[1859,47514],{},[1862,47516,47517],{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}",{"title":426,"searchDepth":452,"depth":1244,"links":47519},[47520],{"id":45971,"depth":452,"text":290,"children":47521},[47522,47523,47524,47525,47526],{"id":45997,"depth":578,"text":45998},{"id":40822,"depth":578,"text":40823},{"id":46127,"depth":578,"text":46128},{"id":46249,"depth":578,"text":46250},{"id":46313,"depth":578,"text":46314,"children":47527},[47528],{"id":426,"depth":584,"text":426},"2026-04-16","Взвешенные графы. Поиск кратчайшего пути.","images\u002Fblog\u002Fpython\u002Fst32\u002Fimg.png",{},{"title":290,"description":47530},"4VuU4ePMxuwTgSFFuGyVelHe76ld3KQ9e5cy3LeeV7s",{"id":47536,"title":294,"author":47537,"body":47539,"date":48844,"description":48845,"extension":1887,"image":48846,"meta":48847,"minRead":2874,"navigation":393,"num":32022,"path":295,"seo":48848,"stem":296,"__hash__":48849},"python\u002Fblog\u002Fpython\u002Fst33.md",{"name":402,"avatar":47538},{"src":404,"alt":405},{"type":407,"value":47540,"toc":48830},[47541,47544,47547,47556,47560,47563,47630,47633,47644,47647,47650,47654,47657,47668,47671,47674,47678,47681,47685,47688,47696,47706,47711,47715,47718,47726,47729,47787,47790,47794,47797,47863,47866,48006,48009,48025,48029,48035,48079,48086,48155,48159,48162,48173,48176,48184,48189,48193,48216,48225,48231,48246,48256,48598,48601,48802,48805,48813,48815,48818,48824,48826,48828],[410,47542,294],{"id":47543},"жадные-алгоритмы",[29130,47545],{":isList":47546,"title":43905},"[\"Узнаете о жадной стратегии при решении задач.\",\"Разберётесь как браться за невозможные задачи, не имеющие быстрого алгоритмического решения NP-трудные задачи.\",\"Познакомитесь с приближёнными алгоритмами, которые могут использоваться для быстрого нахождения приближённого решения NP-полных задач.\"]",[8839,47548,47549],{},[415,47550,47551,47552,47555],{},"В предыдущей статье был рассмотрен: ",[1205,47553,47554],{"href":291},"алгоритм Дейкстры",".\nЗдесь далее текст пойдёт о жадных алгоритмах.",[632,47557,47559],{"id":47558},"задача-составления-расписания","Задача составления расписания",[415,47561,47562],{},"Предположим, имеется учебный класс, в котором нужно провести как можно больше уроков. У вас есть список уроков:",[9256,47564,47565,47578],{},[9259,47566,47567],{},[9262,47568,47569,47572,47575],{},[9265,47570,47571],{},"Предмет",[9265,47573,47574],{},"С",[9265,47576,47577],{},"ДО",[9275,47579,47580,47591,47602,47612,47621],{},[9262,47581,47582,47585,47588],{},[9280,47583,47584],{},"ИЗО",[9280,47586,47587],{},"8:00",[9280,47589,47590],{},"9:00",[9262,47592,47593,47596,47599],{},[9280,47594,47595],{},"English",[9280,47597,47598],{},"8:30",[9280,47600,47601],{},"9:30",[9262,47603,47604,47607,47609],{},[9280,47605,47606],{},"Алгебра",[9280,47608,47590],{},[9280,47610,47611],{},"10:00",[9262,47613,47614,47616,47618],{},[9280,47615,1543],{},[9280,47617,47601],{},[9280,47619,47620],{},"10:30",[9262,47622,47623,47625,47627],{},[9280,47624,1548],{},[9280,47626,47611],{},[9280,47628,47629],{},"11:00",[415,47631,47632],{},"Провести все уроки не получится, потому что они перекрывают друг друга по времени.\nТребуется провести в классе как можно больше уроков.\nКак отобрать уроки, чтобы полученный набор оказался самым большим из возможных?\nВот какой составить необходимо алгоритм:",[1588,47634,47635,47638,47641],{},[700,47636,47637],{},"Выбрать урок, завершающийся раньше всех. Это первый урок, который будет проведён в классе.",[700,47639,47640],{},"Затем выбирается урок, начинающийся после завершения первого урока. И снова следует выбирать урок, который завершается раньше всех остальных. Он становится вторым уроком в расписании класса.",[700,47642,47643],{},"Продолжайте действовать по тому же принципу, чтобы получить ответ.",[415,47645,47646],{},"Попробуйте алгоритм на примере таблицы выше. ИЗО заканчивается раньше всех уроков, поэтому выбираем первым уроком.\nДалее нужно найти и выбрать следующий урок, который начинается после 9:00 и завершается раньше остальных.\nАнглийский отпадает, но алгебра подходит. Наконец, информатика пересекается по времени с алгеброй, но физика подходит.\nИтак, задача решена, эти три урока должны проводится в классе: ИЗО, алгебра, физика.",[415,47648,47649],{},"Можно подумать что этот алгоритм удивительно прост. Он слишком очевиден, но в этом и заключается суть жадных алгоритмов!\nОни просты! Жадный алгоритм: на каждом своём шаге выбирает всегда оптимальный вариант.\nВ техническом плане выбирается всегда локально-оптимальное решение.\nКонечно такие алгоритмы сработают не всегда, но с задачей из примера или подобной они справляются легко и интуитивно понятно реализуются!\nРассмотрим далее другой пример.",[632,47651,47653],{"id":47652},"задача-о-рюкзаке","Задача о рюкзаке",[415,47655,47656],{},"Представьте, что вы богатый покупатель или транжира денежных средств.\nВы зашли в магазин или супермаркет с рюкзаком и перед вами множество товаров, которые вы обязательно хотите немедленно купить.\nОднако, ёмкость вашего рюкзака и ваша грузоподъёмность не бесконечна: примерно рюкзак и соответственно вы сможете понести, допустим, 50 кг(как мешок с цементом)!\nВы также хотите купить максимально дорогие вещи!\nМожно легко представить и противоположную ситуацию — у вас абсолютно нет денег и вы хотите всё украсть и также унести 😁.\nНо задача одна и состоит в том, чтобы подобрать товары максимальной стоимости, которые вы смогли бы унести в своём рюкзаке.\nКакой алгоритм использовать?\nПопробуйте жадный алгоритм:",[1588,47658,47659,47662,47665],{},[700,47660,47661],{},"Выбрать самый дорогой предмет, который поместиться в рюкзаке.",[700,47663,47664],{},"Выбрать следующий по стоимости предмет, который поместится в рюкзаке.",[700,47666,47667],{},"И так далее продолжить до заполнения всего места в рюкзаке.",[415,47669,47670],{},"Вот только, как можно было догадаться, на этот раз такая стратегия не приводит к лучшему решению и соответственно она не работает!\nДопустим вы выбираете самый дорогой товар, например, это музыкальный центр. Вы складываете его в рюкзак и место больше ни для чего не остаётся.\nПусть он стоил 1000000 рублей и это был самый дорогой товар в магазине.\nНо допустим, были также ещё и два товара, стоимостью 750000 и 500000 рублей, которые вдвоём поместились бы в ваш рюкзак.\nНо согласно алгоритму описанному выше вы бы их уже не купили.",[415,47672,47673],{},"Очевидно, жадный алгоритм не всегда выдаёт оптимальное решение всей задачи.\nВпрочем, зачастую результат, даже ошибочный, будет не так уж далёк от истинного ответа.\nИ в некоторых задачах достаточно жадного алгоритма, способного решить задачу достаточно хорошо.\nВ таких областях жадные алгоритмы работают отлично, потому что они просто реализуются, а полученное решение обычно близко к оптимуму.",[29386,47675],{":isAnswers":47676,":isList":47677,":startOl":1192,"isText":40925,"title":29391},"[\"Выбираем достопримечательности с наибольшей стоимостью в баллах, которую вы успеете посетить в оставшееся время. Остановитесь, когда таких достопримечательностей не останется. Такая стратегия не будет оптимальной.\",\"Жадная стратегия заключается в том, чтобы выбрать самую большую коробку, помещающуюся в оставшемся пространстве, и повторять это до тех пор, пока ещё можно выбрать хотя бы одну коробку. Такое решение не будет оптимальным.\"]","[\"Вы едите заграницу и у вас есть семь дней на знакомство с достопримечательности. Вы присваиваете каждой достопримечательности стоимость в баллах(насколько вы хотите её увидеть) и оцениваете продолжительность посещения. Как увидеть всё самое важное из всей поездки? Предложите жадную стратегию решения данной задачи. Будет ли решение оптимальным?\",\"Вы работаете в фирме по производству мебели и поставляете её. Коробки с мебелью размещаются в грузовике. Все коробки имеют разный размер, и вы стараетесь наиболее эффективно использовать доступное пространство в коробках. Как выбрать коробки для того, чтобы загрузка имела максимальную эффективность? Предложите жадную стратегию для решения данной задачи. Будет ли полученное решение оптимальным?\"]",[415,47679,47680],{},"Рассмотрим ещё пример, в котором без жадных алгоритмов трудно обойтись.",[632,47682,47684],{"id":47683},"задача-о-покрытии-множества","Задача о покрытии множества",[415,47686,47687],{},"Вы открываете собственную авторскую программу по радио.\nНужно только решить на каких радиостанциях должна транслироваться ваша программа.\nКаждая трансляция на радио стоит денег, поэтому количество станций нужно свести к минимуму с максимальным качеством вещаний.\nИмеется список станций.\nКаждая станция покрывает определённый набор областей для вещания, эти наборы перекрываются по областям.\nКак найти минимальный набор станций, который покрывал бы все 89 субъектов и областей?\nЗадача довольно сложна. Составим алгоритм:",[1588,47689,47690,47693],{},[700,47691,47692],{},"Составить список всех возможных подмножеств станций – так называемое степенное множество. В нём содержатся 2^n возможных подмножеств.",[700,47694,47695],{},"Из этого списка выбирается множество с наименьшим набором станций, покрывающих все 89 субъектов.",[415,47697,47698,47699,47701,47702,47705],{},"Проблема решения данной задачи состоит в том, что вычисление всех возможных подмножеств станций займёт слишком много времени.\nДля ",[1355,47700,33806],{}," станций оно потребует времени ",[1355,47703,47704],{},"O(2^n)."," Если станций немного, скажем от 5 до 10, — это допустимо.\nНо подумайте, что произойдёт во всех рассмотренных примерах при большом количестве элементов.\nПредположим, вы можете вычислять по 10 подмножеств в секунду.",[415,47707,47708],{},[1355,47709,47710],{},"Не существует алгоритма, который будет вычислять подмножества с приемлемой скоростью! Что делать? На помощь приходят жадные алгоритмы.",[458,47712,47714],{"id":47713},"приближённые-алгоритмы-реализация","Приближённые алгоритмы: реализация",[415,47716,47717],{},"Вот как выглядит жадный алгоритм, который выдаёт результат, достаточно близкий к оптимальному решению:",[1588,47719,47720,47723],{},[700,47721,47722],{},"Выбрать станцию, покрывающую наибольшее количество областей, ещё не входящих в покрытие. Если станция будет покрывать некоторые области, уже входящие в покрытие, это нормально.",[700,47724,47725],{},"Повторять, пока останутся области, не входящие в покрытие.",[415,47727,47728],{},"Этот алгоритм является приближённым. Когда вычисление точного решения занимает слишком много времени, применяется приближённый алгоритм.\nЭффективность приближённого алгоритма оценивается по: быстроте, близости полученного решения к оптимальному.",[415,47730,47731,47732,47783,47784,47786],{},"Жадные алгоритмы хороши не только тем, что они обычно легко формулируются, но и тем, что простота обычно оборачивается скоростью выполнения.\nВ данном случае жадный алгоритм выполняется за время ",[33809,47733,47735],{"className":47734,"jax":33813},[33812],[33815,47736,47737,47752],{"style":35005,"xmlns":33818,"width":43018,"height":37685,"role":15324,"focusable":33821,"viewBox":43019,"xmlnsXLink":33823},[33825,47738,47739,47741,47743,47745,47747,47749],{},[33828,47740],{"id":37720,"d":35014},[33828,47742],{"id":37691,"d":35018},[33828,47744],{"id":33846,"d":33847},[33828,47746],{"id":33842,"d":33843},[33828,47748],{"id":37708,"d":35031},[33828,47750],{"id":47751,"d":39830},"MJX-1-TEX-N-2C",[33849,47753,47754],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,47755,47756,47760,47764,47774,47778],{"dataMmlNode":33855},[33849,47757,47758],{"dataMmlNode":33858},[33860,47759],{"dataC":35053,"xLinkHref":37829},[33849,47761,47762],{"dataMmlNode":34206,"transform":35057},[33860,47763],{"dataC":35060,"xLinkHref":37732},[33849,47765,47766,47770],{"dataMmlNode":34252,"transform":35064},[33849,47767,47768],{"dataMmlNode":33858},[33860,47769],{"dataC":33894,"xLinkHref":33895},[33849,47771,47772],{"dataMmlNode":33883,"transform":40971},[33860,47773],{"dataC":33887,"xLinkHref":33888},[33849,47775,47776],{"dataMmlNode":34206,"transform":40976},[33860,47777],{"dataC":30851,"xLinkHref":37767},[33849,47779,47780],{"dataMmlNode":34206,"transform":43062},[33860,47781],{"dataC":39886,"xLinkHref":47782},"#MJX-1-TEX-N-2C"," где ",[1355,47785,33806],{}," – количество радиостанций.",[415,47788,47789],{},"Теперь разберёмся как задача будет выглядеть в программном коде на Python.",[458,47791,47793],{"id":47792},"подготовительный-код","Подготовительный код",[415,47795,47796],{},"В этом примере для простоты будет использоваться небольшое подмножество областей и станций.\nСначала составим список областей:",[422,47798,47800],{"className":424,"code":47799,"language":396,"meta":426,"style":426},"# Для обозначения субъектов РФ используются коды\n# Переданный массив преобразуется в множество\nstates_needed = set([\"28\", \"29\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\"])  \n",[428,47801,47802,47807,47812],{"__ignoreMap":426},[431,47803,47804],{"class":433,"line":434},[431,47805,47806],{"class":455},"# Для обозначения субъектов РФ используются коды\n",[431,47808,47809],{"class":433,"line":452},[431,47810,47811],{"class":455},"# Переданный массив преобразуется в множество\n",[431,47813,47814,47817,47819,47821,47823,47826,47828,47831,47833,47836,47838,47841,47843,47846,47848,47851,47853,47856,47858,47861],{"class":433,"line":578},[431,47815,47816],{"class":441},"states_needed ",[431,47818,1189],{"class":654},[431,47820,27951],{"class":437},[431,47822,17778],{"class":441},[431,47824,47825],{"class":445},"\"28\"",[431,47827,4846],{"class":441},[431,47829,47830],{"class":445},"\"29\"",[431,47832,4846],{"class":441},[431,47834,47835],{"class":445},"\"30\"",[431,47837,4846],{"class":441},[431,47839,47840],{"class":445},"\"31\"",[431,47842,4846],{"class":441},[431,47844,47845],{"class":445},"\"32\"",[431,47847,4846],{"class":441},[431,47849,47850],{"class":445},"\"33\"",[431,47852,4846],{"class":441},[431,47854,47855],{"class":445},"\"34\"",[431,47857,4846],{"class":441},[431,47859,47860],{"class":445},"\"35\"",[431,47862,3396],{"class":441},[415,47864,47865],{},"В этой реализации используем множество.\nЭта структура данных похожа на список, но каждый элемент может встречаться во множестве не более одного раза.\nМножества не содержат дубликатов. Также понадобится список станций, из которого будет выбираться покрытие.\nВоспользуемся словарём:",[422,47867,47869],{"className":424,"code":47868,"language":396,"meta":426,"style":426},"stations = {}\nstations[\"one\"] = set([\"31\", \"32\", \"33\"])\nstations[\"two\"] = set([\"29\", \"31\", \"28\"])\nstations[\"three\"] = set([\"30\", \"32\", \"34\"])\nstations[\"four\"] = set([\"32\", \"33\"])\nstations[\"five\"] = set([\"34\", \"35\"])\n",[428,47870,47871,47880,47908,47934,47961,47983],{"__ignoreMap":426},[431,47872,47873,47876,47878],{"class":433,"line":434},[431,47874,47875],{"class":441},"stations ",[431,47877,1189],{"class":654},[431,47879,29580],{"class":441},[431,47881,47882,47885,47888,47890,47892,47894,47896,47898,47900,47902,47904,47906],{"class":433,"line":452},[431,47883,47884],{"class":441},"stations[",[431,47886,47887],{"class":445},"\"one\"",[431,47889,4049],{"class":441},[431,47891,1189],{"class":654},[431,47893,27951],{"class":437},[431,47895,17778],{"class":441},[431,47897,47840],{"class":445},[431,47899,4846],{"class":441},[431,47901,47845],{"class":445},[431,47903,4846],{"class":441},[431,47905,47850],{"class":445},[431,47907,3396],{"class":441},[431,47909,47910,47912,47914,47916,47918,47920,47922,47924,47926,47928,47930,47932],{"class":433,"line":578},[431,47911,47884],{"class":441},[431,47913,26438],{"class":445},[431,47915,4049],{"class":441},[431,47917,1189],{"class":654},[431,47919,27951],{"class":437},[431,47921,17778],{"class":441},[431,47923,47830],{"class":445},[431,47925,4846],{"class":441},[431,47927,47840],{"class":445},[431,47929,4846],{"class":441},[431,47931,47825],{"class":445},[431,47933,3396],{"class":441},[431,47935,47936,47938,47941,47943,47945,47947,47949,47951,47953,47955,47957,47959],{"class":433,"line":584},[431,47937,47884],{"class":441},[431,47939,47940],{"class":445},"\"three\"",[431,47942,4049],{"class":441},[431,47944,1189],{"class":654},[431,47946,27951],{"class":437},[431,47948,17778],{"class":441},[431,47950,47835],{"class":445},[431,47952,4846],{"class":441},[431,47954,47845],{"class":445},[431,47956,4846],{"class":441},[431,47958,47855],{"class":445},[431,47960,3396],{"class":441},[431,47962,47963,47965,47967,47969,47971,47973,47975,47977,47979,47981],{"class":433,"line":1244},[431,47964,47884],{"class":441},[431,47966,26449],{"class":445},[431,47968,4049],{"class":441},[431,47970,1189],{"class":654},[431,47972,27951],{"class":437},[431,47974,17778],{"class":441},[431,47976,47845],{"class":445},[431,47978,4846],{"class":441},[431,47980,47850],{"class":445},[431,47982,3396],{"class":441},[431,47984,47985,47987,47990,47992,47994,47996,47998,48000,48002,48004],{"class":433,"line":1985},[431,47986,47884],{"class":441},[431,47988,47989],{"class":445},"\"five\"",[431,47991,4049],{"class":441},[431,47993,1189],{"class":654},[431,47995,27951],{"class":437},[431,47997,17778],{"class":441},[431,47999,47855],{"class":445},[431,48001,4846],{"class":441},[431,48003,47860],{"class":445},[431,48005,3396],{"class":441},[415,48007,48008],{},"Ключи — названия станций, а значения — сокращенные обозначения областей, входящих в зону охвата.\nТаким образом, в данном примере станция one вещает в субъектах с кодами 31, 32, 33(Белгородская, Брянская и Владимирская области).\nВсе значения являются множествами. Хранение данных во множествах упрощает работу.\nНаконец, нам понадобится структура данных для хранения итогового набора станций:",[422,48010,48012],{"className":424,"code":48011,"language":396,"meta":426,"style":426},"final_stations = set()\n",[428,48013,48014],{"__ignoreMap":426},[431,48015,48016,48019,48021,48023],{"class":433,"line":434},[431,48017,48018],{"class":441},"final_stations ",[431,48020,1189],{"class":654},[431,48022,27951],{"class":437},[431,48024,5728],{"class":441},[458,48026,48028],{"id":48027},"вычисление-ответа","Вычисление ответа",[415,48030,48031,48032,3562],{},"Теперь необходимо вычислить набор используемых станций. Правильных решений может быть несколько.\nНеобходимо перебрать все станции и выбрать ту, которая обслуживает больше всего субъектов-областей, не входящих в текущее покрытие.\nБудем называть её ",[428,48033,48034],{},"best_station",[422,48036,48038],{"className":424,"code":48037,"language":396,"meta":426,"style":426},"while states_needed:\n  best_station = None\n  states_covered = set()\n  for station, states_for_station in stations.items():\n",[428,48039,48040,48047,48056,48067],{"__ignoreMap":426},[431,48041,48042,48044],{"class":433,"line":434},[431,48043,12737],{"class":654},[431,48045,48046],{"class":441}," states_needed:\n",[431,48048,48049,48052,48054],{"class":433,"line":452},[431,48050,48051],{"class":441},"  best_station ",[431,48053,1189],{"class":654},[431,48055,11872],{"class":437},[431,48057,48058,48061,48063,48065],{"class":433,"line":578},[431,48059,48060],{"class":441},"  states_covered ",[431,48062,1189],{"class":654},[431,48064,27951],{"class":437},[431,48066,5728],{"class":441},[431,48068,48069,48071,48074,48076],{"class":433,"line":584},[431,48070,20523],{"class":654},[431,48072,48073],{"class":441}," station, states_for_station ",[431,48075,14421],{"class":654},[431,48077,48078],{"class":441}," stations.items():\n",[415,48080,48081,48082,48085],{},"Множество ",[428,48083,48084],{},"states_covered содержит"," все области, обслуживаемые этой станцией, которые ещё не входят в текущее покрытие.\nПомните, мы ищем станцию, которая будет обслуживать большинство ещё не охваченных областей.\nЦикл for перебирает все станции и находит среди них наилучшую.\nРассмотрим тело цикла for:",[422,48087,48089],{"className":424,"code":48088,"language":396,"meta":426,"style":426},"for station, states_for_station in stations.items():\n  covered = states_needed & states_for_station # Пересечение множеств\n  if len(covered) > len(states_covered):\n    best_station = station\n    states_covered = covered\n",[428,48090,48091,48101,48119,48135,48145],{"__ignoreMap":426},[431,48092,48093,48095,48097,48099],{"class":433,"line":434},[431,48094,14329],{"class":654},[431,48096,48073],{"class":441},[431,48098,14421],{"class":654},[431,48100,48078],{"class":441},[431,48102,48103,48106,48108,48111,48113,48116],{"class":433,"line":452},[431,48104,48105],{"class":441},"  covered ",[431,48107,1189],{"class":654},[431,48109,48110],{"class":441}," states_needed ",[431,48112,28532],{"class":654},[431,48114,48115],{"class":441}," states_for_station ",[431,48117,48118],{"class":455},"# Пересечение множеств\n",[431,48120,48121,48123,48125,48128,48130,48132],{"class":433,"line":578},[431,48122,20480],{"class":654},[431,48124,4804],{"class":437},[431,48126,48127],{"class":441},"(covered) ",[431,48129,8883],{"class":654},[431,48131,4804],{"class":437},[431,48133,48134],{"class":441},"(states_covered):\n",[431,48136,48137,48140,48142],{"class":433,"line":584},[431,48138,48139],{"class":441},"    best_station ",[431,48141,1189],{"class":654},[431,48143,48144],{"class":441}," station\n",[431,48146,48147,48150,48152],{"class":433,"line":1244},[431,48148,48149],{"class":441},"    states_covered ",[431,48151,1189],{"class":654},[431,48153,48154],{"class":441}," covered\n",[458,48156,48158],{"id":48157},"про-множества","Про множества",[415,48160,48161],{},"С двумя множествами можно выполнить ряд операций:",[697,48163,48164,48167,48170],{},[700,48165,48166],{},"объединение множеств означает слияние элементов обоих множеств;",[700,48168,48169],{},"под операцией пересечения множеств понимается поиск элементов, входящих в оба множества;",[700,48171,48172],{},"под разностью множеств понимается исключение из одного множества элементов, присутствующих в другом множестве.",[415,48174,48175],{},"Основные особенности множеств:",[697,48177,48178,48181],{},[700,48179,48180],{},"множества похожи на списки, но не содержат дубликатов;",[700,48182,48183],{},"с множествами можно выполнять различные операции — объединение пересечение и разность.",[415,48185,48186],{},[1205,48187,48188],{"href":231},"Подробнее про множества",[458,48190,48192],{"id":48191},"допишем-код","Допишем код",[415,48194,48081,48195,48198,48199,48202,48203,48206,48207,48209,48210,48212,48213,48215],{},[428,48196,48197],{},"covered"," содержит области, присутствующие как ",[428,48200,48201],{},"states_needed",", так и в ",[428,48204,48205],{},"states_for_station",".\nТаким образом, ",[428,48208,48197],{}," — множество областей, не входящих в покрытие, которые покрываются текущей станцией!\nЗатем мы проверяем, покрывает ли эта станция больше областей, чем текущая станция ",[428,48211,48034],{},".\nЕсли условие выполняется, то станция сохраняется в ",[428,48214,48034],{},".\nНаконец, после завершения цикла best_station добавляется в итоговый список станции:",[422,48217,48219],{"className":424,"code":48218,"language":396,"meta":426,"style":426},"final_station.add(best_station)\n",[428,48220,48221],{"__ignoreMap":426},[431,48222,48223],{"class":433,"line":434},[431,48224,48218],{"class":441},[415,48226,48227,48228,48230],{},"Также необходимо обновить содержимое ",[428,48229,48201],{},".\nТе области(субъекты), которые входят в зону покрытия станций, больше не нужны:",[422,48232,48234],{"className":424,"code":48233,"language":396,"meta":426,"style":426},"states_needed -= states_covered\n",[428,48235,48236],{"__ignoreMap":426},[431,48237,48238,48240,48243],{"class":433,"line":434},[431,48239,47816],{"class":441},[431,48241,48242],{"class":654},"-=",[431,48244,48245],{"class":441}," states_covered\n",[415,48247,48248,48249,48251,48252,48255],{},"Цикл продолжается, пока множество ",[428,48250,48201],{}," не станет пустым. В конце остаюётся только вывести ",[428,48253,48254],{},"final_stations",".\nПолный код выглядит так:",[422,48257,48259],{"className":424,"code":48258,"language":396,"meta":426,"style":426},"# Для обозначения субъектов РФ используются коды\n# Переданный массив преобразуется в множество\nstates_needed = set([\"28\", \"29\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\"]) \n\nstations = {}\nstations[\"one\"] = set([\"31\", \"32\", \"33\"])\nstations[\"two\"] = set([\"29\", \"31\", \"28\"])\nstations[\"three\"] = set([\"30\", \"32\", \"34\"])\nstations[\"four\"] = set([\"32\", \"33\"])\nstations[\"five\"] = set([\"34\", \"35\"])\n\nfinal_stations = set()\nwhile states_needed:\n  best_station = None\n  states_covered = set()\n  for station, states_for_station in stations.items():\n    covered = states_needed & states_for_station\n    if len(covered) > len(states_covered) and station not in final_stations:\n      best_station = station\n      states_covered = covered\n  if best_station is not None:\n    states_needed -= states_covered\n    final_stations.add(best_station)\n    stations.pop(best_station)\n    \nprint(final_stations)\n",[428,48260,48261,48265,48269,48312,48316,48324,48350,48376,48402,48424,48446,48450,48460,48466,48474,48484,48494,48508,48535,48544,48553,48568,48577,48582,48587,48591],{"__ignoreMap":426},[431,48262,48263],{"class":433,"line":434},[431,48264,47806],{"class":455},[431,48266,48267],{"class":433,"line":452},[431,48268,47811],{"class":455},[431,48270,48271,48273,48275,48277,48279,48281,48283,48285,48287,48289,48291,48293,48295,48297,48299,48301,48303,48305,48307,48309],{"class":433,"line":578},[431,48272,47816],{"class":441},[431,48274,1189],{"class":654},[431,48276,27951],{"class":437},[431,48278,17778],{"class":441},[431,48280,47825],{"class":445},[431,48282,4846],{"class":441},[431,48284,47830],{"class":445},[431,48286,4846],{"class":441},[431,48288,47835],{"class":445},[431,48290,4846],{"class":441},[431,48292,47840],{"class":445},[431,48294,4846],{"class":441},[431,48296,47845],{"class":445},[431,48298,4846],{"class":441},[431,48300,47850],{"class":445},[431,48302,4846],{"class":441},[431,48304,47855],{"class":445},[431,48306,4846],{"class":441},[431,48308,47860],{"class":445},[431,48310,48311],{"class":441},"]) \n",[431,48313,48314],{"class":433,"line":584},[431,48315,1662],{"emptyLinePlaceholder":393},[431,48317,48318,48320,48322],{"class":433,"line":1244},[431,48319,47875],{"class":441},[431,48321,1189],{"class":654},[431,48323,29580],{"class":441},[431,48325,48326,48328,48330,48332,48334,48336,48338,48340,48342,48344,48346,48348],{"class":433,"line":1985},[431,48327,47884],{"class":441},[431,48329,47887],{"class":445},[431,48331,4049],{"class":441},[431,48333,1189],{"class":654},[431,48335,27951],{"class":437},[431,48337,17778],{"class":441},[431,48339,47840],{"class":445},[431,48341,4846],{"class":441},[431,48343,47845],{"class":445},[431,48345,4846],{"class":441},[431,48347,47850],{"class":445},[431,48349,3396],{"class":441},[431,48351,48352,48354,48356,48358,48360,48362,48364,48366,48368,48370,48372,48374],{"class":433,"line":2041},[431,48353,47884],{"class":441},[431,48355,26438],{"class":445},[431,48357,4049],{"class":441},[431,48359,1189],{"class":654},[431,48361,27951],{"class":437},[431,48363,17778],{"class":441},[431,48365,47830],{"class":445},[431,48367,4846],{"class":441},[431,48369,47840],{"class":445},[431,48371,4846],{"class":441},[431,48373,47825],{"class":445},[431,48375,3396],{"class":441},[431,48377,48378,48380,48382,48384,48386,48388,48390,48392,48394,48396,48398,48400],{"class":433,"line":4018},[431,48379,47884],{"class":441},[431,48381,47940],{"class":445},[431,48383,4049],{"class":441},[431,48385,1189],{"class":654},[431,48387,27951],{"class":437},[431,48389,17778],{"class":441},[431,48391,47835],{"class":445},[431,48393,4846],{"class":441},[431,48395,47845],{"class":445},[431,48397,4846],{"class":441},[431,48399,47855],{"class":445},[431,48401,3396],{"class":441},[431,48403,48404,48406,48408,48410,48412,48414,48416,48418,48420,48422],{"class":433,"line":4030},[431,48405,47884],{"class":441},[431,48407,26449],{"class":445},[431,48409,4049],{"class":441},[431,48411,1189],{"class":654},[431,48413,27951],{"class":437},[431,48415,17778],{"class":441},[431,48417,47845],{"class":445},[431,48419,4846],{"class":441},[431,48421,47850],{"class":445},[431,48423,3396],{"class":441},[431,48425,48426,48428,48430,48432,48434,48436,48438,48440,48442,48444],{"class":433,"line":4419},[431,48427,47884],{"class":441},[431,48429,47989],{"class":445},[431,48431,4049],{"class":441},[431,48433,1189],{"class":654},[431,48435,27951],{"class":437},[431,48437,17778],{"class":441},[431,48439,47855],{"class":445},[431,48441,4846],{"class":441},[431,48443,47860],{"class":445},[431,48445,3396],{"class":441},[431,48447,48448],{"class":433,"line":4436},[431,48449,1662],{"emptyLinePlaceholder":393},[431,48451,48452,48454,48456,48458],{"class":433,"line":4446},[431,48453,48018],{"class":441},[431,48455,1189],{"class":654},[431,48457,27951],{"class":437},[431,48459,5728],{"class":441},[431,48461,48462,48464],{"class":433,"line":4451},[431,48463,12737],{"class":654},[431,48465,48046],{"class":441},[431,48467,48468,48470,48472],{"class":433,"line":4086},[431,48469,48051],{"class":441},[431,48471,1189],{"class":654},[431,48473,11872],{"class":437},[431,48475,48476,48478,48480,48482],{"class":433,"line":4477},[431,48477,48060],{"class":441},[431,48479,1189],{"class":654},[431,48481,27951],{"class":437},[431,48483,5728],{"class":441},[431,48485,48486,48488,48490,48492],{"class":433,"line":4482},[431,48487,20523],{"class":654},[431,48489,48073],{"class":441},[431,48491,14421],{"class":654},[431,48493,48078],{"class":441},[431,48495,48496,48499,48501,48503,48505],{"class":433,"line":4488},[431,48497,48498],{"class":441},"    covered ",[431,48500,1189],{"class":654},[431,48502,48110],{"class":441},[431,48504,28532],{"class":654},[431,48506,48507],{"class":441}," states_for_station\n",[431,48509,48510,48512,48514,48516,48518,48520,48523,48525,48528,48530,48532],{"class":433,"line":4505},[431,48511,10438],{"class":654},[431,48513,4804],{"class":437},[431,48515,48127],{"class":441},[431,48517,8883],{"class":654},[431,48519,4804],{"class":437},[431,48521,48522],{"class":441},"(states_covered) ",[431,48524,8946],{"class":654},[431,48526,48527],{"class":441}," station ",[431,48529,9369],{"class":654},[431,48531,21531],{"class":654},[431,48533,48534],{"class":441}," final_stations:\n",[431,48536,48537,48540,48542],{"class":433,"line":12871},[431,48538,48539],{"class":441},"      best_station ",[431,48541,1189],{"class":654},[431,48543,48144],{"class":441},[431,48545,48546,48549,48551],{"class":433,"line":2874},[431,48547,48548],{"class":441},"      states_covered ",[431,48550,1189],{"class":654},[431,48552,48154],{"class":441},[431,48554,48555,48557,48560,48562,48564,48566],{"class":433,"line":12887},[431,48556,20480],{"class":654},[431,48558,48559],{"class":441}," best_station ",[431,48561,19884],{"class":654},[431,48563,9498],{"class":654},[431,48565,21032],{"class":437},[431,48567,8102],{"class":441},[431,48569,48570,48573,48575],{"class":433,"line":12892},[431,48571,48572],{"class":441},"    states_needed ",[431,48574,48242],{"class":654},[431,48576,48245],{"class":441},[431,48578,48579],{"class":433,"line":12898},[431,48580,48581],{"class":441},"    final_stations.add(best_station)\n",[431,48583,48584],{"class":433,"line":12904},[431,48585,48586],{"class":441},"    stations.pop(best_station)\n",[431,48588,48589],{"class":433,"line":8382},[431,48590,31028],{"class":441},[431,48592,48593,48595],{"class":433,"line":25829},[431,48594,438],{"class":437},[431,48596,48597],{"class":441},"(final_stations)\n",[415,48599,48600],{},"Вместо станций 1,2,3,5 можно было выбрать станции 2,3,4, и 5.\nНиже сравним время выполнения алгоритма:",[9256,48602,48603,48707],{},[9259,48604,48605],{},[9262,48606,48607,48610,48661],{},[9265,48608,48609],{},"Кол-во станций",[9265,48611,48612,48613],{},"Точный алгоритм ",[33809,48614,48616],{"className":48615,"jax":33813},[33812],[33815,48617,48620,48633],{"style":35005,"xmlns":33818,"width":48618,"height":35007,"role":15324,"focusable":33821,"viewBox":48619,"xmlnsXLink":33823},"5.765ex","0 -750 2548.3 1000",[33825,48621,48622,48624,48626,48629,48631],{},[33828,48623],{"id":37892,"d":35014},[33828,48625],{"id":37895,"d":35018},[33828,48627],{"id":48628,"d":33843},"MJX-2-TEX-N-32",[33828,48630],{"id":40997,"d":33847},[33828,48632],{"id":37910,"d":35031},[33849,48634,48635],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,48636,48637,48641,48645,48656],{"dataMmlNode":33855},[33849,48638,48639],{"dataMmlNode":33858},[33860,48640],{"dataC":35053,"xLinkHref":37922},[33849,48642,48643],{"dataMmlNode":34206,"transform":35057},[33860,48644],{"dataC":35060,"xLinkHref":37927},[33849,48646,48647,48652],{"dataMmlNode":34252,"transform":35064},[33849,48648,48649],{"dataMmlNode":33883},[33860,48650],{"dataC":33887,"xLinkHref":48651},"#MJX-2-TEX-N-32",[33849,48653,48654],{"dataMmlNode":33858,"transform":34260},[33860,48655],{"dataC":33894,"xLinkHref":41025},[33849,48657,48659],{"dataMmlNode":34206,"transform":48658},"translate(2159.3,0)",[33860,48660],{"dataC":30851,"xLinkHref":37967},[9265,48662,48663,48664],{},"Жадный алгоритм ",[33809,48665,48667],{"className":48666,"jax":33813},[33812],[33815,48668,48669,48681],{"style":35005,"xmlns":33818,"width":40937,"height":37685,"role":15324,"focusable":33821,"viewBox":40938,"xmlnsXLink":33823},[33825,48670,48671,48673,48675,48677,48679],{},[33828,48672],{"id":39806,"d":35014},[33828,48674],{"id":39809,"d":35018},[33828,48676],{"id":43168,"d":33847},[33828,48678],{"id":39815,"d":33843},[33828,48680],{"id":39826,"d":35031},[33849,48682,48683],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,48684,48685,48689,48693,48703],{"dataMmlNode":33855},[33849,48686,48687],{"dataMmlNode":33858},[33860,48688],{"dataC":35053,"xLinkHref":39839},[33849,48690,48691],{"dataMmlNode":34206,"transform":35057},[33860,48692],{"dataC":35060,"xLinkHref":39844},[33849,48694,48695,48699],{"dataMmlNode":34252,"transform":35064},[33849,48696,48697],{"dataMmlNode":33858},[33860,48698],{"dataC":33894,"xLinkHref":43199},[33849,48700,48701],{"dataMmlNode":33883,"transform":40971},[33860,48702],{"dataC":33887,"xLinkHref":39858},[33849,48704,48705],{"dataMmlNode":34206,"transform":40976},[33860,48706],{"dataC":30851,"xLinkHref":39881},[9275,48708,48709,48719,48728,48737],{},[9262,48710,48711,48713,48716],{},[9280,48712,856],{},[9280,48714,48715],{},"3.3 сек",[9280,48717,48718],{},"2.5 сек",[9262,48720,48721,48723,48726],{},[9280,48722,3565],{},[9280,48724,48725],{},"102.5 сек",[9280,48727,29167],{},[9262,48729,48730,48732,48735],{},[9280,48731,33887],{},[9280,48733,48734],{},"13.6 лет",[9280,48736,48725],{},[9262,48738,48739,48741,48799],{},[9280,48740,2249],{},[9280,48742,48743,48798],{},[33809,48744,48746],{"className":48745,"jax":33813},[33812],[33815,48747,48751,48765],{"style":34023,"xmlns":33818,"width":48748,"height":48749,"role":15324,"focusable":33821,"viewBox":48750,"xmlnsXLink":33823},"7.318ex","2.005ex","0 -864 3234.6 886",[33825,48752,48753,48756,48759,48761,48763],{},[33828,48754],{"id":48755,"d":37705},"MJX-4-TEX-N-34",[33828,48757],{"id":48758,"d":41001},"MJX-4-TEX-N-2217",[33828,48760],{"id":34092,"d":33927},[33828,48762],{"id":34095,"d":33931},[33828,48764],{"id":34089,"d":33843},[33849,48766,48767],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,48768,48769,48774,48780],{"dataMmlNode":33855},[33849,48770,48771],{"dataMmlNode":33883},[33860,48772],{"dataC":36947,"xLinkHref":48773},"#MJX-4-TEX-N-34",[33849,48775,48777],{"dataMmlNode":34206,"transform":48776},"translate(722.2,0)",[33860,48778],{"dataC":41031,"xLinkHref":48779},"#MJX-4-TEX-N-2217",[33849,48781,48783,48789],{"dataMmlNode":34252,"transform":48782},"translate(1444.4,0)",[33849,48784,48785,48787],{"dataMmlNode":33883},[33860,48786],{"dataC":30856,"xLinkHref":34128},[33860,48788],{"dataC":19593,"xLinkHref":34131,"transform":33965},[33849,48790,48792],{"dataMmlNode":33955,"transform":48791,"dataMjxTexclass":33956},"translate(1033,393.1) scale(0.707)",[33849,48793,48794,48796],{"dataMmlNode":33883},[33860,48795],{"dataC":33887,"xLinkHref":34123},[33860,48797],{"dataC":30856,"xLinkHref":34128,"transform":33965}," лет",[9280,48800,48801],{},"16.68 мин",[415,48803,48804],{},"Жадные алгоритмы не всегда дают точный ответ, но они очень быстрые.\nЗадача о покрытии множеств относится к NP-трудным задачам.\nНемного позже в статьях я приведу больше примеров об NP-трудных задачах.\nА на этом знакомство с жадными алгоритмами можно считать успешным.",[8839,48806,48807],{},[415,48808,48809,48810,2699],{},"В следующей статье речь пойдёт про ",[1205,48811,48812],{"href":299},"динамическое программирование",[458,48814],{"id":426},[29130,48816],{":isList":48817,"title":30269},"[\"Жадные алгоритмы стремятся к локальной оптимизации в расчёте на то, что в итоге будет достигнут глобальный оптимум;\",\"Если у вас имеется NP-трудная задача, лучше всего воспользоваться приближённым алгоритмом;\",\"Жадные алгоритмы легко реализовать и быстро выполнить, поэтому из них получаются хорошие приближённые алгоритмы.\"]",[415,48819,34817,48820,1853,48822,1857],{},[800,48821,1852],{},[800,48823,1856],{},[1859,48825],{},[1862,48827,35276],{},[1862,48829,5434],{},{"title":426,"searchDepth":452,"depth":1244,"links":48831},[48832],{"id":47543,"depth":452,"text":294,"children":48833},[48834,48835,48836],{"id":47558,"depth":578,"text":47559},{"id":47652,"depth":578,"text":47653},{"id":47683,"depth":578,"text":47684,"children":48837},[48838,48839,48840,48841,48842,48843],{"id":47713,"depth":584,"text":47714},{"id":47792,"depth":584,"text":47793},{"id":48027,"depth":584,"text":48028},{"id":48157,"depth":584,"text":48158},{"id":48191,"depth":584,"text":48192},{"id":426,"depth":584,"text":426},"2026-04-28","Жадная стратегия при решении задач. NP-трудные задачи. Приближенное решение NP-полных задач.","images\u002Fblog\u002Fpython\u002Fst33\u002Fimg.png",{},{"title":294,"description":48845},"IeqOT254nEE86UtkOJ4PzgDox-krD2l0va4hH7wx6nc",{"id":48851,"title":298,"author":48852,"body":48854,"date":51900,"description":51901,"extension":1887,"image":51902,"meta":51903,"minRead":12482,"navigation":393,"num":32027,"path":299,"seo":51904,"stem":300,"__hash__":51905},"python\u002Fblog\u002Fpython\u002Fst34.md",{"name":402,"avatar":48853},{"src":404,"alt":405},{"type":407,"value":48855,"toc":51865},[48856,48859,48862,48871,48873,48878,48881,48920,48923,48927,48974,48977,48980,48983,48986,48989,49043,49046,49049,49052,49055,49110,49113,49167,49170,49224,49227,49230,49233,49287,49290,49344,49347,49402,49405,49408,49411,49465,49468,49523,49526,49581,49584,49588,49591,49595,49598,49652,49655,49723,49726,49792,49795,49862,49865,49869,49872,49876,49879,49883,49886,49995,49999,50002,50006,50009,50074,50077,50160,50163,50241,50245,50248,50330,50333,50336,50340,50343,50347,50350,50352,50355,50363,50366,50377,50381,50384,50388,50391,50402,50405,50475,50479,50482,50548,50551,50553,50556,50622,50625,50633,50636,50854,50857,51062,51065,51145,51148,51152,51155,51222,51225,51229,51232,51240,51243,51309,51376,51379,51599,51817,51820,51831,51834,51842,51844,51847,51849,51853,51859,51861,51863],[410,48857,298],{"id":48858},"динамическое-программирование",[29130,48860],{":isList":48861,"title":43905},"[\"Узнаете про динамическое программирование — метод решения сложных задач, разбиваемых на подзадачи, которые решаются в первую очередь.\",\"Рассматриваются примеры, которые научат вас искать решения новых задач, основанные на методе динамического программирования.\"]",[8839,48863,48864],{},[415,48865,48866,48867,48870],{},"В предыдущей статье было о: ",[1205,48868,48869],{"href":291},"жадных алгоритмах",".\nЗдесь далее текст пойдёт о динамическом программировании.",[632,48872,47653],{"id":47652},[8839,48874,48875],{},[415,48876,48877],{},"Задача о рюкзаке была описана в предыдущей статье.",[415,48879,48880],{},"Вернёмся к задаче о рюкзаке. У вас есть рюкзак, в котором можно унести товары общим весом до 4 кг.\nЕсть 3 предмета, которые можно положить в рюкзак.",[9256,48882,48883,48896],{},[9259,48884,48885],{},[9262,48886,48887,48890,48893],{},[9265,48888,48889],{},"Магнитофон",[9265,48891,48892],{},"Ноутбук",[9265,48894,48895],{},"Гитара",[9275,48897,48898,48909],{},[9262,48899,48900,48903,48906],{},[9280,48901,48902],{},"3000 руб",[9280,48904,48905],{},"2000 руб",[9280,48907,48908],{},"1500 руб",[9262,48910,48911,48914,48917],{},[9280,48912,48913],{},"4 кг",[9280,48915,48916],{},"3 кг",[9280,48918,48919],{},"1 кг",[415,48921,48922],{},"Какие предметы следует положить в рюкзак, чтобы стоимость добычи была максимальной?",[458,48924,48926],{"id":48925},"простое-решение","Простое решение",[415,48928,48929,48930,48973],{},"Простой способ решения выглядит так: вы перебираете все возможные множества товаров и находите множество с максимальной стоимостью.\nТакое решение работает очень медленно. Для 3 предметов приходится обработать 8 множеств, для 4 — 16 и т.д.\nС каждым добавленным предметом количество множеств удваивается. Такое решение будет выполняться за время: ",[33809,48931,48933],{"className":48932,"jax":33813},[33812],[33815,48934,48935,48947],{"style":35005,"xmlns":33818,"width":48618,"height":35007,"role":15324,"focusable":33821,"viewBox":48619,"xmlnsXLink":33823},[33825,48936,48937,48939,48941,48943,48945],{},[33828,48938],{"id":37720,"d":35014},[33828,48940],{"id":37691,"d":35018},[33828,48942],{"id":33842,"d":33843},[33828,48944],{"id":33846,"d":33847},[33828,48946],{"id":37708,"d":35031},[33849,48948,48949],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,48950,48951,48955,48959,48969],{"dataMmlNode":33855},[33849,48952,48953],{"dataMmlNode":33858},[33860,48954],{"dataC":35053,"xLinkHref":37829},[33849,48956,48957],{"dataMmlNode":34206,"transform":35057},[33860,48958],{"dataC":35060,"xLinkHref":37732},[33849,48960,48961,48965],{"dataMmlNode":34252,"transform":35064},[33849,48962,48963],{"dataMmlNode":33883},[33860,48964],{"dataC":33887,"xLinkHref":33888},[33849,48966,48967],{"dataMmlNode":33858,"transform":34260},[33860,48968],{"dataC":33894,"xLinkHref":33895},[33849,48970,48971],{"dataMmlNode":34206,"transform":48658},[33860,48972],{"dataC":30851,"xLinkHref":37767},".\nЭто слишком медленно!",[415,48975,48976],{},"Для любого сколько-нибудь значительного количества предметов это неприемлемо долго!\nМожно воспользоваться приближённым решением, но такое решение может существенно не совпадать с оптимальным.\nКак вычислить оптимальное решение? С помощью динамического программирования!",[632,48978,298],{"id":48979},"динамическое-программирование-1",[415,48981,48982],{},"Рассмотрим как работает данный способ решения задачи.\nПроцедура решения начинается с решения подзадач с постепенным переходом к решению полной задачи.\nВ задаче о рюкзаке начать следует с решения задачи для меньшего рюкзака(или \"подрюкзака\"), а потом на этой основе попытаться решить исходную задачу.",[415,48984,48985],{},"Динамическое программирование — достаточно сложная концепция.\nДополнительные примеры помогут вам в дальнейшем лучше разобраться с этой темой.",[415,48987,48988],{},"Для начала рассмотрим алгоритм в действии.\nКаждый алгоритм динамического программирования начинается с таблицы. Вот как выглядит таблица для задачи о рюкзаке:",[9256,48990,48991,49005],{},[9259,48992,48993],{},[9262,48994,48995,48997,48999,49001,49003],{},[9265,48996,853],{},[9265,48998,1192],{},[9265,49000,651],{},[9265,49002,971],{},[9265,49004,762],{},[9275,49006,49007,49019,49031],{},[9262,49008,49009,49011,49013,49015,49017],{},[9280,49010,48895],{},[9280,49012],{},[9280,49014],{},[9280,49016],{},[9280,49018],{},[9262,49020,49021,49023,49025,49027,49029],{},[9280,49022,48889],{},[9280,49024],{},[9280,49026],{},[9280,49028],{},[9280,49030],{},[9262,49032,49033,49035,49037,49039,49041],{},[9280,49034,48892],{},[9280,49036],{},[9280,49038],{},[9280,49040],{},[9280,49042],{},[415,49044,49045],{},"Строки таблицы представляют предметы, а столбцы — ёмкость рюкзака от 1 до 4 кг.\nВсе эти столбы нужны, потому что они упрощают вычисление стоимостей \"подкрюкзаков\".\nВ исходном состоянии таблица пуста. Нам предстоит заполнить каждую ячейку таблицы.\nПосле того как таблица будет заполнена, вы получите ответ на свою задачу.\nПожалуйста, внимательно разберитесь в происходящем. Нарисуйте собственную таблицу.",[12129,49047,48895],{"id":49048},"гитара",[415,49050,49051],{},"Точная формула для вычисления значений в таблице будет приведена позднее, а пока ограничимся общим описанием.\nНачнём с первой строки.\nСтрока снабжена пометкой «гитара»; это означает, что вы пытаетесь уложить гитару в рюкзак.\nВ каждой ячейке принимается простое решение:класть гитару в рюкзак или нет?\nПомните: мы пытаемся найти множество элементов с максимальной стоимостью.",[415,49053,49054],{},"В первой ячейке емкость рюкзака равна 1 кг. Гитара также весит 1 кг — значит, она поместится в рюкзак!\nИтак, стоимость этой ячейки составляет 1500₽, а в рюкзаке лежит гитара.\nНачнем заполнять ячейку:",[9256,49056,49057,49071],{},[9259,49058,49059],{},[9262,49060,49061,49063,49065,49067,49069],{},[9265,49062,853],{},[9265,49064,1192],{},[9265,49066,651],{},[9265,49068,971],{},[9265,49070,762],{},[9275,49072,49073,49086,49098],{},[9262,49074,49075,49077,49080,49082,49084],{},[9280,49076,48895],{},[9280,49078,49079],{},"1500",[9280,49081],{},[9280,49083],{},[9280,49085],{},[9262,49087,49088,49090,49092,49094,49096],{},[9280,49089,48889],{},[9280,49091],{},[9280,49093],{},[9280,49095],{},[9280,49097],{},[9262,49099,49100,49102,49104,49106,49108],{},[9280,49101,48892],{},[9280,49103],{},[9280,49105],{},[9280,49107],{},[9280,49109],{},[415,49111,49112],{},"По тому же принципу каждая ячейка в таблице содержит список всех элементов, которые помещаются в рюкзаке на данный момент.\nПосмотрим на следующую ячейку. На этот раз емкость рюкзака составляет 2 кг. Понятно, что гитара здесь поместится!",[9256,49114,49115,49129],{},[9259,49116,49117],{},[9262,49118,49119,49121,49123,49125,49127],{},[9265,49120,853],{},[9265,49122,1192],{},[9265,49124,651],{},[9265,49126,971],{},[9265,49128,762],{},[9275,49130,49131,49143,49155],{},[9262,49132,49133,49135,49137,49139,49141],{},[9280,49134,48895],{},[9280,49136,49079],{},[9280,49138,49079],{},[9280,49140],{},[9280,49142],{},[9262,49144,49145,49147,49149,49151,49153],{},[9280,49146,48889],{},[9280,49148],{},[9280,49150],{},[9280,49152],{},[9280,49154],{},[9262,49156,49157,49159,49161,49163,49165],{},[9280,49158,48892],{},[9280,49160],{},[9280,49162],{},[9280,49164],{},[9280,49166],{},[415,49168,49169],{},"Процедура повторяется для остальных ячеек строки.\nВспомните, что текущей является первая строка, поэтому выбирать приходится только из одного предмета — гитары.\nСчитайте, что два других предмета пока недоступны.\nПочему все это делается для рюкзаков с емкостью 1, 2 и т.д., если в задаче речь идет о рюкзаке с емкостью 4 кг?\nМетод динамического программирования начинает с малых задач, а затем переходит к большой задаче.\nВы решаете подзадачи, которые помогут в решении большой задачи.\nПосле того как первая строка будет заполнена, таблица будет выглядеть так:",[9256,49171,49172,49186],{},[9259,49173,49174],{},[9262,49175,49176,49178,49180,49182,49184],{},[9265,49177,853],{},[9265,49179,1192],{},[9265,49181,651],{},[9265,49183,971],{},[9265,49185,762],{},[9275,49187,49188,49200,49212],{},[9262,49189,49190,49192,49194,49196,49198],{},[9280,49191,48895],{},[9280,49193,49079],{},[9280,49195,49079],{},[9280,49197,49079],{},[9280,49199,49079],{},[9262,49201,49202,49204,49206,49208,49210],{},[9280,49203,48889],{},[9280,49205],{},[9280,49207],{},[9280,49209],{},[9280,49211],{},[9262,49213,49214,49216,49218,49220,49222],{},[9280,49215,48892],{},[9280,49217],{},[9280,49219],{},[9280,49221],{},[9280,49223],{},[415,49225,49226],{},"Помните, что мы стремимся обеспечить максимальную стоимость предметов в рюкзаке.\nЭта строка представляет текущую лучшую оценку максимума.\nИтак, на данный момент из этой строки следует, что для рюкзака с емкостью 4 кг максимальная стоимость предметов составит 1500₽.\nЭто решение неокончательно. В процессе работы алгоритма оценка будет уточняться.",[12129,49228,48889],{"id":49229},"магнитофон",[415,49231,49232],{},"Займемся следующей строкой, которая относится к магнитофону.\nТеперь, когда вы перешли ко второй строке, появляется выбор между магнитофоном и гитарой.\nВ каждой строке можно взять предмет этой строки или предметы, находящиеся в верхних строках.\nТаким образом, сейчас нельзя выбрать ноутбук, но можно выбрать магнитофон и\u002Fили гитару.\nНачнем с первой ячейки (рюкзак с емкостью 1 кг).\nТекущая максимальная стоимость предметов, которые можно положить в рюкзак с емкостью 1 кг, составляет 1500₽.\nБрать магнитофон или нет?\nЕмкость рюкзака составляет 1 кг. Поместится туда магнитофон? Нет, он слишком тяжел!\nТак как магнитофон не помещается в рюкзак, максимальная оценка для 1-кг рюкзака остается равной 1500₽.",[9256,49234,49235,49249],{},[9259,49236,49237],{},[9262,49238,49239,49241,49243,49245,49247],{},[9265,49240,853],{},[9265,49242,1192],{},[9265,49244,651],{},[9265,49246,971],{},[9265,49248,762],{},[9275,49250,49251,49263,49275],{},[9262,49252,49253,49255,49257,49259,49261],{},[9280,49254,48895],{},[9280,49256,49079],{},[9280,49258,49079],{},[9280,49260,49079],{},[9280,49262,49079],{},[9262,49264,49265,49267,49269,49271,49273],{},[9280,49266,48889],{},[9280,49268,49079],{},[9280,49270],{},[9280,49272],{},[9280,49274],{},[9262,49276,49277,49279,49281,49283,49285],{},[9280,49278,48892],{},[9280,49280],{},[9280,49282],{},[9280,49284],{},[9280,49286],{},[415,49288,49289],{},"То же самое происходит со следующими двумя клетками.\nЕмкость этих рюкзаков составляет 2 и 3 кг соответственно.\nМаксимальная стоимость для обеих ячеек была равна 1500₽.",[9256,49291,49292,49306],{},[9259,49293,49294],{},[9262,49295,49296,49298,49300,49302,49304],{},[9265,49297,853],{},[9265,49299,1192],{},[9265,49301,651],{},[9265,49303,971],{},[9265,49305,762],{},[9275,49307,49308,49320,49332],{},[9262,49309,49310,49312,49314,49316,49318],{},[9280,49311,48895],{},[9280,49313,49079],{},[9280,49315,49079],{},[9280,49317,49079],{},[9280,49319,49079],{},[9262,49321,49322,49324,49326,49328,49330],{},[9280,49323,48889],{},[9280,49325,49079],{},[9280,49327,49079],{},[9280,49329,49079],{},[9280,49331],{},[9262,49333,49334,49336,49338,49340,49342],{},[9280,49335,48892],{},[9280,49337],{},[9280,49339],{},[9280,49341],{},[9280,49343],{},[415,49345,49346],{},"Магнитофон все равно не помещается, так что оценка остается неизменной.\nА если емкость рюкзака увеличивается до 4 кг?\nАга, магнитофон наконец-то войдет в рюкзак!\nСтарая максимальная стоимость была равна 1500₽, но если вместо гитары положить магнитофон, она увеличится до 3000₽!\nБерем магнитофон.",[9256,49348,49349,49363],{},[9259,49350,49351],{},[9262,49352,49353,49355,49357,49359,49361],{},[9265,49354,853],{},[9265,49356,1192],{},[9265,49358,651],{},[9265,49360,971],{},[9265,49362,762],{},[9275,49364,49365,49377,49390],{},[9262,49366,49367,49369,49371,49373,49375],{},[9280,49368,48895],{},[9280,49370,49079],{},[9280,49372,49079],{},[9280,49374,49079],{},[9280,49376,49079],{},[9262,49378,49379,49381,49383,49385,49387],{},[9280,49380,48889],{},[9280,49382,49079],{},[9280,49384,49079],{},[9280,49386,49079],{},[9280,49388,49389],{},"3000",[9262,49391,49392,49394,49396,49398,49400],{},[9280,49393,48892],{},[9280,49395],{},[9280,49397],{},[9280,49399],{},[9280,49401],{},[415,49403,49404],{},"Оценка только что обновилась! Имея рюкзак емкостью 4 кг, вы можете положить в него товары стоимостью по крайней мере 3000₽.\nИз таблицы видно, что оценка постепенно возрастает.",[12129,49406,48892],{"id":49407},"ноутбук",[415,49409,49410],{},"А теперь проделаем то же для ноутбука! Ноутбук весит 3 кг, поэтому он не поместится в рюкзак с емкостью 1 или 2 кг.\nОценка для первых двух ячеек остается на уровне 1500₽.",[9256,49412,49413,49427],{},[9259,49414,49415],{},[9262,49416,49417,49419,49421,49423,49425],{},[9265,49418,853],{},[9265,49420,1192],{},[9265,49422,651],{},[9265,49424,971],{},[9265,49426,762],{},[9275,49428,49429,49441,49453],{},[9262,49430,49431,49433,49435,49437,49439],{},[9280,49432,48895],{},[9280,49434,49079],{},[9280,49436,49079],{},[9280,49438,49079],{},[9280,49440,49079],{},[9262,49442,49443,49445,49447,49449,49451],{},[9280,49444,48889],{},[9280,49446,49079],{},[9280,49448,49079],{},[9280,49450,49079],{},[9280,49452,49389],{},[9262,49454,49455,49457,49459,49461,49463],{},[9280,49456,48892],{},[9280,49458,49079],{},[9280,49460,49079],{},[9280,49462],{},[9280,49464],{},[415,49466,49467],{},"Для 3 кг старая оценка составляла 1500₽.\nНо теперь вы можете выбрать ноутбук, который стоит 2000₽.\nСледовательно, новая максимальная оценка равна 2000₽!",[9256,49469,49470,49484],{},[9259,49471,49472],{},[9262,49473,49474,49476,49478,49480,49482],{},[9265,49475,853],{},[9265,49477,1192],{},[9265,49479,651],{},[9265,49481,971],{},[9265,49483,762],{},[9275,49485,49486,49498,49510],{},[9262,49487,49488,49490,49492,49494,49496],{},[9280,49489,48895],{},[9280,49491,49079],{},[9280,49493,49079],{},[9280,49495,49079],{},[9280,49497,49079],{},[9262,49499,49500,49502,49504,49506,49508],{},[9280,49501,48889],{},[9280,49503,49079],{},[9280,49505,49079],{},[9280,49507,49079],{},[9280,49509,49389],{},[9262,49511,49512,49514,49516,49518,49521],{},[9280,49513,48892],{},[9280,49515,49079],{},[9280,49517,49079],{},[9280,49519,49520],{},"2000",[9280,49522],{},[415,49524,49525],{},"При 4 кг ситуация становится по-настоящему интересной. Это очень важная часть.\nВ настоящее время оценка составляет 3000₽.\nВ рюкзак можно положить ноутбук, но он стоит всего 2000₽.\nВ соответствии с последней оценкой в свободном месте емкостью в 1 кг можно разместить гитару стоимостью 1500₽.\nСледовательно, настоящее сравнение выглядит так: 3000₽(магнитофон) или (2000₽(ноутбук) + 1500₽(гитара)).\nЗачем мы вычисляем максимальную стоимость для рюкзаков меньшей емкости? Надеюсь, теперь всё ясно!\nЕсли в рюкзаке остается свободное место, вы можете использовать ответы на эти подзадачи для определения того, чем заполнить это пространство.\nВместо магнитофона лучше взять ноутбук + гитару за 3500₽.\nВ завершающем состоянии таблица выглядит так:",[9256,49527,49528,49542],{},[9259,49529,49530],{},[9262,49531,49532,49534,49536,49538,49540],{},[9265,49533,853],{},[9265,49535,1192],{},[9265,49537,651],{},[9265,49539,971],{},[9265,49541,762],{},[9275,49543,49544,49556,49568],{},[9262,49545,49546,49548,49550,49552,49554],{},[9280,49547,48895],{},[9280,49549,49079],{},[9280,49551,49079],{},[9280,49553,49079],{},[9280,49555,49079],{},[9262,49557,49558,49560,49562,49564,49566],{},[9280,49559,48889],{},[9280,49561,49079],{},[9280,49563,49079],{},[9280,49565,49079],{},[9280,49567,49389],{},[9262,49569,49570,49572,49574,49576,49578],{},[9280,49571,48892],{},[9280,49573,49079],{},[9280,49575,49079],{},[9280,49577,49520],{},[9280,49579,49580],{},"3500",[415,49582,49583],{},"Итак, мы получили ответ: максимальная стоимость товаров, которые поместятся в рюкзак, равна 3500₽ — для гитары и ноутбука.\nСтоимость каждой ячейки вычисляется по постоянной формуле, которая выглядит так:\nмаксимум из предыдущего элемента или стоимость текущего элемента плюс стоимость оставшегося пространства.\nТаким образом, в данной задаче объединяется решение двух подзадач для решения ещё одной большей задачи.",[632,49585,49587],{"id":49586},"вопросы-по-задаче","Вопросы по задаче",[415,49589,49590],{},"Ответим на вопросы которую могут возникнуть.",[12129,49592,49594],{"id":49593},"что-произойдет-при-добавлении-элемента","Что произойдет при добавлении элемента?",[415,49596,49597],{},"Представьте, что вы увидели четвертый предмет, который тоже можно засунуть в рюкзак!\nВместе со всем предыдущим добром можно также взять смартфон.\nПридется ли пересчитывать все заново с новым предметом? Нет.\nДинамическое программирование последовательно строит решение на основании вашей оценки.\nК настоящему моменту максимальные стоимости выглядят так:",[9256,49599,49600,49614],{},[9259,49601,49602],{},[9262,49603,49604,49606,49608,49610,49612],{},[9265,49605,853],{},[9265,49607,1192],{},[9265,49609,651],{},[9265,49611,971],{},[9265,49613,762],{},[9275,49615,49616,49628,49640],{},[9262,49617,49618,49620,49622,49624,49626],{},[9280,49619,48895],{},[9280,49621,49079],{},[9280,49623,49079],{},[9280,49625,49079],{},[9280,49627,49079],{},[9262,49629,49630,49632,49634,49636,49638],{},[9280,49631,48889],{},[9280,49633,49079],{},[9280,49635,49079],{},[9280,49637,49079],{},[9280,49639,49389],{},[9262,49641,49642,49644,49646,49648,49650],{},[9280,49643,48892],{},[9280,49645,49079],{},[9280,49647,49079],{},[9280,49649,49520],{},[9280,49651,49580],{},[415,49653,49654],{},"Это означает, что в рюкзак с емкостью 4 кг можно упаковать товары стоимостью до 3500₽.\nДобавим новую строку для смартфона.",[9256,49656,49657,49671],{},[9259,49658,49659],{},[9262,49660,49661,49663,49665,49667,49669],{},[9265,49662,853],{},[9265,49664,1192],{},[9265,49666,651],{},[9265,49668,971],{},[9265,49670,762],{},[9275,49672,49673,49685,49697,49709],{},[9262,49674,49675,49677,49679,49681,49683],{},[9280,49676,48895],{},[9280,49678,49079],{},[9280,49680,49079],{},[9280,49682,49079],{},[9280,49684,49079],{},[9262,49686,49687,49689,49691,49693,49695],{},[9280,49688,48889],{},[9280,49690,49079],{},[9280,49692,49079],{},[9280,49694,49079],{},[9280,49696,49389],{},[9262,49698,49699,49701,49703,49705,49707],{},[9280,49700,48892],{},[9280,49702,49079],{},[9280,49704,49079],{},[9280,49706,49520],{},[9280,49708,49580],{},[9262,49710,49711,49714,49716,49718,49720],{},[9280,49712,49713],{},"Смартфон",[9280,49715],{},[9280,49717],{},[9280,49719],{},[9280,49721,49722],{},"ответ",[415,49724,49725],{},"Оказывается, в таблице появляется новый максимум! Заполним последнюю строку.\nНачнем с первой ячейки. Смартфон сам по себе помещается в рюкзак с емкостью 1 кг.\nСтарый максимум был равен 1500₽, но Смартфон стоит 2000₽.\nЗначит, берем Смартфон.\nВ следующей далее можно разместить смартфон и гитару.",[9256,49727,49728,49742],{},[9259,49729,49730],{},[9262,49731,49732,49734,49736,49738,49740],{},[9265,49733,853],{},[9265,49735,1192],{},[9265,49737,651],{},[9265,49739,971],{},[9265,49741,762],{},[9275,49743,49744,49756,49768,49780],{},[9262,49745,49746,49748,49750,49752,49754],{},[9280,49747,48895],{},[9280,49749,49079],{},[9280,49751,49079],{},[9280,49753,49079],{},[9280,49755,49079],{},[9262,49757,49758,49760,49762,49764,49766],{},[9280,49759,48889],{},[9280,49761,49079],{},[9280,49763,49079],{},[9280,49765,49079],{},[9280,49767,49389],{},[9262,49769,49770,49772,49774,49776,49778],{},[9280,49771,48892],{},[9280,49773,49079],{},[9280,49775,49079],{},[9280,49777,49520],{},[9280,49779,49580],{},[9262,49781,49782,49784,49786,49788,49790],{},[9280,49783,49713],{},[9280,49785,49520],{},[9280,49787,49580],{},[9280,49789],{},[9280,49791],{},[415,49793,49794],{},"Для ячейки 3 ничего лучшего, чем снова взять смартфон вместе с гитарой, все равно не найдется.\nА вот в последней ячейке ситуация становится интересной. Текущий максимум до смартфона был равен 3500₽.\nСнова можно взять смартфон, и еще останется свободное место на 3 кг.\nНо эти 3 кг можно заполнить на 2000₽! 2000₽ от смартфона + 2000₽ из старой подзадачи: получается 4000₽. Новый максимум!\nВот как выглядит новая завершающая таблица:",[9256,49796,49797,49811],{},[9259,49798,49799],{},[9262,49800,49801,49803,49805,49807,49809],{},[9265,49802,853],{},[9265,49804,1192],{},[9265,49806,651],{},[9265,49808,971],{},[9265,49810,762],{},[9275,49812,49813,49825,49837,49849],{},[9262,49814,49815,49817,49819,49821,49823],{},[9280,49816,48895],{},[9280,49818,49079],{},[9280,49820,49079],{},[9280,49822,49079],{},[9280,49824,49079],{},[9262,49826,49827,49829,49831,49833,49835],{},[9280,49828,48889],{},[9280,49830,49079],{},[9280,49832,49079],{},[9280,49834,49079],{},[9280,49836,49389],{},[9262,49838,49839,49841,49843,49845,49847],{},[9280,49840,48892],{},[9280,49842,49079],{},[9280,49844,49079],{},[9280,49846,49520],{},[9280,49848,49580],{},[9262,49850,49851,49853,49855,49857,49859],{},[9280,49852,49713],{},[9280,49854,49520],{},[9280,49856,49580],{},[9280,49858,49580],{},[9280,49860,49861],{},"4000",[415,49863,49864],{},"Вопрос: может ли значение в столбце уменьшиться? Ответ: нет. При каждой итерации сохраняется текущая оценка максимума.\nЭта оценка ни при каких условиях не может быть меньше предыдущей!",[12129,49866,49868],{"id":49867},"что-произойдет-при-изменении-порядка-строк","Что произойдет при изменении порядка строк?",[415,49870,49871],{},"Допустим, строки заполняются в другом порядке: магнитофон, ноутбук, гитара.\nКак будет выглядеть таблица? Изменится ли ответ? Заполните таблицу самостоятельно и убедитесь — ответ не изменился.\nОтвет не зависит от порядка строк.",[12129,49873,49875],{"id":49874},"можно-ли-заполнять-таблицу-по-столбцам-а-не-по-строкам","Можно ли заполнять таблицу по столбцам, а не по строкам?",[415,49877,49878],{},"В данной задаче это ни на что не влияет, но в других задачах возможны изменения.",[12129,49880,49882],{"id":49881},"что-произойдет-при-добавлении-меньшего-элемента","Что произойдет при добавлении меньшего элемента?",[415,49884,49885],{},"Допустим, вы можете выбрать ожерелье, которое весит 0,5 кг и стоит 1000₽.\nИзначально наша структура таблицы предполагает, что все веса являются целыми числами.\nТеперь вы решаете взять ожерелье. Остается еще 3,5 кг.\nКакую максимальную стоимость можно разместить в объеме 3,5 кг? Неизвестно!\nМы вычисляли стоимость только для рюкзаков с емкостью 1, 2, 3 и 4 кг.\nТеперь придется определять стоимость для рюкзака на 3,5 кг.\nИз-за ожерелья приходится повысить точность представления весов, поэтому таблица должна измениться.",[9256,49887,49888,49912],{},[9259,49889,49890],{},[9262,49891,49892,49894,49896,49898,49901,49903,49906,49908,49910],{},[9265,49893,853],{},[9265,49895,8557],{},[9265,49897,1192],{},[9265,49899,49900],{},"1.5",[9265,49902,651],{},[9265,49904,49905],{},"2.5",[9265,49907,971],{},[9265,49909,4500],{},[9265,49911,762],{},[9275,49913,49914,49934,49954,49974],{},[9262,49915,49916,49918,49920,49922,49924,49926,49928,49930,49932],{},[9280,49917,48895],{},[9280,49919],{},[9280,49921],{},[9280,49923],{},[9280,49925],{},[9280,49927],{},[9280,49929],{},[9280,49931],{},[9280,49933],{},[9262,49935,49936,49938,49940,49942,49944,49946,49948,49950,49952],{},[9280,49937,48889],{},[9280,49939],{},[9280,49941],{},[9280,49943],{},[9280,49945],{},[9280,49947],{},[9280,49949],{},[9280,49951],{},[9280,49953],{},[9262,49955,49956,49958,49960,49962,49964,49966,49968,49970,49972],{},[9280,49957,48892],{},[9280,49959],{},[9280,49961],{},[9280,49963],{},[9280,49965],{},[9280,49967],{},[9280,49969],{},[9280,49971],{},[9280,49973],{},[9262,49975,49976,49979,49981,49983,49985,49987,49989,49991,49993],{},[9280,49977,49978],{},"Ожерелье",[9280,49980],{},[9280,49982],{},[9280,49984],{},[9280,49986],{},[9280,49988],{},[9280,49990],{},[9280,49992],{},[9280,49994],{},[12129,49996,49998],{"id":49997},"можно-ли-взять-часть-предмета","Можно ли взять часть предмета?",[415,50000,50001],{},"Допустим, вы наполняете рюкзак в продуктовом магазине. Вы можете взять мешки с чечевицей и рисом.\nЕсли весь мешок не помещается, его можно открыть и отсыпать столько, сколько унесете.\nВ этом случае вы уже не действуете по принципу «все или ничего» — можно взять только часть предмета.\nКак решить такую задачу методом динамического программирования?\nОтвет: никак. В решении, полученном методом динамического программирования, вы либо берете предмет, либо не берете.\nАлгоритм не предусматривает возможности взять половину предмета.\nОднако проблема легко решается с помощью жадного алгоритма!\nСначала вы берете самый ценный предмет — настолько бóльшую его часть, насколько возможно.\nКогда самый ценный предмет будет исчерпан, вы берете максимально возможную часть следующего по ценности предмета и т.д.",[458,50003,50005],{"id":50004},"оптимизация-туристического-маршрута","Оптимизация туристического маршрута",[415,50007,50008],{},"Представьте, что вы приехали в Лондон на выходные. У вас два дня, а мест, которые хочется посетить, слишком много.\nПобывать везде не получится, поэтому вы составляете список.\nДля каждой достопримечательности, которую вы захотите увидеть, вы указываете, сколько времени займет осмотр и насколько сильно вы хотите ее увидеть.\nСможете ли вы построить оптимальный туристический маршрут на основании этого списка?\nДа это все та же задача о рюкзаке! Вместо ограниченной емкости рюкзака — ограниченное время.\nВместо магнитофонов и ноутбуков — список мест, которые вы хотите посетить.",[9256,50010,50011,50024],{},[9259,50012,50013],{},[9262,50014,50015,50018,50021],{},[9265,50016,50017],{},"Достопримечательность",[9265,50019,50020],{},"Время",[9265,50022,50023],{},"Оценка",[9275,50025,50026,50036,50046,50055,50065],{},[9262,50027,50028,50031,50034],{},[9280,50029,50030],{},"Вестминстерское аббатство",[9280,50032,50033],{},"1\u002F2 дня",[9280,50035,781],{},[9262,50037,50038,50041,50044],{},[9280,50039,50040],{},"Национальная галерея",[9280,50042,50043],{},"1 день",[9280,50045,3357],{},[9262,50047,50048,50051,50053],{},[9280,50049,50050],{},"Театр",[9280,50052,50033],{},[9280,50054,742],{},[9262,50056,50057,50060,50063],{},[9280,50058,50059],{},"Музей",[9280,50061,50062],{},"2 дня",[9280,50064,3357],{},[9262,50066,50067,50070,50072],{},[9280,50068,50069],{},"Собор св. Павла",[9280,50071,50033],{},[9280,50073,1021],{},[415,50075,50076],{},"Нарисуйте таблицу динамического программирования для списка, прежде чем двигаться дальше.\nВот как должна выглядеть эта таблица:",[9256,50078,50079,50095],{},[9259,50080,50081],{},[9262,50082,50083,50085,50088,50090,50093],{},[9265,50084,853],{},[9265,50086,50087],{},"1\u002F2",[9265,50089,1192],{},[9265,50091,50092],{},"1 1\u002F2",[9265,50094,651],{},[9275,50096,50097,50110,50122,50135,50147],{},[9262,50098,50099,50102,50104,50106,50108],{},[9280,50100,50101],{},"Вестминистер",[9280,50103],{},[9280,50105],{},[9280,50107],{},[9280,50109],{},[9262,50111,50112,50114,50116,50118,50120],{},[9280,50113,50050],{},[9280,50115],{},[9280,50117],{},[9280,50119],{},[9280,50121],{},[9262,50123,50124,50127,50129,50131,50133],{},[9280,50125,50126],{},"Галерея",[9280,50128],{},[9280,50130],{},[9280,50132],{},[9280,50134],{},[9262,50136,50137,50139,50141,50143,50145],{},[9280,50138,50059],{},[9280,50140],{},[9280,50142],{},[9280,50144],{},[9280,50146],{},[9262,50148,50149,50152,50154,50156,50158],{},[9280,50150,50151],{},"Собор",[9280,50153],{},[9280,50155],{},[9280,50157],{},[9280,50159],{},[415,50161,50162],{},"Вы изобразили ее правильно? Теперь заполните. Какие достопримечательности вы выберете? Ответ: аббатство, галерея, собор.",[9256,50164,50165,50179],{},[9259,50166,50167],{},[9262,50168,50169,50171,50173,50175,50177],{},[9265,50170,853],{},[9265,50172,50087],{},[9265,50174,1192],{},[9265,50176,50092],{},[9265,50178,651],{},[9275,50180,50181,50193,50205,50217,50229],{},[9262,50182,50183,50185,50187,50189,50191],{},[9280,50184,50101],{},[9280,50186,781],{},[9280,50188,781],{},[9280,50190,781],{},[9280,50192,781],{},[9262,50194,50195,50197,50199,50201,50203],{},[9280,50196,50050],{},[9280,50198,781],{},[9280,50200,16889],{},[9280,50202,16889],{},[9280,50204,16889],{},[9262,50206,50207,50209,50211,50213,50215],{},[9280,50208,50126],{},[9280,50210,781],{},[9280,50212,16889],{},[9280,50214,36817],{},[9280,50216,36859],{},[9262,50218,50219,50221,50223,50225,50227],{},[9280,50220,50059],{},[9280,50222,781],{},[9280,50224,16889],{},[9280,50226,36817],{},[9280,50228,36859],{},[9262,50230,50231,50233,50235,50237,50239],{},[9280,50232,50151],{},[9280,50234,1021],{},[9280,50236,22026],{},[9280,50238,21518],{},[9280,50240,36846],{},[12129,50242,50244],{"id":50243},"взаимозависимые-элементы","Взаимозависимые элементы",[415,50246,50247],{},"Предположим, вы хотите посетить Париж и добавили в свой список пару элементов.",[9256,50249,50250,50260],{},[9259,50251,50252],{},[9262,50253,50254,50256,50258],{},[9265,50255,50017],{},[9265,50257,50020],{},[9265,50259,50023],{},[9275,50261,50262,50270,50278,50286,50294,50302,50312,50321],{},[9262,50263,50264,50266,50268],{},[9280,50265,50030],{},[9280,50267,50033],{},[9280,50269,781],{},[9262,50271,50272,50274,50276],{},[9280,50273,50040],{},[9280,50275,50043],{},[9280,50277,3357],{},[9262,50279,50280,50282,50284],{},[9280,50281,50050],{},[9280,50283,50033],{},[9280,50285,742],{},[9262,50287,50288,50290,50292],{},[9280,50289,50059],{},[9280,50291,50062],{},[9280,50293,3357],{},[9262,50295,50296,50298,50300],{},[9280,50297,50069],{},[9280,50299,50033],{},[9280,50301,1021],{},[9262,50303,50304,50307,50310],{},[9280,50305,50306],{},"Эйфелева башня",[9280,50308,50309],{},"1 1\u002F2 дня",[9280,50311,1021],{},[9262,50313,50314,50317,50319],{},[9280,50315,50316],{},"Лувр",[9280,50318,50309],{},[9280,50320,3357],{},[9262,50322,50323,50326,50328],{},[9280,50324,50325],{},"Нотр-дам",[9280,50327,50309],{},[9280,50329,781],{},[415,50331,50332],{},"На их посещение потребуется много времени, потому что сначала придется приехать из Лондона в Париж.\nПереезд отнимает полдня. Если вы захотите посмотреть все 3 достопримечательности, осмотр займет 4,5 дня.\nНебольшая поправка: не обязательно приезжать в Париж ради каждой достопримечательности.\nПосле того как вы там окажетесь, каждый последующий элемент займет всего один день.\nСледовательно, потребуется 1 день на каждую достопримечательность + 1 день на переезды = 3,5 дня, а не 4,5.",[415,50334,50335],{},"Если вы положите Эйфелеву башню в свой «рюкзак», то Лувр станет «дешевле» — он займет всего 1 день вместо 1,5.\nКак смоделировать это обстоятельство в динамическом программировании? Ответ: никак.\nДинамическое программирование — мощный метод, способный решать подзадачи и использовать полученные ответы для решения большой задачи.\nДинамическое программирование работает только в том случае, если каждая подзадача автономна, то есть не зависит от других подзадач.\nИз этого следует, что учесть поездки в Париж в алгоритме динамического программирования не удастся.",[12129,50337,50339],{"id":50338},"может-ли-оказаться-что-решение-требует-более-двух-подрюкзаков","Может ли оказаться, что решение требует более двух «подрюкзаков»?",[415,50341,50342],{},"Может оказаться, что в лучшем решении должны отбираться больше двух элементов.\nВ текущем варианте алгоритма объединяются не более двух «подрюкзаков» — больше двух их не бывает.\nОднако вполне возможно, что у этих «подрюкзаков» будут собственные «подрюкзаки».",[12129,50344,50346],{"id":50345},"возможно-ли-что-при-лучшем-решении-в-рюкзаке-остается-пустое-место","Возможно ли, что при лучшем решении в рюкзаке остается пустое место?",[415,50348,50349],{},"Да. Представьте, что вы можете также положить в рюкзак бриллиант.\nБриллиант очень крупный: он весит целых 3,5 кг и стоит 1 миллиард долларов — намного больше, чем любые другие предметы.\nБезусловно, нужно брать именно его!\nНо в рюкзаке остается еще пустое место на 0,5 кг, и в нем ничего не поместится.",[458,50351,33670],{"id":33669},[415,50353,50354],{},"Мы рассмотрели одну задачу динамического программирования. Какие выводы из нее можно сделать?",[697,50356,50357,50360],{},[700,50358,50359],{},"Динамическое программирование применяется для оптимизации какой-либо характеристики при заданных ограничениях. В задаче о рюкзаке требуется максимизировать стоимость отобранных предметов с ограничениями по емкости рюкзака.",[700,50361,50362],{},"Динамическое программирование работает только в ситуациях, в которых задача может быть разбита на автономные подзадачи, не зависящие друг от друга.",[415,50364,50365],{},"Построить решение на базе динамического программирования бывает непросто. Несколько общих рекомендаций:",[697,50367,50368,50371,50374],{},[700,50369,50370],{},"в каждом решении из области динамического программирования строится таблица;",[700,50372,50373],{},"значения ячеек таблицы обычно соответствуют оптимизируемой характеристике. Для задачи о рюкзаке значения представляли общую стоимость товаров;",[700,50375,50376],{},"каждая ячейка представляет подзадачу, поэтому вы должны подумать о том, как разбить задачу на подзадачи. Это поможет вам определиться с осями.",[458,50378,50380],{"id":50379},"ещё-пример-задачи","Ещё пример задачи",[415,50382,50383],{},"Допустим, вы открыли сайт dictionary.com. Пользователь вводит слово, а сайт возвращает определение.\nНо если пользователь ввел несуществующее слово, нужно предположить, какое слово имелось в виду.\nАлексей ищет определение «fish», но он случайно ввел «hish». Такого слова в словаре нет, но зато у вас есть список похожих слов.\nКакое слово он хотел ввести на самом деле: fish или например, vista?",[12129,50385,50387],{"id":50386},"построение-таблицы","Построение таблицы",[415,50389,50390],{},"Как должна выглядеть таблица для этой задачи? Вы должны ответить на следующие вопросы.",[697,50392,50393,50396,50399],{},[700,50394,50395],{},"Какие значения должны содержаться в ячейках?",[700,50397,50398],{},"Как разбить эту задачу на подзадачи?",[700,50400,50401],{},"Каков смысл осей таблицы?",[415,50403,50404],{},"В динамическом программировании вы пытаетесь максимизировать некоторую характеристику.\nВ данном случае ищется самая длинная подстрока, общая в двух словах.\nКакую общую подстроку содержат hish и fish? А как насчет hish и vista? Именно это требуется вычислить.\nКак говорилось ранее, значения в ячейках обычно представляют ту характеристику, которую вы пытаетесь оптимизировать.\nВероятно, в данном случае этой характеристикой будет число: длина самой длинной подстроки, общей для двух строк.\nКак разделить эту задачу на подзадачи? Например, можно заняться сравнением подстрок.\nВместо того чтобы сравнивать hish и fish, можно сначала сравнить his и fis.\nКаждая ячейка будет содержать длину самой длинной подстроки, общей для двух подстрок.\nТакое решение также подсказывает, что строками и столбцами таблицы, вероятно, будут два слова.\nА значит, таблица будет выглядеть примерно так:",[9256,50406,50407,50424],{},[9259,50408,50409],{},[9262,50410,50411,50413,50416,50419,50422],{},[9265,50412,853],{},[9265,50414,50415],{},"H",[9265,50417,50418],{},"I",[9265,50420,50421],{},"S",[9265,50423,50415],{},[9275,50425,50426,50439,50451,50463],{},[9262,50427,50428,50431,50433,50435,50437],{},[9280,50429,50430],{},"F",[9280,50432],{},[9280,50434],{},[9280,50436],{},[9280,50438],{},[9262,50440,50441,50443,50445,50447,50449],{},[9280,50442,50418],{},[9280,50444],{},[9280,50446],{},[9280,50448],{},[9280,50450],{},[9262,50452,50453,50455,50457,50459,50461],{},[9280,50454,50421],{},[9280,50456],{},[9280,50458],{},[9280,50460],{},[9280,50462],{},[9262,50464,50465,50467,50469,50471,50473],{},[9280,50466,50415],{},[9280,50468],{},[9280,50470],{},[9280,50472],{},[9280,50474],{},[12129,50476,50478],{"id":50477},"заполнение-таблицы","Заполнение таблицы",[415,50480,50481],{},"Сейчас вы уже достаточно хорошо представляете, как должна выглядеть таблица.\nПо какой формуле заполняются ячейки таблицы?\nМы можем немного упростить свою задачу, потому что уже знаем решение — у hish и fish имеется общая подстрока длины 3: ish.\nОднако этот факт ничего не говорит о том, какая формула должна использоваться.\nПо правде говоря, простого способа вычислить формулу для данного случая не существует.\nВам придется экспериментировать и искать работоспособное решение.\nИногда алгоритм предоставляет не точный рецепт, а основу, на которую вы наращиваете свою идею.\nПопробуйте предложить решение этой задачи самостоятельно. Часть таблицы выглядит так:",[9256,50483,50484,50498],{},[9259,50485,50486],{},[9262,50487,50488,50490,50492,50494,50496],{},[9265,50489,853],{},[9265,50491,50415],{},[9265,50493,50418],{},[9265,50495,50421],{},[9265,50497,50415],{},[9275,50499,50500,50512,50524,50536],{},[9262,50501,50502,50504,50506,50508,50510],{},[9280,50503,50430],{},[9280,50505,3302],{},[9280,50507,3302],{},[9280,50509],{},[9280,50511],{},[9262,50513,50514,50516,50518,50520,50522],{},[9280,50515,50418],{},[9280,50517],{},[9280,50519],{},[9280,50521],{},[9280,50523],{},[9262,50525,50526,50528,50530,50532,50534],{},[9280,50527,50421],{},[9280,50529],{},[9280,50531],{},[9280,50533,651],{},[9280,50535,3302],{},[9262,50537,50538,50540,50542,50544,50546],{},[9280,50539,50415],{},[9280,50541],{},[9280,50543],{},[9280,50545],{},[9280,50547,971],{},[415,50549,50550],{},"Попытайтесь вывести формулу самостоятельно, прежде чем продолжить читать.",[12129,50552,35413],{"id":35412},[415,50554,50555],{},"Итоговая версия таблицы выглядит так:",[9256,50557,50558,50572],{},[9259,50559,50560],{},[9262,50561,50562,50564,50566,50568,50570],{},[9265,50563,853],{},[9265,50565,50415],{},[9265,50567,50418],{},[9265,50569,50421],{},[9265,50571,50415],{},[9275,50573,50574,50586,50598,50610],{},[9262,50575,50576,50578,50580,50582,50584],{},[9280,50577,50430],{},[9280,50579,3302],{},[9280,50581,3302],{},[9280,50583,3302],{},[9280,50585,3302],{},[9262,50587,50588,50590,50592,50594,50596],{},[9280,50589,50418],{},[9280,50591,3302],{},[9280,50593,1192],{},[9280,50595,3302],{},[9280,50597,3302],{},[9262,50599,50600,50602,50604,50606,50608],{},[9280,50601,50421],{},[9280,50603,3302],{},[9280,50605,3302],{},[9280,50607,651],{},[9280,50609,3302],{},[9262,50611,50612,50614,50616,50618,50620],{},[9280,50613,50415],{},[9280,50615,1192],{},[9280,50617,3302],{},[9280,50619,3302],{},[9280,50621,971],{},[415,50623,50624],{},"Формула заполнения ячеек:",[1588,50626,50627,50630],{},[700,50628,50629],{},"Если буквы не совпадают, значение равно 0;",[700,50631,50632],{},"Если буквы совпадают, то значение равно значению ячейки наверху слева +1.",[415,50634,50635],{},"На Python эта формула реализуется так:",[422,50637,50639],{"className":424,"code":50638,"language":396,"meta":426,"style":426},"dp_table_hish = [\"h\", \"i\", \"s\", \"h\"]\ndp_table_fish = [\"f\", \"i\", \"s\", \"h\"]\ndp_table = [[0 for i in range(len(dp_table_hish))] for i in range(len(dp_table_fish))]\nfor i in range(0, len(dp_table_fish)):\n    for j in range(0, len(dp_table_hish)):\n        if dp_table_hish[j] == dp_table_fish[i]:  # Буквы совпадают\n            dp_table[i][j] = dp_table[i-1][j-1] + 1\n        else:  # Буквы не совпали\n            dp_table[i][j] = 0\nfor i in dp_table:\n    print(i)\n",[428,50640,50641,50669,50695,50736,50757,50778,50793,50820,50829,50837,50848],{"__ignoreMap":426},[431,50642,50643,50646,50648,50650,50653,50655,50658,50660,50663,50665,50667],{"class":433,"line":434},[431,50644,50645],{"class":441},"dp_table_hish ",[431,50647,1189],{"class":654},[431,50649,17401],{"class":441},[431,50651,50652],{"class":445},"\"h\"",[431,50654,4846],{"class":441},[431,50656,50657],{"class":445},"\"i\"",[431,50659,4846],{"class":441},[431,50661,50662],{"class":445},"\"s\"",[431,50664,4846],{"class":441},[431,50666,50652],{"class":445},[431,50668,3568],{"class":441},[431,50670,50671,50674,50676,50678,50681,50683,50685,50687,50689,50691,50693],{"class":433,"line":452},[431,50672,50673],{"class":441},"dp_table_fish ",[431,50675,1189],{"class":654},[431,50677,17401],{"class":441},[431,50679,50680],{"class":445},"\"f\"",[431,50682,4846],{"class":441},[431,50684,50657],{"class":445},[431,50686,4846],{"class":441},[431,50688,50662],{"class":445},[431,50690,4846],{"class":441},[431,50692,50652],{"class":445},[431,50694,3568],{"class":441},[431,50696,50697,50700,50702,50704,50706,50708,50710,50712,50714,50716,50718,50721,50723,50725,50727,50729,50731,50733],{"class":433,"line":578},[431,50698,50699],{"class":441},"dp_table ",[431,50701,1189],{"class":654},[431,50703,22296],{"class":441},[431,50705,3302],{"class":437},[431,50707,39428],{"class":654},[431,50709,12664],{"class":441},[431,50711,14421],{"class":654},[431,50713,14424],{"class":437},[431,50715,442],{"class":441},[431,50717,5205],{"class":437},[431,50719,50720],{"class":441},"(dp_table_hish))] ",[431,50722,14329],{"class":654},[431,50724,12664],{"class":441},[431,50726,14421],{"class":654},[431,50728,14424],{"class":437},[431,50730,442],{"class":441},[431,50732,5205],{"class":437},[431,50734,50735],{"class":441},"(dp_table_fish))]\n",[431,50737,50738,50740,50742,50744,50746,50748,50750,50752,50754],{"class":433,"line":584},[431,50739,14329],{"class":654},[431,50741,12664],{"class":441},[431,50743,14421],{"class":654},[431,50745,14424],{"class":437},[431,50747,442],{"class":441},[431,50749,3302],{"class":437},[431,50751,4846],{"class":441},[431,50753,5205],{"class":437},[431,50755,50756],{"class":441},"(dp_table_fish)):\n",[431,50758,50759,50761,50763,50765,50767,50769,50771,50773,50775],{"class":433,"line":1244},[431,50760,14745],{"class":654},[431,50762,30695],{"class":441},[431,50764,14421],{"class":654},[431,50766,14424],{"class":437},[431,50768,442],{"class":441},[431,50770,3302],{"class":437},[431,50772,4846],{"class":441},[431,50774,5205],{"class":437},[431,50776,50777],{"class":441},"(dp_table_hish)):\n",[431,50779,50780,50782,50785,50787,50790],{"class":433,"line":1985},[431,50781,11471],{"class":654},[431,50783,50784],{"class":441}," dp_table_hish[j] ",[431,50786,8409],{"class":654},[431,50788,50789],{"class":441}," dp_table_fish[i]:  ",[431,50791,50792],{"class":455},"# Буквы совпадают\n",[431,50794,50795,50798,50800,50803,50805,50807,50810,50812,50814,50816,50818],{"class":433,"line":2041},[431,50796,50797],{"class":441},"            dp_table[i][j] ",[431,50799,1189],{"class":654},[431,50801,50802],{"class":441}," dp_table[i",[431,50804,853],{"class":654},[431,50806,1192],{"class":437},[431,50808,50809],{"class":441},"][j",[431,50811,853],{"class":654},[431,50813,1192],{"class":437},[431,50815,4049],{"class":441},[431,50817,802],{"class":654},[431,50819,3916],{"class":437},[431,50821,50822,50824,50826],{"class":433,"line":4018},[431,50823,24030],{"class":654},[431,50825,11639],{"class":441},[431,50827,50828],{"class":455},"# Буквы не совпали\n",[431,50830,50831,50833,50835],{"class":433,"line":4030},[431,50832,50797],{"class":441},[431,50834,1189],{"class":654},[431,50836,3459],{"class":437},[431,50838,50839,50841,50843,50845],{"class":433,"line":4419},[431,50840,14329],{"class":654},[431,50842,12664],{"class":441},[431,50844,14421],{"class":654},[431,50846,50847],{"class":441}," dp_table:\n",[431,50849,50850,50852],{"class":433,"line":4436},[431,50851,6357],{"class":437},[431,50853,12677],{"class":441},[415,50855,50856],{},"Аналогично для строк hish и vista:",[422,50858,50860],{"className":424,"code":50859,"language":396,"meta":426,"style":426},"dp_table_hish = [\"h\", \"i\", \"s\", \"h\"]\ndp_table_vista = [\"v\", \"i\", \"s\", \"t\", \"a\"]\ndp_table = [[0 for i in range(len(dp_table_hish))] for i in range(len(dp_table_vista))]\nfor i in range(0, len(dp_table_vista)):\n    for j in range(0, len(dp_table_hish)):\n        if dp_table_hish[j] == dp_table_vista[i]:\n            dp_table[i][j] = dp_table[i-1][j-1] + 1\n        else:\n            dp_table[i][j] = 0\nfor i in dp_table:\n    print(i)\n",[428,50861,50862,50886,50917,50956,50977,50997,51008,51032,51038,51046,51056],{"__ignoreMap":426},[431,50863,50864,50866,50868,50870,50872,50874,50876,50878,50880,50882,50884],{"class":433,"line":434},[431,50865,50645],{"class":441},[431,50867,1189],{"class":654},[431,50869,17401],{"class":441},[431,50871,50652],{"class":445},[431,50873,4846],{"class":441},[431,50875,50657],{"class":445},[431,50877,4846],{"class":441},[431,50879,50662],{"class":445},[431,50881,4846],{"class":441},[431,50883,50652],{"class":445},[431,50885,3568],{"class":441},[431,50887,50888,50891,50893,50895,50898,50900,50902,50904,50906,50908,50911,50913,50915],{"class":433,"line":452},[431,50889,50890],{"class":441},"dp_table_vista ",[431,50892,1189],{"class":654},[431,50894,17401],{"class":441},[431,50896,50897],{"class":445},"\"v\"",[431,50899,4846],{"class":441},[431,50901,50657],{"class":445},[431,50903,4846],{"class":441},[431,50905,50662],{"class":445},[431,50907,4846],{"class":441},[431,50909,50910],{"class":445},"\"t\"",[431,50912,4846],{"class":441},[431,50914,26597],{"class":445},[431,50916,3568],{"class":441},[431,50918,50919,50921,50923,50925,50927,50929,50931,50933,50935,50937,50939,50941,50943,50945,50947,50949,50951,50953],{"class":433,"line":578},[431,50920,50699],{"class":441},[431,50922,1189],{"class":654},[431,50924,22296],{"class":441},[431,50926,3302],{"class":437},[431,50928,39428],{"class":654},[431,50930,12664],{"class":441},[431,50932,14421],{"class":654},[431,50934,14424],{"class":437},[431,50936,442],{"class":441},[431,50938,5205],{"class":437},[431,50940,50720],{"class":441},[431,50942,14329],{"class":654},[431,50944,12664],{"class":441},[431,50946,14421],{"class":654},[431,50948,14424],{"class":437},[431,50950,442],{"class":441},[431,50952,5205],{"class":437},[431,50954,50955],{"class":441},"(dp_table_vista))]\n",[431,50957,50958,50960,50962,50964,50966,50968,50970,50972,50974],{"class":433,"line":584},[431,50959,14329],{"class":654},[431,50961,12664],{"class":441},[431,50963,14421],{"class":654},[431,50965,14424],{"class":437},[431,50967,442],{"class":441},[431,50969,3302],{"class":437},[431,50971,4846],{"class":441},[431,50973,5205],{"class":437},[431,50975,50976],{"class":441},"(dp_table_vista)):\n",[431,50978,50979,50981,50983,50985,50987,50989,50991,50993,50995],{"class":433,"line":1244},[431,50980,14745],{"class":654},[431,50982,30695],{"class":441},[431,50984,14421],{"class":654},[431,50986,14424],{"class":437},[431,50988,442],{"class":441},[431,50990,3302],{"class":437},[431,50992,4846],{"class":441},[431,50994,5205],{"class":437},[431,50996,50777],{"class":441},[431,50998,50999,51001,51003,51005],{"class":433,"line":1985},[431,51000,11471],{"class":654},[431,51002,50784],{"class":441},[431,51004,8409],{"class":654},[431,51006,51007],{"class":441}," dp_table_vista[i]:\n",[431,51009,51010,51012,51014,51016,51018,51020,51022,51024,51026,51028,51030],{"class":433,"line":2041},[431,51011,50797],{"class":441},[431,51013,1189],{"class":654},[431,51015,50802],{"class":441},[431,51017,853],{"class":654},[431,51019,1192],{"class":437},[431,51021,50809],{"class":441},[431,51023,853],{"class":654},[431,51025,1192],{"class":437},[431,51027,4049],{"class":441},[431,51029,802],{"class":654},[431,51031,3916],{"class":437},[431,51033,51034,51036],{"class":433,"line":4018},[431,51035,24030],{"class":654},[431,51037,8102],{"class":441},[431,51039,51040,51042,51044],{"class":433,"line":4030},[431,51041,50797],{"class":441},[431,51043,1189],{"class":654},[431,51045,3459],{"class":437},[431,51047,51048,51050,51052,51054],{"class":433,"line":4419},[431,51049,14329],{"class":654},[431,51051,12664],{"class":441},[431,51053,14421],{"class":654},[431,51055,50847],{"class":441},[431,51057,51058,51060],{"class":433,"line":4436},[431,51059,6357],{"class":437},[431,51061,12677],{"class":441},[415,51063,51064],{},"Таблица:",[9256,51066,51067,51081],{},[9259,51068,51069],{},[9262,51070,51071,51073,51075,51077,51079],{},[9265,51072,853],{},[9265,51074,50415],{},[9265,51076,50418],{},[9265,51078,50421],{},[9265,51080,50415],{},[9275,51082,51083,51096,51108,51120,51133],{},[9262,51084,51085,51088,51090,51092,51094],{},[9280,51086,51087],{},"V",[9280,51089,3302],{},[9280,51091,3302],{},[9280,51093,3302],{},[9280,51095,3302],{},[9262,51097,51098,51100,51102,51104,51106],{},[9280,51099,50418],{},[9280,51101,3302],{},[9280,51103,1192],{},[9280,51105,3302],{},[9280,51107,3302],{},[9262,51109,51110,51112,51114,51116,51118],{},[9280,51111,50421],{},[9280,51113,3302],{},[9280,51115,3302],{},[9280,51117,651],{},[9280,51119,3302],{},[9262,51121,51122,51125,51127,51129,51131],{},[9280,51123,51124],{},"T",[9280,51126,3302],{},[9280,51128,3302],{},[9280,51130,3302],{},[9280,51132,3302],{},[9262,51134,51135,51137,51139,51141,51143],{},[9280,51136,9267],{},[9280,51138,3302],{},[9280,51140,3302],{},[9280,51142,3302],{},[9280,51144,3302],{},[415,51146,51147],{},"Важный момент: в этой задаче окончательное решение далеко не всегда находится в последней ячейке!\nВ задаче о рюкзаке последняя ячейка всегда содержит окончательное решение.\nНо в задаче поиска самой длинной общей подстроки решение определяется самым большим числом в таблице — и это может быть не последняя, а какая-то другая ячейка.\nВернемся к исходному вопросу: какая строка ближе к hish? У строк hish и fish есть общая подстрока длиной в три буквы.\nУ hish и vista есть общая подстрока из двух букв. Скорее всего, Алексей хотел ввести строку fish.",[458,51149,51151],{"id":51150},"самая-длинная-общая-подпоследовательность","Самая длинная общая подпоследовательность",[415,51153,51154],{},"Предположим, Алексей ввел строку fosh. Какое слово он имел в виду: fish или fort?\nСравним строки, по способу выше, длину общей подстроки.\nОкажется, что длина подстрок одинакова: две буквы! Но fosh при этом ближе к fish.\nМы сравниваем самую длинную общую подстроку, а на самом деле нужно сравнивать самую длинную общую подпоследовательность: количество букв в последовательности, общих для двух слов.\nКак вычислить самую длинную общую подпоследовательность?\nНиже приведена частично заполненная таблица для fish и fosh:",[9256,51156,51157,51172],{},[9259,51158,51159],{},[9262,51160,51161,51163,51165,51168,51170],{},[9265,51162,853],{},[9265,51164,50430],{},[9265,51166,51167],{},"O",[9265,51169,50421],{},[9265,51171,50415],{},[9275,51173,51174,51186,51198,51210],{},[9262,51175,51176,51178,51180,51182,51184],{},[9280,51177,50430],{},[9280,51179,1192],{},[9280,51181,1192],{},[9280,51183],{},[9280,51185],{},[9262,51187,51188,51190,51192,51194,51196],{},[9280,51189,50418],{},[9280,51191,1192],{},[9280,51193],{},[9280,51195],{},[9280,51197],{},[9262,51199,51200,51202,51204,51206,51208],{},[9280,51201,50421],{},[9280,51203],{},[9280,51205,1192],{},[9280,51207,651],{},[9280,51209,651],{},[9262,51211,51212,51214,51216,51218,51220],{},[9280,51213,50415],{},[9280,51215],{},[9280,51217],{},[9280,51219],{},[9280,51221],{},[415,51223,51224],{},"Сможете ли вы определить формулу для этой таблицы?\nСамая длинная общая подпоследовательность имеет много общего с самой длинной общей подстрокой, и их формулы тоже очень похожи.\nПопробуйте решить задачу самостоятельно.",[12129,51226,51228],{"id":51227},"решение-самая-длинная-общая-подпоследовательность","Решение: самая длинная общая подпоследовательность",[415,51230,51231],{},"Формула для заполнения каждой ячейки(для соседелй наверху слева):",[1588,51233,51234,51237],{},[700,51235,51236],{},"Если буквы не совпадают, выбрать большее значение;",[700,51238,51239],{},"Если буквы совпадают, значение равно значению ячейки наверху слева +1 (как и в случае с самой длинной общей подстрокой).",[415,51241,51242],{},"Окончательные версии таблиц:",[9256,51244,51245,51259],{},[9259,51246,51247],{},[9262,51248,51249,51251,51253,51255,51257],{},[9265,51250,853],{},[9265,51252,50430],{},[9265,51254,51167],{},[9265,51256,50421],{},[9265,51258,50415],{},[9275,51260,51261,51273,51285,51297],{},[9262,51262,51263,51265,51267,51269,51271],{},[9280,51264,50430],{},[9280,51266,1192],{},[9280,51268,1192],{},[9280,51270,1192],{},[9280,51272,1192],{},[9262,51274,51275,51277,51279,51281,51283],{},[9280,51276,50418],{},[9280,51278,1192],{},[9280,51280,1192],{},[9280,51282,1192],{},[9280,51284,1192],{},[9262,51286,51287,51289,51291,51293,51295],{},[9280,51288,50421],{},[9280,51290,1192],{},[9280,51292,1192],{},[9280,51294,651],{},[9280,51296,651],{},[9262,51298,51299,51301,51303,51305,51307],{},[9280,51300,50415],{},[9280,51302,1192],{},[9280,51304,1192],{},[9280,51306,651],{},[9280,51308,971],{},[9256,51310,51311,51325],{},[9259,51312,51313],{},[9262,51314,51315,51317,51319,51321,51323],{},[9265,51316,853],{},[9265,51318,50430],{},[9265,51320,51167],{},[9265,51322,50421],{},[9265,51324,50415],{},[9275,51326,51327,51339,51351,51364],{},[9262,51328,51329,51331,51333,51335,51337],{},[9280,51330,50430],{},[9280,51332,1192],{},[9280,51334,1192],{},[9280,51336,1192],{},[9280,51338,1192],{},[9262,51340,51341,51343,51345,51347,51349],{},[9280,51342,51167],{},[9280,51344,1192],{},[9280,51346,651],{},[9280,51348,651],{},[9280,51350,651],{},[9262,51352,51353,51356,51358,51360,51362],{},[9280,51354,51355],{},"R",[9280,51357,1192],{},[9280,51359,651],{},[9280,51361,651],{},[9280,51363,651],{},[9262,51365,51366,51368,51370,51372,51374],{},[9280,51367,51124],{},[9280,51369,1192],{},[9280,51371,651],{},[9280,51373,651],{},[9280,51375,651],{},[415,51377,51378],{},"На Python это решение выглядит так:",[422,51380,51382],{"className":424,"code":51381,"language":396,"meta":426,"style":426},"dp_table_fosh = [\"f\", \"o\", \"s\", \"h\"]\ndp_table_fish = [\"f\", \"i\", \"s\", \"h\"]\ndp_table = [[0 for i in range(len(dp_table_fosh))] for i in range(len(dp_table_fish))]\nfor i in range(0, len(dp_table_fish)):\n    for j in range(0, len(dp_table_fosh)):\n        if dp_table_fosh[j] == dp_table_fish[i]:  # Буквы совпадают\n            dp_table[i][j] = dp_table[i-1][j-1] + 1\n        else:  # Буквы не совпали\n            dp_table[i][j] = max(dp_table[i-1][j], dp_table[i][j-1])\nfor i in dp_table:\n    print(i)\n",[428,51383,51384,51410,51434,51473,51493,51514,51527,51551,51559,51583,51593],{"__ignoreMap":426},[431,51385,51386,51389,51391,51393,51395,51397,51400,51402,51404,51406,51408],{"class":433,"line":434},[431,51387,51388],{"class":441},"dp_table_fosh ",[431,51390,1189],{"class":654},[431,51392,17401],{"class":441},[431,51394,50680],{"class":445},[431,51396,4846],{"class":441},[431,51398,51399],{"class":445},"\"o\"",[431,51401,4846],{"class":441},[431,51403,50662],{"class":445},[431,51405,4846],{"class":441},[431,51407,50652],{"class":445},[431,51409,3568],{"class":441},[431,51411,51412,51414,51416,51418,51420,51422,51424,51426,51428,51430,51432],{"class":433,"line":452},[431,51413,50673],{"class":441},[431,51415,1189],{"class":654},[431,51417,17401],{"class":441},[431,51419,50680],{"class":445},[431,51421,4846],{"class":441},[431,51423,50657],{"class":445},[431,51425,4846],{"class":441},[431,51427,50662],{"class":445},[431,51429,4846],{"class":441},[431,51431,50652],{"class":445},[431,51433,3568],{"class":441},[431,51435,51436,51438,51440,51442,51444,51446,51448,51450,51452,51454,51456,51459,51461,51463,51465,51467,51469,51471],{"class":433,"line":578},[431,51437,50699],{"class":441},[431,51439,1189],{"class":654},[431,51441,22296],{"class":441},[431,51443,3302],{"class":437},[431,51445,39428],{"class":654},[431,51447,12664],{"class":441},[431,51449,14421],{"class":654},[431,51451,14424],{"class":437},[431,51453,442],{"class":441},[431,51455,5205],{"class":437},[431,51457,51458],{"class":441},"(dp_table_fosh))] ",[431,51460,14329],{"class":654},[431,51462,12664],{"class":441},[431,51464,14421],{"class":654},[431,51466,14424],{"class":437},[431,51468,442],{"class":441},[431,51470,5205],{"class":437},[431,51472,50735],{"class":441},[431,51474,51475,51477,51479,51481,51483,51485,51487,51489,51491],{"class":433,"line":584},[431,51476,14329],{"class":654},[431,51478,12664],{"class":441},[431,51480,14421],{"class":654},[431,51482,14424],{"class":437},[431,51484,442],{"class":441},[431,51486,3302],{"class":437},[431,51488,4846],{"class":441},[431,51490,5205],{"class":437},[431,51492,50756],{"class":441},[431,51494,51495,51497,51499,51501,51503,51505,51507,51509,51511],{"class":433,"line":1244},[431,51496,14745],{"class":654},[431,51498,30695],{"class":441},[431,51500,14421],{"class":654},[431,51502,14424],{"class":437},[431,51504,442],{"class":441},[431,51506,3302],{"class":437},[431,51508,4846],{"class":441},[431,51510,5205],{"class":437},[431,51512,51513],{"class":441},"(dp_table_fosh)):\n",[431,51515,51516,51518,51521,51523,51525],{"class":433,"line":1985},[431,51517,11471],{"class":654},[431,51519,51520],{"class":441}," dp_table_fosh[j] ",[431,51522,8409],{"class":654},[431,51524,50789],{"class":441},[431,51526,50792],{"class":455},[431,51528,51529,51531,51533,51535,51537,51539,51541,51543,51545,51547,51549],{"class":433,"line":2041},[431,51530,50797],{"class":441},[431,51532,1189],{"class":654},[431,51534,50802],{"class":441},[431,51536,853],{"class":654},[431,51538,1192],{"class":437},[431,51540,50809],{"class":441},[431,51542,853],{"class":654},[431,51544,1192],{"class":437},[431,51546,4049],{"class":441},[431,51548,802],{"class":654},[431,51550,3916],{"class":437},[431,51552,51553,51555,51557],{"class":433,"line":4018},[431,51554,24030],{"class":654},[431,51556,11639],{"class":441},[431,51558,50828],{"class":455},[431,51560,51561,51563,51565,51567,51570,51572,51574,51577,51579,51581],{"class":433,"line":4030},[431,51562,50797],{"class":441},[431,51564,1189],{"class":654},[431,51566,20572],{"class":437},[431,51568,51569],{"class":441},"(dp_table[i",[431,51571,853],{"class":654},[431,51573,1192],{"class":437},[431,51575,51576],{"class":441},"][j], dp_table[i][j",[431,51578,853],{"class":654},[431,51580,1192],{"class":437},[431,51582,3396],{"class":441},[431,51584,51585,51587,51589,51591],{"class":433,"line":4419},[431,51586,14329],{"class":654},[431,51588,12664],{"class":441},[431,51590,14421],{"class":654},[431,51592,50847],{"class":441},[431,51594,51595,51597],{"class":433,"line":4436},[431,51596,6357],{"class":437},[431,51598,12677],{"class":441},[422,51600,51602],{"className":424,"code":51601,"language":396,"meta":426,"style":426},"dp_table_fosh = [\"f\", \"o\", \"s\", \"h\"]\ndp_table_fort = [\"f\", \"o\", \"r\", \"t\"]\ndp_table = [[0 for i in range(len(dp_table_fosh))] for i in range(len(dp_table_fort))]\nfor i in range(0, len(dp_table_fort)):\n    for j in range(0, len(dp_table_fosh)):\n        if dp_table_fosh[j] == dp_table_fort[i]:  # Буквы совпадают\n            dp_table[i][j] = dp_table[i-1][j-1] + 1\n        else:  # Буквы не совпали\n            dp_table[i][j] = max(dp_table[i-1][j], dp_table[i][j-1])\nfor i in dp_table:\n    print(i)\n",[428,51603,51604,51628,51654,51693,51714,51734,51747,51771,51779,51801,51811],{"__ignoreMap":426},[431,51605,51606,51608,51610,51612,51614,51616,51618,51620,51622,51624,51626],{"class":433,"line":434},[431,51607,51388],{"class":441},[431,51609,1189],{"class":654},[431,51611,17401],{"class":441},[431,51613,50680],{"class":445},[431,51615,4846],{"class":441},[431,51617,51399],{"class":445},[431,51619,4846],{"class":441},[431,51621,50662],{"class":445},[431,51623,4846],{"class":441},[431,51625,50652],{"class":445},[431,51627,3568],{"class":441},[431,51629,51630,51633,51635,51637,51639,51641,51643,51645,51648,51650,51652],{"class":433,"line":452},[431,51631,51632],{"class":441},"dp_table_fort ",[431,51634,1189],{"class":654},[431,51636,17401],{"class":441},[431,51638,50680],{"class":445},[431,51640,4846],{"class":441},[431,51642,51399],{"class":445},[431,51644,4846],{"class":441},[431,51646,51647],{"class":445},"\"r\"",[431,51649,4846],{"class":441},[431,51651,50910],{"class":445},[431,51653,3568],{"class":441},[431,51655,51656,51658,51660,51662,51664,51666,51668,51670,51672,51674,51676,51678,51680,51682,51684,51686,51688,51690],{"class":433,"line":578},[431,51657,50699],{"class":441},[431,51659,1189],{"class":654},[431,51661,22296],{"class":441},[431,51663,3302],{"class":437},[431,51665,39428],{"class":654},[431,51667,12664],{"class":441},[431,51669,14421],{"class":654},[431,51671,14424],{"class":437},[431,51673,442],{"class":441},[431,51675,5205],{"class":437},[431,51677,51458],{"class":441},[431,51679,14329],{"class":654},[431,51681,12664],{"class":441},[431,51683,14421],{"class":654},[431,51685,14424],{"class":437},[431,51687,442],{"class":441},[431,51689,5205],{"class":437},[431,51691,51692],{"class":441},"(dp_table_fort))]\n",[431,51694,51695,51697,51699,51701,51703,51705,51707,51709,51711],{"class":433,"line":584},[431,51696,14329],{"class":654},[431,51698,12664],{"class":441},[431,51700,14421],{"class":654},[431,51702,14424],{"class":437},[431,51704,442],{"class":441},[431,51706,3302],{"class":437},[431,51708,4846],{"class":441},[431,51710,5205],{"class":437},[431,51712,51713],{"class":441},"(dp_table_fort)):\n",[431,51715,51716,51718,51720,51722,51724,51726,51728,51730,51732],{"class":433,"line":1244},[431,51717,14745],{"class":654},[431,51719,30695],{"class":441},[431,51721,14421],{"class":654},[431,51723,14424],{"class":437},[431,51725,442],{"class":441},[431,51727,3302],{"class":437},[431,51729,4846],{"class":441},[431,51731,5205],{"class":437},[431,51733,51513],{"class":441},[431,51735,51736,51738,51740,51742,51745],{"class":433,"line":1985},[431,51737,11471],{"class":654},[431,51739,51520],{"class":441},[431,51741,8409],{"class":654},[431,51743,51744],{"class":441}," dp_table_fort[i]:  ",[431,51746,50792],{"class":455},[431,51748,51749,51751,51753,51755,51757,51759,51761,51763,51765,51767,51769],{"class":433,"line":2041},[431,51750,50797],{"class":441},[431,51752,1189],{"class":654},[431,51754,50802],{"class":441},[431,51756,853],{"class":654},[431,51758,1192],{"class":437},[431,51760,50809],{"class":441},[431,51762,853],{"class":654},[431,51764,1192],{"class":437},[431,51766,4049],{"class":441},[431,51768,802],{"class":654},[431,51770,3916],{"class":437},[431,51772,51773,51775,51777],{"class":433,"line":4018},[431,51774,24030],{"class":654},[431,51776,11639],{"class":441},[431,51778,50828],{"class":455},[431,51780,51781,51783,51785,51787,51789,51791,51793,51795,51797,51799],{"class":433,"line":4030},[431,51782,50797],{"class":441},[431,51784,1189],{"class":654},[431,51786,20572],{"class":437},[431,51788,51569],{"class":441},[431,51790,853],{"class":654},[431,51792,1192],{"class":437},[431,51794,51576],{"class":441},[431,51796,853],{"class":654},[431,51798,1192],{"class":437},[431,51800,3396],{"class":441},[431,51802,51803,51805,51807,51809],{"class":433,"line":4419},[431,51804,14329],{"class":654},[431,51806,12664],{"class":441},[431,51808,14421],{"class":654},[431,51810,50847],{"class":441},[431,51812,51813,51815],{"class":433,"line":4436},[431,51814,6357],{"class":437},[431,51816,12677],{"class":441},[415,51818,51819],{},"Ещё примеры применения динамического программирования:",[697,51821,51822,51825,51828],{},[700,51823,51824],{},"Биологи используют самую длинную общую подпоследовательность для выявления сходства в цепях ДНК. По этой метрике можно судить о сходстве двух видов животных, двух заболеваний и т.д. Самая длинная общая подпоследовательность используется для поиска лекарства от рассеянного склероза.",[700,51826,51827],{},"Вы когда-нибудь пользовались ключом diff (например, в команде git diff)? Этот ключ выводит информацию о различиях между двумя файлами, а для этого он использует динамическое программирование.",[700,51829,51830],{},"Расстояние Левенштейна оценивает, насколько похожи две строки, а для его вычисления применяется динамическое программирование. Расстояние Левенштейна используется в самых разных областях, от проверки орфографии до выявления отправки пользователем данных, защищенных авторским правом.",[415,51832,51833],{},"Поздравляю — вы справились! Безусловно, это была одна из самых сложных тем в программировании.\nНиже посмотрите и выполните упражнения, чтобы закрепить свои знания по теме.",[8839,51835,51836],{},[415,51837,51838,51839],{},"В следующей статье речь идёт про ",[1205,51840,51841],{"href":303},"алгоритм k ближайших соседей.",[458,51843],{"id":426},[29130,51845],{":isList":51846,"title":30269},"[\"Динамическое программирование применяется при оптимизации некоторой характеристики;\",\"Динамическое программирование работает только в ситуациях, в которых задача может быть разбита на автономные подзадачи;\",\"В каждом решении из области динамического программирования строится таблица;\",\"Значения ячеек таблицы обычно соответствуют оптимизируемой характеристике;\",\"Каждая ячейка представляет подзадачу, поэтому вы должны подумать о том, как разбить задачу на подзадачи;\",\"Не существует единой формулы для вычисления решений методом динамического программирования.\"]",[458,51848],{"id":43864},[29386,51850],{":isAnswers":51851,":isList":51852,":startOl":1192,"isText":40925,"title":29391},"[\"Да. Вы сможете положить в рюкзак клавиатуру, смартфон и гитару общей стоимостью 4500.\",\"Возьмите воду, еду и камеру.\",\"Строки таблицы clues(столбцы) и blue(строки): | 0 0 0 0 0 | 0 1 0 0 0 | 0 0 2 0 0 | 0 0 0 3 0 |.\"]","[\"Предположим, к предметам из примера первой задачи(гитара, магнитофон, ноутбук) добавился еще один: клавиатура. Она весит 1 кг и стоит 1000₽. Стоит ли ее брать?\",\"Предположим, что вы собираетесь в турпоход. Емкость вашего рюкзака составляет 6 фунтов, и вы можете взять предметы из следующего списка. У каждого предмета имеется стоимость; чем она выше, тем важнее предмет: вода, 3 кг, 10; книга, 1 кг, 3; еда, 2 кг, 9; куртка, 2 кг, 5; камера, 1 кг, 6. Как выглядит оптимальный набор предметов для похода?\",\"Нарисуйте и заполните таблицу для вычисления самой длинной общей подстроки между строками blue и clues.\"]",[415,51854,34817,51855,1853,51857,1857],{},[800,51856,1852],{},[800,51858,1856],{},[1859,51860],{},[1862,51862,35276],{},[1862,51864,4066],{},{"title":426,"searchDepth":452,"depth":1244,"links":51866},[51867],{"id":48858,"depth":452,"text":298,"children":51868},[51869,51872,51877],{"id":47652,"depth":578,"text":47653,"children":51870},[51871],{"id":48925,"depth":584,"text":48926},{"id":48979,"depth":578,"text":298,"children":51873},[51874,51875,51876],{"id":49048,"depth":1244,"text":48895},{"id":49229,"depth":1244,"text":48889},{"id":49407,"depth":1244,"text":48892},{"id":49586,"depth":578,"text":49587,"children":51878},[51879,51880,51881,51882,51883,51884,51889,51890,51895,51898,51899],{"id":49593,"depth":1244,"text":49594},{"id":49867,"depth":1244,"text":49868},{"id":49874,"depth":1244,"text":49875},{"id":49881,"depth":1244,"text":49882},{"id":49997,"depth":1244,"text":49998},{"id":50004,"depth":584,"text":50005,"children":51885},[51886,51887,51888],{"id":50243,"depth":1244,"text":50244},{"id":50338,"depth":1244,"text":50339},{"id":50345,"depth":1244,"text":50346},{"id":33669,"depth":584,"text":33670},{"id":50379,"depth":584,"text":50380,"children":51891},[51892,51893,51894],{"id":50386,"depth":1244,"text":50387},{"id":50477,"depth":1244,"text":50478},{"id":35412,"depth":1244,"text":35413},{"id":51150,"depth":584,"text":51151,"children":51896},[51897],{"id":51227,"depth":1244,"text":51228},{"id":426,"depth":584,"text":426},{"id":43864,"depth":584,"text":426},"2026-05-07","Метод решения сложных задач, разбиваемых на подзадачи. Примеры задач.","images\u002Fblog\u002Fpython\u002Fst34\u002Fimg.png",{},{"title":298,"description":51901},"hCYr2rwTS2xj2rGWK1Tijj83qsYd4xWWy7ML9CNbE_Y",{"id":51907,"title":302,"author":51908,"body":51910,"date":52756,"description":52757,"extension":1887,"image":52758,"meta":52759,"minRead":52109,"navigation":393,"num":32032,"path":303,"seo":52760,"stem":304,"__hash__":52761},"python\u002Fblog\u002Fpython\u002Fst35.md",{"name":402,"avatar":51909},{"src":404,"alt":405},{"type":407,"value":51911,"toc":52720},[51912,51915,51918,51926,51929,51933,51936,51940,52277,52282,52285,52288,52290,52294,52298,52301,52349,52352,52360,52363,52374,52377,52380,52388,52392,52395,52403,52406,52408,52413,52417,52420,52424,52427,52430,52438,52441,52445,52448,52452,52455,52459,52462,52481,52484,52489,52492,52495,52499,52502,52506,52509,52520,52523,52529,52532,52536,52539,52543,52551,52555,52571,52591,52594,52598,52601,52605,52611,52615,52618,52626,52629,52633,52636,52640,52643,52646,52649,52660,52663,52667,52679,52693,52697,52706,52710,52713,52718],[410,51913,302],{"id":51914},"алгоритм-k-ближайших-соседей",[29130,51916],{":isList":51917,"title":43905},"[\"Научитесь строить системы классификации на базе алгоритма k ближайших соседей.\",\"Узнаете об извлечении признаков.\",\"Узнаете о регрессии: прогнозировании чисел (например, завтрашних биржевых котировок или успеха фильма у зрителей).\",\"Познакомитесь с типичными сценариями использования и ограничениями алгоритма k ближайших соседей.\"]",[8839,51919,51920],{},[415,51921,51922,51923,51925],{},"В предыдущей статье было про: ",[1205,51924,48812],{"href":299},".\nЗдесь далее текст пойдёт об алгоритме k ближайших соседей.",[415,51927,51928],{},"Алгоритм k ближайших соседей прост и полезен! Если вы пытаетесь выполнить классификацию чего-либо, сначала попробуйте применить алгоритм k ближайших соседей.\nРассмотрим реалистичный пример.",[458,51930,51932],{"id":51931},"построение-рекомендательной-системы","Построение рекомендательной системы",[415,51934,51935],{},"Представьте, что вы работаете с сайтом о кино и хотите построить систему, которая будет рекомендовать фильмы для ваших пользователей.\nПоложение пользователя определяется его вкусами, поэтому пользователи с похожими вкусами располагаются недалеко друг от друга.\nПредположим, вы хотите порекомендовать фильмы Алексею. Найдите 5 пользователей, ближайших к нему.\nДопустим, окажется, что у Ивана, Сергея, Анны, Ларисы и Анатолия похожие вкусы.\nЗначит, те фильмы, которые нравятся им, с большой вероятностью понравятся и Алексею!\nПосле того как у вас появится такая диаграмма, построить рекомендательную систему будет несложно.\nЕсли Анатолию нравится какой-нибудь фильм, порекомендуйте этот фильм Алексею.\nОднако в картине не хватает одного важного фрагмента.\nВы сравнивали вкусы двух пользователей. Но как определить, насколько они близки?",[12129,51937,51939],{"id":51938},"извлечение-признаков","Извлечение признаков",[415,51941,51942,51943,52112,52113,52276],{},"В примере с фруктами можно сравнивать фрукты на основании их размера и цвета кожуры.\nРазмер и цвет — признаки, по которым ведется сравнение.\nТеперь предположим, что у вас есть три фрукта.\nВы можете извлечь из них информацию, то есть провести извлечение признаков.\nДанные этих фруктов наносятся на график.\nПредположим, что из диаграммы хорошо видно, что фрукты A и B похожи.\nДавайте измерим степень их сходства.\nДля вычисления расстояния между двумя точками применяется формула Пифагора: ",[33809,51944,51946],{"className":51945,"jax":33813},[33812],[33815,51947,51952,51983],{"style":51948,"xmlns":33818,"width":51949,"height":51950,"role":15324,"focusable":33821,"viewBox":51951,"xmlnsXLink":33823},"vertical-align: -1.094ex;","24.857ex","4.208ex","0 -1376.5 10986.7 1860",[33825,51953,51954,51958,51960,51964,51967,51971,51973,51975,51979],{},[33828,51955],{"id":51956,"d":51957},"MJX-1-TEX-LO-221A","M1001 1150Q1017 1150 1020 1132Q1020 1127 741 244L460 -643Q453 -650 436 -650H424Q423 -647 423 -645T421 -640T419 -631T415 -617T408 -594T399 -560T385 -512T367 -448T343 -364T312 -259L203 119L138 41L111 67L212 188L264 248L472 -474L983 1140Q988 1150 1001 1150Z",[33828,51959],{"id":37691,"d":35018},[33828,51961],{"id":51962,"d":51963},"MJX-1-TEX-I-1D465","M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z",[33828,51965],{"id":51966,"d":33927},"MJX-1-TEX-N-31",[33828,51968],{"id":51969,"d":51970},"MJX-1-TEX-N-2212","M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z",[33828,51972],{"id":33842,"d":33843},[33828,51974],{"id":37708,"d":35031},[33828,51976],{"id":51977,"d":51978},"MJX-1-TEX-N-2B","M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z",[33828,51980],{"id":51981,"d":51982},"MJX-1-TEX-I-1D466","M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z",[33849,51984,51985],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,51986,51987],{"dataMmlNode":33855},[33849,51988,51990,52098,52105],{"dataMmlNode":51989},"msqrt",[33849,51991,51993,52043,52050],{"transform":51992},"translate(1020,0)",[33849,51994,51995,52038],{"dataMmlNode":34252},[33849,51996,51997,52001,52015,52022,52033],{"dataMmlNode":33955,"dataMjxTexclass":33956},[33849,51998,51999],{"dataMmlNode":34206},[33860,52000],{"dataC":35060,"xLinkHref":37732},[33849,52002,52003,52009],{"dataMmlNode":33873,"transform":37735},[33849,52004,52005],{"dataMmlNode":33858},[33860,52006],{"dataC":52007,"xLinkHref":52008},"1D465","#MJX-1-TEX-I-1D465",[33849,52010,52012],{"dataMmlNode":33883,"transform":52011},"translate(605,-150) scale(0.707)",[33860,52013],{"dataC":30856,"xLinkHref":52014},"#MJX-1-TEX-N-31",[33849,52016,52018],{"dataMmlNode":34206,"transform":52017},"translate(1619.8,0)",[33860,52019],{"dataC":52020,"xLinkHref":52021},"2212","#MJX-1-TEX-N-2212",[33849,52023,52025,52029],{"dataMmlNode":33873,"transform":52024},"translate(2620,0)",[33849,52026,52027],{"dataMmlNode":33858},[33860,52028],{"dataC":52007,"xLinkHref":52008},[33849,52030,52031],{"dataMmlNode":33883,"transform":52011},[33860,52032],{"dataC":33887,"xLinkHref":33888},[33849,52034,52036],{"dataMmlNode":34206,"transform":52035},"translate(3628.6,0)",[33860,52037],{"dataC":30851,"xLinkHref":37767},[33849,52039,52041],{"dataMmlNode":33883,"transform":52040},"translate(4050.6,477.1) scale(0.707)",[33860,52042],{"dataC":33887,"xLinkHref":33888},[33849,52044,52046],{"dataMmlNode":34206,"transform":52045},"translate(4676.3,0)",[33860,52047],{"dataC":52048,"xLinkHref":52049},"2B","#MJX-1-TEX-N-2B",[33849,52051,52053,52093],{"dataMmlNode":34252,"transform":52052},"translate(5676.5,0)",[33849,52054,52055,52059,52072,52077,52088],{"dataMmlNode":33955,"dataMjxTexclass":33956},[33849,52056,52057],{"dataMmlNode":34206},[33860,52058],{"dataC":35060,"xLinkHref":37732},[33849,52060,52061,52067],{"dataMmlNode":33873,"transform":37735},[33849,52062,52063],{"dataMmlNode":33858},[33860,52064],{"dataC":52065,"xLinkHref":52066},"1D466","#MJX-1-TEX-I-1D466",[33849,52068,52070],{"dataMmlNode":33883,"transform":52069},"translate(523,-150) scale(0.707)",[33860,52071],{"dataC":30856,"xLinkHref":52014},[33849,52073,52075],{"dataMmlNode":34206,"transform":52074},"translate(1537.8,0)",[33860,52076],{"dataC":52020,"xLinkHref":52021},[33849,52078,52080,52084],{"dataMmlNode":33873,"transform":52079},"translate(2538,0)",[33849,52081,52082],{"dataMmlNode":33858},[33860,52083],{"dataC":52065,"xLinkHref":52066},[33849,52085,52086],{"dataMmlNode":33883,"transform":52069},[33860,52087],{"dataC":33887,"xLinkHref":33888},[33849,52089,52091],{"dataMmlNode":34206,"transform":52090},"translate(3464.6,0)",[33860,52092],{"dataC":30851,"xLinkHref":37767},[33849,52094,52096],{"dataMmlNode":33883,"transform":52095},"translate(3886.6,477.1) scale(0.707)",[33860,52097],{"dataC":33887,"xLinkHref":33888},[33849,52099,52101],{"dataMmlNode":34206,"transform":52100},"translate(0,166.5)",[33860,52102],{"dataC":52103,"xLinkHref":52104},"221A","#MJX-1-TEX-LO-221A",[52106,52107],"rect",{"width":52108,"height":52109,"x":52110,"y":52111},9966.7,60,"1020","1256.5","\nФормула расстояния подтверждает то, что мы видим: между фруктами есть или отсутствует сходство.\nДопустим, вместо фруктов вы сравниваете пользователей. Пользователей нужно будет как-то нанести на график.\nСледовательно, каждого пользователя нужно будет преобразовать в координаты.\nКогда вы сможете нанести пользователей на график, вы также сможете измерить расстояние между ними.\nНачнем с преобразования пользователей в набор чисел.\nКогда пользователь регистрируется на сайте, предложите ему оценить несколько категорий фильмов: нравятся они лично ему или нет.\nТаким образом у вас появляется набор оценок для каждого пользователя!\nИ в итоге каждый пользователь представляется набором из чисел.\nВместо вычисления расстояния в двух измерениях вы теперь вычисляете расстояние в n измерениях(зависит от категорий жанров у фильмов).\nТем не менее формула расстояния остается неизменной:\n",[33809,52114,52116],{"className":52115,"jax":33813},[33812],[33815,52117,52120,52146],{"style":51948,"xmlns":33818,"width":52118,"height":51950,"role":15324,"focusable":33821,"viewBox":52119,"xmlnsXLink":33823},"29.127ex","0 -1376.5 12874.2 1860",[33825,52121,52122,52125,52127,52130,52132,52135,52137,52139,52142,52144],{},[33828,52123],{"id":52124,"d":51957},"MJX-2-TEX-LO-221A",[33828,52126],{"id":37895,"d":35018},[33828,52128],{"id":52129,"d":51963},"MJX-2-TEX-I-1D465",[33828,52131],{"id":33926,"d":33927},[33828,52133],{"id":52134,"d":51970},"MJX-2-TEX-N-2212",[33828,52136],{"id":48628,"d":33843},[33828,52138],{"id":37910,"d":35031},[33828,52140],{"id":52141,"d":51978},"MJX-2-TEX-N-2B",[33828,52143],{"id":37913,"d":34245},[33828,52145],{"id":40997,"d":33847},[33849,52147,52148],{"stroke":33851,"fill":33851,"stroke-width":3302,"transform":33852},[33849,52149,52150],{"dataMmlNode":33855},[33849,52151,52152,52268,52273],{"dataMmlNode":51989},[33849,52153,52154,52196,52202,52207,52212,52217,52222],{"transform":51992},[33849,52155,52156,52192],{"dataMmlNode":34252},[33849,52157,52158,52162,52173,52178,52188],{"dataMmlNode":33955,"dataMjxTexclass":33956},[33849,52159,52160],{"dataMmlNode":34206},[33860,52161],{"dataC":35060,"xLinkHref":37927},[33849,52163,52164,52169],{"dataMmlNode":33873,"transform":37735},[33849,52165,52166],{"dataMmlNode":33858},[33860,52167],{"dataC":52007,"xLinkHref":52168},"#MJX-2-TEX-I-1D465",[33849,52170,52171],{"dataMmlNode":33883,"transform":52011},[33860,52172],{"dataC":30856,"xLinkHref":33961},[33849,52174,52175],{"dataMmlNode":34206,"transform":52017},[33860,52176],{"dataC":52020,"xLinkHref":52177},"#MJX-2-TEX-N-2212",[33849,52179,52180,52184],{"dataMmlNode":33873,"transform":52024},[33849,52181,52182],{"dataMmlNode":33858},[33860,52183],{"dataC":52007,"xLinkHref":52168},[33849,52185,52186],{"dataMmlNode":33883,"transform":52011},[33860,52187],{"dataC":33887,"xLinkHref":48651},[33849,52189,52190],{"dataMmlNode":34206,"transform":52035},[33860,52191],{"dataC":30851,"xLinkHref":37967},[33849,52193,52194],{"dataMmlNode":33883,"transform":52040},[33860,52195],{"dataC":33887,"xLinkHref":48651},[33849,52197,52199],{"dataMmlNode":34206,"transform":52198},"translate(4454.1,0)",[33860,52200],{"dataC":52048,"xLinkHref":52201},"#MJX-2-TEX-N-2B",[33849,52203,52205],{"dataMmlNode":34206,"transform":52204},"translate(5232.1,0)",[33860,52206],{"dataC":34278,"xLinkHref":37973},[33849,52208,52210],{"dataMmlNode":34206,"transform":52209},"translate(5676.8,0)",[33860,52211],{"dataC":34278,"xLinkHref":37973},[33849,52213,52215],{"dataMmlNode":34206,"transform":52214},"translate(6121.4,0)",[33860,52216],{"dataC":34278,"xLinkHref":37973},[33849,52218,52220],{"dataMmlNode":34206,"transform":52219},"translate(6566.1,0)",[33860,52221],{"dataC":52048,"xLinkHref":52201},[33849,52223,52225,52263],{"dataMmlNode":34252,"transform":52224},"translate(7344.1,0)",[33849,52226,52227,52231,52242,52247,52258],{"dataMmlNode":33955,"dataMjxTexclass":33956},[33849,52228,52229],{"dataMmlNode":34206},[33860,52230],{"dataC":35060,"xLinkHref":37927},[33849,52232,52233,52237],{"dataMmlNode":33873,"transform":37735},[33849,52234,52235],{"dataMmlNode":33858},[33860,52236],{"dataC":33894,"xLinkHref":41025},[33849,52238,52240],{"dataMmlNode":33883,"transform":52239},"translate(633,-150) scale(0.707)",[33860,52241],{"dataC":30856,"xLinkHref":33961},[33849,52243,52245],{"dataMmlNode":34206,"transform":52244},"translate(1647.8,0)",[33860,52246],{"dataC":52020,"xLinkHref":52177},[33849,52248,52250,52254],{"dataMmlNode":33873,"transform":52249},"translate(2648,0)",[33849,52251,52252],{"dataMmlNode":33858},[33860,52253],{"dataC":33894,"xLinkHref":41025},[33849,52255,52256],{"dataMmlNode":33883,"transform":52239},[33860,52257],{"dataC":33887,"xLinkHref":48651},[33849,52259,52261],{"dataMmlNode":34206,"transform":52260},"translate(3684.6,0)",[33860,52262],{"dataC":30851,"xLinkHref":37967},[33849,52264,52266],{"dataMmlNode":33883,"transform":52265},"translate(4106.6,477.1) scale(0.707)",[33860,52267],{"dataC":33887,"xLinkHref":48651},[33849,52269,52270],{"dataMmlNode":34206,"transform":52100},[33860,52271],{"dataC":52103,"xLinkHref":52272},"#MJX-2-TEX-LO-221A",[52106,52274],{"width":52275,"height":52109,"x":52110,"y":52111},11854.2,"\nФормула расстояния универсальна: даже если вы используете набор из миллиона чисел, расстояние вычисляется по той же формуле.\nЕстественно спросить: какой смысл передает метрика расстояния с пятью числами?\nОна сообщает, насколько близки между собой эти наборы из пяти чисел.",[8839,52278,52279],{},[415,52280,52281],{},"Массивы чисел, такие как(2, 2) или (3, 4, 4, 1, 4) называются векторами.\nЕсли вам встретится статья о машинном обучении и вы увидите, что авторы говорят о векторах, знайте, что они имеют в виду подобный массив чисел.",[415,52283,52284],{},"Теперь порекомендовать фильм Алексею будет несложно: если Сергею понравился какой-то фильм, мы рекомендуем его Алексею, и наоборот.\nВы только что построили систему, рекомендующую фильмы.",[415,52286,52287],{},"Если вы являетесь пользователем приложения с фильмами, то оно постоянно напоминает вам:\n«Пожалуйста, оценивайте больше фильмов. Чем больше фильмов вы оцените, тем точнее будут наши рекомендации».\nТеперь вы знаете почему: чем больше фильмов вы оцениваете, тем точнее рекомендательная система определяет, с какими пользователями у вас общие вкусы.",[458,52289],{"id":426},[29386,52291],{":isAnswers":52292,":isList":52293,":startOl":1192,"isText":40925,"title":29391},"[\"Можно воспользоваться нормализацией: вы вычисляете среднюю оценку для каждого человека и используете ее для масштабирования оценок. Например, вы определили, что средняя оценка первого равна 3, а средняя оценка второго — 3,5. Соответственно оценки первого немного увеличиваются так, чтобы ее средняя оценка тоже была равна 3,5. После этого оценки можно сравнивать по единой шкале.\",\"При применении алгоритма k ближайших соседей можно увеличить вес оценок авторитетов. Предположим, у вас трое соседей: Антон, Олег и Сергей(авторитет). Они поставили фильму оценки 3, 4 и 5 соответственно. Вместо того чтобы вычислять среднее арифметическое их оценок (3 + 4 + 5 \u002F 3 = 4 звезды), вы просто повышаете вес оценки авторитета Сергея: 3 + 4 + 5 + 5 + 5 \u002F 5 = 4,4 звезды.\"]","[\"В примере с приложением просмотра фильмов сходство между двумя пользователями оценивалось по формуле расстояния. Но не все пользователи оценивают фильмы одинаково. Допустим, есть два пользователя, вкусы которых совпадают. Но первый ставит 5 баллов любому фильму, который ему понравился, а второй более разборчив и ставит пятерки только самым лучшим фильмам. Вроде бы вкусы одинаковые, но по метрике расстояния они не являются соседями. Как учесть различия в стратегиях выставления оценок?\",\"Предположим, рекомендательная система определяет группу «авторитетов». Скажем, Иван и Сергей относятся к числу авторитетов приложения просмотра фильмов, поэтому их оценки оказывают более сильное влияние, чем оценки рядовых пользователей. Как изменить систему рекомендаций, чтобы она учитывала повышенную ценность оценок авторитетов?\"]",[458,52295,52297],{"id":52296},"регрессия","Регрессия",[415,52299,52300],{},"А теперь предположим, что просто порекомендовать фильм недостаточно: вы хотите спрогнозировать, какую оценку Алексей поставит фильму.\nВозьмите 5 пользователей, находящихся вблизи от нее.\nВ числе «5» нет ничего особенного: с таким же успехом можно взять 2 ближайших пользователей, 10 или 10 000.\nПоэтому-то алгоритм и называется «алгоритмом k ближайших пользователей», а не «алгоритмом 5 ближайших пользователей»!\nДопустим, вы пытаетесь угадать оценку Алексея для фильма «». Как этот фильм оценили Иван, Сергей, Лариса, Ольга и Антон?",[9256,52302,52303,52312],{},[9259,52304,52305],{},[9262,52306,52307,52310],{},[9265,52308,52309],{},"Имя",[9265,52311,50023],{},[9275,52313,52314,52321,52328,52335,52342],{},[9262,52315,52316,52319],{},[9280,52317,52318],{},"Сергей",[9280,52320,762],{},[9262,52322,52323,52326],{},[9280,52324,52325],{},"Иван",[9280,52327,856],{},[9262,52329,52330,52333],{},[9280,52331,52332],{},"Лариса",[9280,52334,762],{},[9262,52336,52337,52340],{},[9280,52338,52339],{},"Ольга",[9280,52341,856],{},[9262,52343,52344,52347],{},[9280,52345,52346],{},"Антон",[9280,52348,971],{},[415,52350,52351],{},"Если вычислить среднее арифметическое их оценок, вы получите 4,2. Такой метод прогнозирования называется регрессией.\nУ алгоритма k ближайших соседей есть два основных применения — классификация и регрессия:",[697,52353,52354,52357],{},[700,52355,52356],{},"классификация = распределение по категориям;",[700,52358,52359],{},"регрессия = прогнозирование ответа (в числовом выражении).",[415,52361,52362],{},"Регрессия чрезвычайно полезна. Представьте, что вы открыли маленькую булочную и каждый день выпекаете свежий хлеб.\nВы пытаетесь предсказать, сколько буханок следует испечь на сегодня. Есть несколько признаков:",[697,52364,52365,52368,52371],{},[700,52366,52367],{},"погода по шкале от 1 до 5 (1 = плохая, 5 = отличная);",[700,52369,52370],{},"праздник или выходной (1, если сегодня праздник или выходной, 0 в противном случае);",[700,52372,52373],{},"проходят ли сегодня спортивные игры (1 = да, 0 = нет).",[415,52375,52376],{},"И вы знаете, сколько буханок хлеба было продано в прошлом при разных сочетаниях признаков.\nA(5,1,0) = 300 буханок; B(3,1,1) = 225; C(1,1,0) = 75; D(4,0,1) = 200; E(4,0,0) = 150; F(2,0,0) = 50.",[415,52378,52379],{},"Сегодня выходной и хорошая погода. Сколько буханок вы продадите на основании только что приведенных данных?\nИспользуем алгоритм k ближайших соседей для k = 4. Сначала определим четырех ближайших соседей для этой точки: (4,1,0) = ?.\nНиже перечислены расстояния. Точки A, B, D и E являются ближайшими: A - 1, B - 2, C - 9, D - 2, E - 1, F - 5.\nВычисляя среднее арифметическое продаж в эти дни, вы получаете ≈ 218.\nЗначит, именно столько буханок нужно выпекать на сегодня!",[8839,52381,52382],{},[415,52383,52384,52385],{},"Выше мы использовали формулу расстояния для вычисления степени сходства.\nНо является ли эта формула лучшей?\nНа практике также часто применяется метрика близости косинусов.\nМетрика близости косинусов не измеряет расстояния между двумя векторами.\nВместо этого она сравнивает углы двух векторов и в целом лучше подходит для подобных случаев.\n",[1355,52386,52387],{},"Тема метрики близости косинусов выходит за рамки этой статьи, вам стоит самостоятельно поискать информацию, если вы будете применять алгоритм k ближайших соседей!",[12129,52389,52391],{"id":52390},"выбор-признаков","Выбор признаков",[415,52393,52394],{},"Чтобы подобрать рекомендации, вы предлагаете пользователям ставить оценки категориям фильмов.\nА если бы вы вместо этого предлагали им ставить оценки картинкам?\nНаверное, вам удалось бы найти пользователей, которые ставили похожие оценки этим картинкам.\nОднако у вас получилась бы самая плохая рекомендательная система в мире, потому что эти «признаки» не имеют никакого отношения к их вкусам в области кино!\nИли представьте, что вы предлагаете пользователям оценить фильмы для формирования рекомендаций — но только «Игру престолов», «Игру\nпрестолов-2» и «Игру престолов-3». Эти оценки ничего не скажут вам о вкусах пользователей.\nКогда вы работаете с алгоритмом k ближайших соседей, очень важно правильно выбрать признаки для сравнения.\nПод правильным выбором признаков следует понимать:",[697,52396,52397,52400],{},[700,52398,52399],{},"признаки, напрямую связанные с фильмами, которые вы пытаетесь рекомендовать;",[700,52401,52402],{},"признаки, не содержащие смещения (например, если предлагать пользователям оценивать только комедии, вы не получите никакой информации об их отношении к боевикам).",[415,52404,52405],{},"Как вы думаете, оценки хорошо подходят для рекомендации фильмов? Возможно, я поставил «Золушке» более высокую оценку, чем «Охотникам за\nприведениями», но на самом деле я провел больше времени за просмотром «Охотников».\nКак улучшить рекомендательную систему?\nВозвращаясь к примеру с пекарней: сможете ли вы придумать два хороших и два плохих признака, которые можно было бы выбрать для прогнозирования объема выпечки?\nВозможно, нужно выпечь побольше хлеба после рекламы в газете. Или увеличить объем производства по понедельникам.\nВ том, что касается выбора хороших признаков, не существует единственно правильного ответа.\nТщательно продумайте все факторы, которые необходимо учесть при прогнозировании.",[458,52407],{"id":43864},[29386,52409],{":isAnswers":52410,":isList":52411,":startOl":971,"isText":40925,"title":52412},"[\"Слишком мало. Если ограничиться малым числом соседей, существует высокая вероятность того, что результаты будут искажены. Существует хорошее эмпирическое правило: для N пользователей следует рассматривать корень из N соседей.\"]","[\"У сервиса просмотра фильмов миллионы пользователей. В приведенном ранее примере рекомендательная система строилась для пяти ближайших соседей. Пять — это слишком мало? Слишком много?\"]","УПРАЖНЕНИЕ",[632,52414,52416],{"id":52415},"знакомство-с-машинным-обучением","Знакомство с машинным обучением",[415,52418,52419],{},"Мало того, что алгоритм k ближайших соседей полезен — он открывает путь в волшебный мир машинного обучения!\nСуть машинного обучения — сделать ваш компьютер более разумным.\nВы уже видели один пример машинного обучения: построение рекомендательной системы.\nРассмотрим другие примеры.",[458,52421,52423],{"id":52422},"ocr","OCR",[415,52425,52426],{},"Сокращение OCR означает «Optical Character Recognition», то есть «оптическое распознавание текста».\nИначе говоря, вы берете фотографию страницы текста, а компьютер автоматически преобразует изображение в текст.\nGoogle использует OCR для оцифровки книг. Как работает OCR?\nДля примера возьмем следующую цифру: 7.",[415,52428,52429],{},"Как автоматически определить, что это за цифра? Можно воспользоваться алгоритмом k ближайших соседей:",[1588,52431,52432,52435],{},[700,52433,52434],{},"Переберите изображения цифр и извлеките признаки.",[700,52436,52437],{},"Получив новое изображение, извлеките признаки и проверьте ближайших соседей.",[415,52439,52440],{},"По сути, это та же задача, что и задача классификации.\nВ общем случае алгоритмы OCR основаны на выделении линий, точек и кривых.\nЗатем при получении нового символа из него можно извлечь те же признаки.\nИзвлечение признаков в OCR происходит сложнее чем в задачах классификации.\nОднако важно понимать, что даже сложные технологии строятся на основе простых идей(таких, как алгоритм k ближайших соседей).\nТе же принципы могут использоваться для распознавания речи или лиц.\nКогда вы отправляете фотографию на Яндекс Диск, иногда сервису Яндекса хватает сообразительности для автоматической пометки людей на фото.\nДа это машинное обучение в действии!\nПервый шаг OCR, в ходе которого перебираются изображения цифр и происходит извлечение признаков, называется тренировкой.\nВ большинстве алгоритмов машинного обучения присутствует фаза тренировки: прежде чем компьютер сможет решить свою задачу, его необходимо натренировать.\nВ следующем примере рассмотрим создание спам-фильтров, и в нем тоже есть шаг тренировки.",[458,52442,52444],{"id":52443},"построение-спам-фильтра","Построение спам-фильтра",[415,52446,52447],{},"Спам-фильтры используют другой простой алгоритм, называемый наивным классификатором Байеса.\nСначала наивный классификатор Байеса тренируется на данных.\nПредположим, вы получили сообщение с темой «Получите свой миллион прямо сейчас!» Это спам?\nПредложение можно разбить на слова, а затем для каждого слова проверить вероятность присутствия этого слова в спам сообщении.\nНапример, в нашей очень простой модели слово «миллион» встречается только в спаме.\nНаивный классификатор Байеса вычисляет вероятность того, что сообщение с большой вероятностью является спамом.\nНа практике он применяется примерно для тех же целей, что и алгоритм k ближайших соседей.\nНапример, наивный классификатор Байеса может использоваться для классификации фруктов: есть большой и красный фрукт.\nКакова вероятность того, что он окажется грейпфрутом?\nЭто простой, но весьма эффективный алгоритм — из тех, что нравятся больше всего!",[458,52449,52451],{"id":52450},"прогнозы-на-биржевых-торгах","Прогнозы на биржевых торгах",[415,52453,52454],{},"Есть одна задача, в которой трудно добиться успеха машинным обучением: точно спрогнозировать курсы акций на бирже.\nКак выбрать хорошие признаки? Предположим, вы говорите, что если курс акций рос вчера, то он будет расти и сегодня.\nХороший это признак или нет? Или, предположим, вы утверждаете, что курс всегда снижается в апреле. Сработает или нет?\nНе существует гарантированного способа прогнозировать будущее на основании прошлых данных.\nПрогнозирование будущего — сложное дело, а при таком количестве переменных оно становится почти невозможным.",[632,52456,52458],{"id":52457},"тренировка-модели-машинного-обучения","Тренировка модели машинного обучения",[415,52460,52461],{},"Тренировка нейросети МО состоит из нескольких основных этапов:",[1588,52463,52464,52467,52470,52472,52475,52478],{},[700,52465,52466],{},"Сбор данных",[700,52468,52469],{},"Анализ и очистка данных",[700,52471,51939],{},[700,52473,52474],{},"Процесс обучения на тестовых данных",[700,52476,52477],{},"Проверка на новых данных",[700,52479,52480],{},"Проверка(валидация) и корректировка модели",[415,52482,52483],{},"Рассмотрим последовательность действий по тренировке модели МО. Все начинается со сбора данных.\nВ примере с рекомендательной системой по фильмам данными были оценки пользователей.\nЗатем необходимо провести очистку данных, то есть удаление неподходящих данных.\nНапример, какой-нибудь пользователь не пожелал оценивать фильмы, поэтому расставил случайные оценки и перешел к следующему экрану.\nТакие данные необходимо удалить из набора. После этого требуется извлечь из данных признаки.\nПолучив признаки, можно переходить к тренировке модели.\nВыберите модель — например, k ближайших соседей, создайте структуру нейронов и саму нейросеть — и проведите ее тренировку на 90% данных.\nОставьте около 10% данных для проверки модели.\nПосле того как модель пройдет обучение, протестируйте ее, предложив ей составить прогноз.\nЧтобы оценить качество прогноза, используйте зарезервированные или новые данные.\nНапример, вы хотите проверить рекомендательную модель фильмов.\nМожно спросить, понравились ли некоторому пользователю некоторые фильмы и сериалы. Модель выдаёт прогнозы.\nА мы при этом заранее знаем, какие фильмы нравятся пользователю, — эта информация содержится в 10 % данных, которые мы зарезервировали.\nЭти зарезервированные данные сравниваются с прогнозами модели.\nПосле сравнения результатов модели и реальных данных, можно сделать вывод о том, что модель выдала хороший результат или не очень.\nХороший результат у модели получается тогда, когда числа достаточно близки к реальным оценкам пользователя.\nЭтот шаг тестирования модели называется проверкой (или валидацией) модели.\nПосле проверки можно вернуться к модели и скорректировать ее.\nПредставьте, что вы построили модель k ближайших соседей, в которой k = 5.\nМожно опробовать ее с k = 7, чтобы посмотреть, не даст ли она лучший результат. Это называется корректировкой(или подкруткой) параметров.\nПосле того как вы завершите тренировку и оценку модели, ваша модель будет готова к работе.\nТак выглядит процедура построения модели МО в общем случае.",[415,52485,52486],{},[1355,52487,52488],{},"Надеюсь, вы хотя бы в общих чертах поняли, что можно сделать с помощью алгоритма k ближайших соседей и машинного обучения!\nМашинное обучение — интересная область, и при желании в нее можно зайти достаточно глубоко.",[458,52490],{"id":52491},"_2",[29130,52493],{":isList":52494,"title":30269},"[\"Алгоритм k ближайших соседей применяется для классификации и регрессии. В нем используется проверка k ближайших соседей.;\",\"Классификация = распределение по категориям;\",\"Регрессия = прогнозирование результата (например, в виде числа);\",\"«Извлечением признаков» называется преобразование элемента (например, пользователя) в список чисел, которые могут использоваться для сравнения;\",\"Качественный выбор признаков — важная часть успешного алгоритма k ближайших соседей;\"]",[632,52496,52498],{"id":52497},"ещё-об-алгоритмах","Ещё об алгоритмах",[415,52500,52501],{},"Ниже краткий обзор 10 алгоритмов, которые не рассматривались. Вы узнаете, для чего нужны эти алгоритмы.\nА также рекомендация книг, которые стоит читать дальше в зависимости от того, какие темы вам интересны.",[458,52503,52505],{"id":52504},"линейная-регрессия","Линейная регрессия",[415,52507,52508],{},"Представьте, что вы хотите продать свой дом.\nЕго площадь составляет 300 квадратных метров.\nВы изучаете описания домов, недавно проданных по соседству:",[1588,52510,52511,52514,52517],{},[700,52512,52513],{},"100 кв. метров 10 миллионов рублей;",[700,52515,52516],{},"200 кв. метров 13 миллионов рублей;",[700,52518,52519],{},"400 кв. метров 25 миллионов рублей.",[415,52521,52522],{},"Какую цену вы бы назначили за свой дом, исходя из этой информации?\nНиже представлено одно из возможных решений. Сначала вы наносите все точки на график.\nЗатем соединяете их прямой линией(отсюда и название линейная).",[415,52524,52525],{},[15324,52526],{"alt":52527,"src":52528},"Пример линейной регрессии","\u002Fimages\u002Fblog\u002Fpython\u002Fst35\u002Fimg_1.png",[415,52530,52531],{},"Теперь вы видите, где на этой линии находится точка 300 квадратных метров.\nСоответствующую ей цену можно сделать начальной ценой.\nТак работает линейная регрессия. Она выстраивает линию из заданной группы точек, а затем использует эту линию для вычисления прогнозов.\nЛинейная регрессия уже давно применяется в статистике, а теперь и в машинном обучении, поскольку это метод, с которого легко начинать.\nЛинейная регрессия полезна, если значения непрерывны. Если вам нужно сделать прогноз, проще всего использовать именно линейную регрессию.",[458,52533,52535],{"id":52534},"инвертированные-индексы","Инвертированные индексы",[415,52537,52538],{},"Перед вами сильно упрощенное объяснение того, как работает поисковая система.\nДопустим, имеются три веб-страницы с простым содержимым.\nСтроиться хеш-таблица для этого содержимого или проще python словарь.\nКлючами словаря являются слова, а значения указывают, на каких страницах встречается каждое слово.\nТеперь предположим, что пользователь ищет слово \"python\".\nДалее проверяется, на каких страницах это слово встречается.\nПусть, слово встречается на страницах А и B. Выведем эти страницы в результатах поиска.\nИли предположим, что пользователь ищет слово \"питон\".\nИ система проверяет, что это слово встречается на страницах A и C.\nНесложно, верно?\nХеш-таблица — это очень полезная структура данных: хеш-таблица, связывающая слова с местами, в которых эти слова встречаются.\nТакая структура данных, называемая инвертированным индексом, часто используется для построения поисковых систем.\nЕсли вас интересует область поиска, эта тема станет хорошей отправной точкой для дальнейшего изучения.",[458,52540,52542],{"id":52541},"преобразование-фурье","Преобразование Фурье",[415,52544,52545,52546],{},"Преобразование Фурье — действительно выдающийся алгоритм: великолепный, элегантный и имеющий миллион практических применений.\nПример для преобразования Фурье: если у вас есть коктейль, преобразование Фурье сообщает, из каких ингредиентов он состоит.\nИли для заданной песни преобразование разделяет ее на отдельные частоты.\nОказывается, эта простая идея находит множество практических применений.\nНапример, если песню можно разложить на частоты, вы можете усилить тот диапазон, который вас интересует, — скажем, усилить низкие частоты и приглушить высокие.\nПреобразование Фурье прекрасно подходит для обработки сигналов.\nТакже оно может применяться для сжатия музыки: сначала звуковой файл разбивается на составляющие.\nПреобразование Фурье сообщает, какой вклад вносит каждая составляющая в музыку, что позволяет исключить несущественные составляющие.\nСобственно, именно так работает музыкальный формат MP3!\nМузыка — не единственный вид цифровых сигналов.\nГрафический формат JPG также использует сжатие и работает по тому же принципу.\nКроме того, преобразование Фурье применяется для прогнозирования землетрясений и анализа ДНК.\nС его помощью можно построить приложение, которое находит песни по отрывкам.\nПреобразование Фурье очень часто применяется на практике!\n",[1205,52547,52550],{"href":52548,"rel":52549},"https:\u002F\u002Fproglib.io\u002Fp\u002Fpreobrazovaniya-fure-dlya-obrabotki-signalov-s-pomoshchyu-python-2020-11-03",[1209],"Подробнее о преобразовании Фурье в работе со звуком есть отличная статья.",[458,52552,52554],{"id":52553},"параллельные-алгоритмы","Параллельные алгоритмы",[415,52556,52557,52558,52560,52561,52563,52564,52566,52567,52570],{},"Следующие три темы связаны с масштабируемостью и обработкой больших объемов данных.\nКогда-то компьютеры становились все быстрее и быстрее.\nЕсли вы хотели, чтобы ваш алгоритм работал быстрее, можно было подождать несколько месяцев и запустить программу на более мощном компьютере.\nНо сейчас этот период подошел к концу.\nСовременные компьютеры и ноутбуки оснащаются многоядерными процессорами. Чтобы алгоритм заработал быстрее,\nнеобходимо преобразовать его в форму, подходящую для параллельного выполнения сразу на всех ядрах!\nРассмотрим простой пример. Лучшее время выполнения для алгоритма сортировки равно приблизительно ",[1355,52559,45854],{},".\nИзвестно, что массив невозможно отсортировать за время ",[1355,52562,34864],{},", если только не воспользоваться параллельным алгоритмом!\nСуществует параллельная версия быстрой сортировки, которая сортирует массив за время ",[1355,52565,34864],{},".\nПараллельный алгоритм трудно разработать.\nИ так же трудно убедиться в том, что он работает правильно, и понять, какой прирост скорости он обеспечивает.\nОдно можно заявить твердо: ",[1355,52568,52569],{},"выигрыш по времени нелинеен",".\nСледовательно, если процессор вашего компьютера имеет два ядра вместо одного, из этого не следует, что ваш алгоритм по волшебству заработает вдвое быстрее.\nЭто объясняется несколькими причинами:",[697,52572,52573,52579,52585],{},[700,52574,52575,52578],{},[1355,52576,52577],{},"Затраты ресурсов на управление параллелизмом"," — допустим, нужно отсортировать массив из 1000 элементов. Как разбить эту задачу для выполнения на двух ядрах? Выделить каждому ядру 500 элементов, а затем объединить два отсортированных массива в один большой отсортированный массив? Слияние двух массивов требует времени.",[700,52580,52581,52584],{},[1355,52582,52583],{},"Закон Амдала"," — представьте, что вы пишете картину. Это занимает очень много времени, допустим около 30 часов. В идеале вам хотелось бы уложиться в 10 часов. Вы решаете оптимизировать процесс. Для этого разбиваете его на два шага: (1) эскиз и (2) рисование красками. Исходный эскиз не обязательно рисовать вручную — конечно, с помощью трейсинга(обводки) это делается быстрее. Но при следующей попытке на картину уходит 29 часов и 5 минут! Что произошло? Раньше эскиз занимал 1 час. Вы сократили его до 5 минут, что стало значительным улучшением. Тем не менее бóльшая часть времени приходится на рисование красками, так что оптимизация оказалась незначительной. Это проявление так называемого закона Амдала. Он гласит, что при оптимизации одной части системы выигрыш в производительности ограничивается тем, какую долю времени занимает эта часть. В данном случае время создания эскиза сокращается до 1\u002F12 исходного значения. При этом экономятся 55 минут. Если бы нам удалось сократить время рисования красками в той же степени, это сэкономило бы 2090 минут!Ускоряя алгоритм за счет параллелизации, подумайте, какую его часть следует распараллелить — создание эскиза или рисование?",[700,52586,52587,52590],{},[1355,52588,52589],{},"Распределение нагрузки"," — допустим, необходимо выполнить 10 задач, и вы назначаете каждому ядру 5 задач. Однако ядру A достаются все простые задачи, поэтому оно выполняет свою работу за 10 секунд, тогда как ядро B справится со сложными задачами только за минуту. Это означает, что ядро A целых 50 секунд простаивает, пока ядро B выполняет всю работу! Как организовать равномерное распределение работы, чтобы оба ядра трудились с одинаковой интенсивностью?",[415,52592,52593],{},"Если вас интересует теоретическая сторона производительности и масштабируемости, возможно, параллельные алгоритмы — именно то, что вам нужно!",[12129,52595,52597],{"id":52596},"mapreduce","MapReduce",[415,52599,52600],{},"Существует разновидность параллельных алгоритмов, которая в последнее время активно набирает популярность: распределенные алгоритмы.\nКонечно, параллельный алгоритм удобно запускать на компьютере, если для его выполнения требуется от двух до четырех ядер. Но если нужны сотни?\nТогда алгоритм записывают так, чтобы он мог выполняться на множестве машин.\nКомпания Google популяризировала распределенный алгоритм, который называется MapReduce, но его функции известны уже давно.\nДля чего нужны распределенные алгоритмы?\nПредположим, имеется таблица с миллиардами или триллионами записей и к ней нужно сделать сложный запрос SQL.\nВ MySQL это сделать не удастся, потому что MySQL начнет «тормозить» уже после нескольких миллиардов записей.\nИспользуйте MapReduce!\nИли, предположим, вам нужно обработать длинный список задач.\nОбработка каждой задачи занимает 10 секунд, а всего в списке 1 миллион задач.\nЕсли выполнять эту работу на одном компьютере, она займет несколько месяцев!\nЕсли бы ее можно было выполнить на 100 машинах, работа завершилась бы за несколько дней.\nРаспределенные алгоритмы хорошо работают в ситуациях, когда нужно выполнить большой объем работы за максимально короткое время.",[458,52602,52604],{"id":52603},"фильтры-блума-и-hyperloglog","Фильтры Блума и HyperLogLog",[415,52606,52607,52608,52610],{},"Представьте себя на месте сайта Reddit. Когда пользователь публикует ссылку, нужно проверить, публиковалась ли эта ссылка ранее.\nИстории, которые еще не публиковались, считаются более ценными.\nИли представьте себя на месте поискового бота Google.\nОбрабатывать веб-страницу нужно только в том случае, если она еще не обрабатывалась ранее.\nИтак, нужно проверить, обрабатывалась ли страница ранее.\nИли представьте себя на месте bit.ly — сервиса сокращения URL.\nПользователи не должны перенаправляться на вредоносные сайты.\nУ вас имеется набор URL-адресов, которые считаются вредоносными.\nТеперь нужно выяснить, не направляется ли пользователь на URL-адрес из этого набора.\nВо всех этих примерах возникает одна проблема.\nИмеется очень большой набор данных.\nПоявляется новый объект, и вы хотите узнать, содержится ли он в существующем наборе.\nЭта задача быстро решается при помощи хеша.\nНапример, представьте, что Google создает большой хеш, ключами которого являются все обработанные страницы.\nКак узнать, обрабатывался ли сайт ashtana.ru? Нужно заглянуть в хеш.\nУ ashtana.ru имеется свой ключ в хеше, а значит, адрес уже обрабатывался.\nСреднее время обращения к элементам в хеш-таблице составляет ",[1355,52609,40883],{},".\nТаким образом, вы узнали о том, что страница ashtana.ru уже проиндексирована за постоянное время. Неплохо!\nВот только этот хеш получится просто огромным.\nGoogle индексирует триллион веб-страниц. Если хеш содержит все URL-адреса, индексируемые Google, он займет слишком много места.\nУ Reddit и bit.ly возникает аналогичная проблема. Сталкиваясь с такими объемами данных, приходится действовать более изобретательно!",[12129,52612,52614],{"id":52613},"фильтры-блума","Фильтры Блума",[415,52616,52617],{},"Для решения проблемы можно воспользоваться вероятностными структурами данных, которые называются фильтрами Блума.\nОни дают ответ, который может оказаться ложным, но с большой вероятностью является правильным.\nВместо того чтобы обращаться к хешу, вы спрашиваете у фильтра Блума, обрабатывался ли этот URL-адрес ранее.\nХеш-таблица даст точный ответ. Фильтр Блума дает ответ, правильный с высокой вероятностью:",[697,52619,52620,52623],{},[700,52621,52622],{},"возможны ложноположительные срабатывания. Фильтр скажет: «Этот сайт уже обрабатывался», хотя этого не было;",[700,52624,52625],{},"ложноотрицательные срабатывания исключены. Если фильтр утверждает, что сайт не обрабатывался, вы можете быть в этом уверены.",[415,52627,52628],{},"Фильтры Блума хороши тем, что занимают очень мало места.\nХеш-таблице пришлось бы хранить все URL-адреса, обрабатываемые Google, а фильтру Блума это не нужно.\nФильтр Блума очень удобен тогда, когда нет необходимости в точном ответе(как во всех приведенных примерах).",[12129,52630,52632],{"id":52631},"hyperloglog","HyperLogLog",[415,52634,52635],{},"Примерно так же действует другой алгоритм, который называется HyperLogLog.\nПредположим, Google хочет подсчитать количество уникальных поисков, выполненных пользователями.\nИли Amazon хочет подсчитать количество уникальных предметов, просмотренных пользователями за сегодняшний день.\nДля получения ответов на эти вопросы потребуется очень много места!\nТак, в примере с Google придется вести журнал всех уникальных вариантов поиска.\nКогда пользователь что-то ищет, вы сначала проверяете, присутствует ли условие в журнале, и если нет, добавляете его.\nДаже для одного дня этот журнал получится гигантским.\nHyperLogLog аппроксимирует количество уникальных элементов в множестве.\nКак и фильтры Блума, он не дает точного ответа, но выдает достаточно близкий результат с использованием малой части памяти, которую обычно занимает такая задача.\nЕсли вы используете большие объемы данных и вас устраивают приближенные ответы — воспользуйтесь вероятностными алгоритмами!",[458,52637,52639],{"id":52638},"https-и-обмен-ключами-диффи-хеллмана","HTTPS и обмен ключами Диффи — Хеллмана",[415,52641,52642],{},"HTTPS — опора современного интернета.\nЭтот протокол обеспечивает безопасные онлайн-транзакции, от ввода пароля до оплаты покупок.\nРабота HTTPS основана на шифровании сообщений между клиентом и сервером.\nКак же работает шифрование? Функции передаются сообщение и секретный ключ.\nЗатем функция генерирует зашифрованное сообщение.\nЧтобы расшифровать его, передайте зашифрованное сообщение и тот же ключ функции, и вы получите исходное сообщение.\nКогда вы отправляете данные серверу, ваш браузер зашифровывает сообщение, после чего сервер расшифровывает его.\nДа, кроме одного: как проверить, что браузер и сервер используют один и тот же ключ?\nПомните, что для работы HTTPS обе стороны должны иметь одинаковые ключи.\nНо как задать ключ, чтобы никто его не видел? Если отправить ключ серверу, злоумышленник сможет перехватить этот ключ.\nКак задать ключ, чтобы только браузер и сервер знали его? Задача кажется неразрешимой, но это не так!\nДля ее решения существует очень умный алгоритм, называемый обменом ключей Диффи — Хеллмана.",[415,52644,52645],{},"Ниже описано, как работает алгоритм Диффи — Хеллмана.\nНа шаге 1 мы генерируем собственные ключи. Я — клиент, и я генерирую ключ для себя. Сервис также генерирует ключ.\nЭти ключи разные. Мы не знаем ключи друг друга, они закрытые. В реальности ключи представляют собой байты.\nНа шаге 2 генерируется общий шаблон. Это открытый шаблон. Он виден обеим сторонам и всем остальным. Нам неважно, кто его видит.\nНа шаге 3 этот шаблон совмещается с закрытыми ключами.\nВ результате мы получаем открытые ключи. Раз они открытые, нас не интересует, кто их видит.\nСервер видит мой открытый ключ, а я вижу его открытый ключ.\nНаконец, на шаге 4 я получаю открытый ключ сервера и совмещаю его со своим закрытым ключом.\nСервис делает то же самое с моим открытым ключом.\nТеперь у нас одинаковые ключи! У каждого из нас есть ключ, объединяющий три шаблона.\nНам удалось задать ключ, не отправляя ключи друг другу.\nЗаданный ключ называется общим секретом; так работает обмен ключами Диффи — Хеллмана.",[415,52647,52648],{},"HTTPS — интересная и важная часть нашей повседневной жизни. Вот немного терминологии, связанной с HTTPS:",[697,52650,52651,52654,52657],{},[700,52652,52653],{},"TLS — протокол безопасности транспортного уровня (Transport Layer Security). TLS используется для установления безопасного соединения.",[700,52655,52656],{},"SSL — прежнее название TLS, но люди часто не различают их. Если вы слышите, как кто-то упоминает SSL, то, скорее всего, речь идет о TLS. В этом протоколе часто находят дефекты безопасности, поэтому его постоянно приходится обновлять. Протокол TLS впервые появился в 1999 году. Все версии протокола SSL, выпущенные до TLS, небезопасны.",[700,52658,52659],{},"Шифрование с симметричным ключом — в нашем примере выше обе стороны используют одинаковые ключи. Но существует и асимметричное шифрование с открытым ключом, когда обе стороны используют разные ключи. Я говорю о шифровании с симметричным ключом, потому что оно используется HTTPS.",[415,52661,52662],{},"HTTPS использует измененную версию обмена ключей Диффи — Хеллмана, называемую эфемерным обменом ключей Диффи — Хеллмана.\nОна работает так же, как было показано, кроме того, что закрытые ключи генерируются заново для каждого соединения.\nЭто означает, что даже если злоумышленнику станет известен один из закрытых ключей, он сможет расшифровать сообщения только одного соединения.\nКриптография — интересная и глубокая тема, в которую можно сильно погрузиться.",[458,52664,52666],{"id":52665},"локально-чувствительное-хеширование","Локально-чувствительное хеширование",[415,52668,52669,52670,52673,52674,52676,52677,3562],{},"Многие хеш-функции имеют одну важную особенность: они являются локально-нечувствительными.\nПредположим, имеется строка, для которой генерируется хеш-код с помощью алгоритма SHA-256: dog → cd6357.\nЕсли изменить в строке всего один символ, а потом сгенерировать хеш заново, строка полностью изменяется!\nИ это хорошо, потому что сравнение хешей не позволит атакующему определить, насколько он близок к взлому пароля.\nИногда требуется обратный результат: локально-чувствительная функция хеширования.\nЗдесь на помощь приходит алгоритм ",[1355,52671,52672],{},"Simhash",".\nПри незначительном изменении строки ",[1355,52675,52672],{}," генерирует хеш-код, который почти не отличается от исходного.\nЭто позволяет сравнивать хеш-коды и определять, насколько похожи две строки, — весьма полезная возможность!\nПримеры использования ",[1355,52678,52672],{},[697,52680,52681,52684,52687,52690],{},[700,52682,52683],{},"Google использует Simhash для выявления дубликатов в процессе индексирования.",[700,52685,52686],{},"Система проверки на антиплагиат может использовать Simhash для обнаружения плагиата(копирования рефератов из интернета).",[700,52688,52689],{},"Книжное издательство позволяет пользователям загружать документы или книги, чтобы они стали доступны для других пользователей. Но издатель не хочет, чтобы пользователи размещали информацию, защищенную авторским правом! С помощью Simhash сайт может обнаружить, что отправленная информация похожа на изданную книгу, и при обнаружении сходства автоматически запретить ее размещение.",[700,52691,52692],{},"Simhash используется для выявления сходства между фрагментами текста.",[458,52694,52696],{"id":52695},"минимальные-кучи-и-приоритетные-очереди","Минимальные кучи и приоритетные очереди",[415,52698,52699,52700,52702,52703,52705],{},"Минимальная куча — структура данных, построенная на базе деревьев. В таких кучах хранятся числа.\nМинимальные кучи позволяют быстро найти наименьший элемент кучи, потому что наименьшее значение всегда находится в корне.\nЭто самое важное свойство минимальной кучи, и наименьший элемент находится за время ",[1355,52701,40883],{},".\nИли же за время ",[1355,52704,45591],{}," его можно удалить из кучи, заменив новым минимумом.\nБлагодаря кучам проводить сортировку очень легко — просто продолжая запрашивать минимальное значение.\nИ сохранять значения по порядку. В конце куча будет пустой, а у вас появится отсортированный список чисел!\nТакой алгоритм называется пирамидальной сортировкой, или сортировкой кучей.\nМаксимальные кучи (невозрастающие пирамиды) очень похожи на минимальные, но у них в корне хранится наибольшее значение.\nКучи отлично подходят для реализации приоритетных очередей.\nВспомните, что очереди относятся к категории FIFO (First In, First Out — «первым пришел, первым вышел»).\nС другой стороны, стек относится к структуре данных LIFO(Last In, First Out — «последним пришел, первым вышел»).\nПриоритетная очередь похожа на обычную очередь, не считая того, что при запросе элемента приоритетная очередь выдает элемент с наибольшим приоритетом.\nПриоритетная очередь отлично подходит для реализации списка задач.\nСначала вы сохраняете в списке задачи, а затем запрашиваете задачу для работы; приоритетная очередь выдает задачу с наибольшим приоритетом.\nПриоритетные очереди также используются для реализации эффективной версии алгоритма Дейкстры.",[458,52707,52709],{"id":52708},"линейное-программирование","Линейное программирование",[415,52711,52712],{},"Линейное программирование — одна из самых интересных областей, которые мне известны.\nЛинейное программирование используется для максимизации некоторой характеристики при заданных ограничениях.\nПредположим, ваша компания выпускает два продукта: рубашки и сумки.\nНа рубашку требуется 1 метр ткани и 5 пуговиц. На изготовление сумки необходимо 2 метра ткани и 2 пуговицы.\nУ вас есть 11 метров ткани и 20 пуговиц.\nРубашка приносит прибыль 200 рублей, а сумка — 300.\nСколько рубашек и сумок следует изготовить для получения максимальной прибыли?\nЗдесь мы пытаемся максимизировать прибыль, а ограничения определяют количество имеющихся материалов.\nДругой пример: вы политик, пытающийся получить максимальное количество голосов.\nПредположим, что исследования показали, что на каждый голос жителя Белгорода требуется примерно 1 час работы (маркетинг, исследования и т.д.), а на каждый голос жителя Курска — 1,5 часа.\nВам нужны голоса как минимум 500 жителей Белгорода и как минимум 300 жителей Курска.\nВ вашем распоряжении 50 дней. Кроме того, затраты на жителя Белгорода составляют 200 рублей, а на жителя Курска — 100.\nВаш бюджет составляет 1500000 рублей. Какое максимальное количество голосов вы сможете получить от жителей двух городов?\nНа этот раз вы стремитесь к максимуму голосов при ограничениях по времени и деньгам.\nВозможно, вы подумаете: «Есть много задач решающие вопросы оптимизации. Как они связаны с линейным программированием?»\nВсе алгоритмы, работающие с графами, могут быть реализованы средствами линейного программирования.\nЛинейное программирование — намного более общая область, а задачи с графами составляют ее подмножество.\nВ линейном программировании используется симплекс-метод. Этот алгоритм достаточно сложен, поэтому я не привожу его.\nЕсли вы заинтересуетесь различными задачами оптимизации, поищите информацию о линейном программировании!",[8839,52714,52715],{},[415,52716,52717],{},"Надеюсь, этот краткий обзор показал, как много всего ещё можно узнать.\nЯ считаю, что лучший способ узнать что-то — найти тему, которая вас интересует, и постоянно изучать её!",[1862,52719,35276],{},{"title":426,"searchDepth":452,"depth":1244,"links":52721},[52722],{"id":51914,"depth":452,"text":302,"children":52723},[52724,52727,52728,52731,52732,52737,52740],{"id":51931,"depth":584,"text":51932,"children":52725},[52726],{"id":51938,"depth":1244,"text":51939},{"id":426,"depth":584,"text":426},{"id":52296,"depth":584,"text":52297,"children":52729},[52730],{"id":52390,"depth":1244,"text":52391},{"id":43864,"depth":584,"text":426},{"id":52415,"depth":578,"text":52416,"children":52733},[52734,52735,52736],{"id":52422,"depth":584,"text":52423},{"id":52443,"depth":584,"text":52444},{"id":52450,"depth":584,"text":52451},{"id":52457,"depth":578,"text":52458,"children":52738},[52739],{"id":52491,"depth":584,"text":426},{"id":52497,"depth":578,"text":52498,"children":52741},[52742,52743,52744,52745,52748,52752,52753,52754,52755],{"id":52504,"depth":584,"text":52505},{"id":52534,"depth":584,"text":52535},{"id":52541,"depth":584,"text":52542},{"id":52553,"depth":584,"text":52554,"children":52746},[52747],{"id":52596,"depth":1244,"text":52597},{"id":52603,"depth":584,"text":52604,"children":52749},[52750,52751],{"id":52613,"depth":1244,"text":52614},{"id":52631,"depth":1244,"text":52632},{"id":52638,"depth":584,"text":52639},{"id":52665,"depth":584,"text":52666},{"id":52695,"depth":584,"text":52696},{"id":52708,"depth":584,"text":52709},"2026-05-21","Сценарии использования и ограничениями алгоритма k ближайших соседей. Рекомендации по темам, которые стоит изучать дальше.","images\u002Fblog\u002Fpython\u002Fst35\u002Fimg.png",{},{"title":302,"description":52757},"FhJq5mHoGPEC5l6d1i2F38YSrmw8a8KJZ5G6PJVok1w",1780737499964]