[{"data":1,"prerenderedAt":22870},["ShallowReactive",2],{"navigation_docs":3,"-python-modules-packages-venv":3379,"-python-modules-packages-venv-surround":22865},[4,1707,1912,2366,2547,2649,2856,2978,3028,3085,3119,3245,3322,3375],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"Робота з файлами: C-стиль (stdio.h)","\u002Fcpp\u002Fc-style-files","02.cpp\u002F47.c-style-files",{"title":1905,"path":1906,"stem":1907},"Робота з файлами: C++-стиль (fstream)","\u002Fcpp\u002Fcpp-style-files","02.cpp\u002F48.cpp-style-files",{"title":1909,"path":1910,"stem":1911},"План навчання: Курс C++ — Продовження (Статті 29–60+)","\u002Fcpp\u002Fcurriculum-plan","02.cpp\u002Fcurriculum-plan",{"title":1913,"icon":1914,"path":1915,"stem":1916,"children":1917,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[1918,1944,1998,2020,2324,2362],{"title":1919,"icon":1920,"path":1921,"stem":1922,"children":1923,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[1924,1928,1932,1936,1940],{"title":1925,"path":1926,"stem":1927},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":1929,"path":1930,"stem":1931},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":1933,"path":1934,"stem":1935},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":1937,"path":1938,"stem":1939},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":1941,"path":1942,"stem":1943},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":1945,"icon":1946,"path":1947,"stem":1948,"children":1949,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[1950,1954,1958,1962,1966,1970,1974,1978,1982,1986,1990,1994],{"title":1951,"path":1952,"stem":1953},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":1955,"path":1956,"stem":1957},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":1959,"path":1960,"stem":1961},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":1963,"path":1964,"stem":1965},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":1967,"path":1968,"stem":1969},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":1971,"path":1972,"stem":1973},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":1975,"path":1976,"stem":1977},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":1979,"path":1980,"stem":1981},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":1983,"path":1984,"stem":1985},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":1987,"path":1988,"stem":1989},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":1991,"path":1992,"stem":1993},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":1995,"path":1996,"stem":1997},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":1999,"icon":2000,"path":2001,"stem":2002,"children":2003,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[2004,2008,2012,2016],{"title":2005,"path":2006,"stem":2007},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2009,"path":2010,"stem":2011},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2013,"path":2014,"stem":2015},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2017,"path":2018,"stem":2019},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2021,"icon":2022,"path":2023,"stem":2024,"children":2025},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2026,2027,2031,2035,2039,2043,2106,2141,2293],{"title":2021,"path":2023,"stem":2024},{"title":2028,"path":2029,"stem":2030},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2032,"path":2033,"stem":2034},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2036,"path":2037,"stem":2038},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2040,"path":2041,"stem":2042},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2044,"icon":132,"path":2045,"stem":2046,"children":2047},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2048,2050,2054,2058,2062,2066,2070,2074,2078,2082,2086,2090,2094,2098,2102],{"title":2049,"path":2045,"stem":2046},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2051,"path":2052,"stem":2053},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2055,"path":2056,"stem":2057},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2059,"path":2060,"stem":2061},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2063,"path":2064,"stem":2065},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2067,"path":2068,"stem":2069},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2071,"path":2072,"stem":2073},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2075,"path":2076,"stem":2077},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2079,"path":2080,"stem":2081},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2083,"path":2084,"stem":2085},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2087,"path":2088,"stem":2089},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2091,"path":2092,"stem":2093},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2095,"path":2096,"stem":2097},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2099,"path":2100,"stem":2101},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2103,"path":2104,"stem":2105},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2107,"icon":2022,"path":2108,"stem":2109,"children":2110},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2111,2113,2117,2121,2125,2129,2133,2137],{"title":2112,"path":2108,"stem":2109},"React Router: Навігаційна система сучасного вебу",{"title":2114,"path":2115,"stem":2116},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2118,"path":2119,"stem":2120},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2122,"path":2123,"stem":2124},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2126,"path":2127,"stem":2128},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2130,"path":2131,"stem":2132},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2134,"path":2135,"stem":2136},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2138,"path":2139,"stem":2140},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2142,"icon":132,"path":2143,"stem":2144,"children":2145},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2146,2148,2164,2193,2202,2223,2239,2268],{"title":2147,"path":2143,"stem":2144},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2149,"stem":2150,"children":2151,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2152,2156,2160],{"title":2153,"path":2154,"stem":2155},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2157,"path":2158,"stem":2159},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2161,"path":2162,"stem":2163},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2165,"icon":132,"path":2166,"stem":2167,"children":2168,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2169,2173,2177,2181,2185,2189],{"title":2170,"path":2171,"stem":2172},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2174,"path":2175,"stem":2176},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2178,"path":2179,"stem":2180},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2182,"path":2183,"stem":2184},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2186,"path":2187,"stem":2188},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2190,"path":2191,"stem":2192},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2194,"icon":132,"path":2195,"stem":2196,"children":2197,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2198],{"title":2199,"path":2200,"stem":2201},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2203,"icon":132,"path":2204,"stem":2205,"children":2206,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2207,2211,2215,2219],{"title":2208,"path":2209,"stem":2210},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2212,"path":2213,"stem":2214},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2216,"path":2217,"stem":2218},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2220,"path":2221,"stem":2222},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2224,"icon":92,"path":2225,"stem":2226,"children":2227,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2228,2232,2236],{"title":2229,"path":2230,"stem":2231},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2233,"path":2234,"stem":2235},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2083,"path":2237,"stem":2238},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2240,"icon":132,"path":2241,"stem":2242,"children":2243,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2244,2248,2252,2256,2260,2264],{"title":2245,"path":2246,"stem":2247},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2249,"path":2250,"stem":2251},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2253,"path":2254,"stem":2255},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2257,"path":2258,"stem":2259},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2261,"path":2262,"stem":2263},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2265,"path":2266,"stem":2267},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2269,"icon":132,"path":2270,"stem":2271,"children":2272,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2273,2277,2281,2285,2289],{"title":2274,"path":2275,"stem":2276},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2278,"path":2279,"stem":2280},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2282,"path":2283,"stem":2284},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2286,"path":2287,"stem":2288},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2290,"path":2291,"stem":2292},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2294,"icon":132,"path":2295,"stem":2296,"children":2297},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2298,2300,2304,2308,2312,2316,2320],{"title":2299,"path":2295,"stem":2296},"UI Бібліотеки в React",{"title":2301,"path":2302,"stem":2303},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2305,"path":2306,"stem":2307},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2309,"path":2310,"stem":2311},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2313,"path":2314,"stem":2315},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2317,"path":2318,"stem":2319},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2321,"path":2322,"stem":2323},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2325,"icon":2326,"path":2327,"stem":2328,"children":2329,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2330,2334,2338,2342,2346,2350,2354,2358],{"title":2331,"path":2332,"stem":2333},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2335,"path":2336,"stem":2337},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2339,"path":2340,"stem":2341},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2343,"path":2344,"stem":2345},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2347,"path":2348,"stem":2349},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2351,"path":2352,"stem":2353},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2355,"path":2356,"stem":2357},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2359,"path":2360,"stem":2361},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2363,"path":2364,"stem":2365},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2367,"icon":2368,"path":2369,"stem":2370,"children":2371,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2372,2375,2378,2382,2386,2390,2394],{"title":162,"path":2373,"stem":2374},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2376,"stem":2377},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2379,"path":2380,"stem":2381},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2383,"path":2384,"stem":2385},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2387,"path":2388,"stem":2389},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2391,"path":2392,"stem":2393},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2395,"path":2396,"stem":2397,"children":2398,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2399,2403,2407,2411,2415,2419,2423,2427,2431,2435,2439,2443,2447,2451,2455,2459,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511,2515,2519,2523,2527,2531,2535,2539,2543],{"title":2400,"path":2401,"stem":2402},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2404,"path":2405,"stem":2406},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2408,"path":2409,"stem":2410},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2412,"path":2413,"stem":2414},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2416,"path":2417,"stem":2418},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2420,"path":2421,"stem":2422},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2424,"path":2425,"stem":2426},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2428,"path":2429,"stem":2430},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2432,"path":2433,"stem":2434},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2436,"path":2437,"stem":2438},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2440,"path":2441,"stem":2442},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2444,"path":2445,"stem":2446},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2448,"path":2449,"stem":2450},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2452,"path":2453,"stem":2454},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2456,"path":2457,"stem":2458},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2460,"path":2461,"stem":2462},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2464,"path":2465,"stem":2466},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2468,"path":2469,"stem":2470},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2472,"path":2473,"stem":2474},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2476,"path":2477,"stem":2478},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2480,"path":2481,"stem":2482},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2484,"path":2485,"stem":2486},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2488,"path":2489,"stem":2490},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2492,"path":2493,"stem":2494},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2496,"path":2497,"stem":2498},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2500,"path":2501,"stem":2502},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2504,"path":2505,"stem":2506},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2508,"path":2509,"stem":2510},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2512,"path":2513,"stem":2514},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2516,"path":2517,"stem":2518},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2520,"path":2521,"stem":2522},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2524,"path":2525,"stem":2526},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2528,"path":2529,"stem":2530},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2532,"path":2533,"stem":2534},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2536,"path":2537,"stem":2538},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2540,"path":2541,"stem":2542},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2544,"path":2545,"stem":2546},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2548,"icon":2549,"path":2550,"stem":2551,"children":2552,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2553,2557,2560,2564,2568,2572,2576,2580,2584,2588,2592,2596,2600,2604,2608,2645],{"title":2554,"path":2555,"stem":2556},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2558,"stem":2559},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2561,"path":2562,"stem":2563},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2565,"path":2566,"stem":2567},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2569,"path":2570,"stem":2571},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2573,"path":2574,"stem":2575},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2577,"path":2578,"stem":2579},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2581,"path":2582,"stem":2583},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2585,"path":2586,"stem":2587},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2589,"path":2590,"stem":2591},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2593,"path":2594,"stem":2595},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2597,"path":2598,"stem":2599},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2601,"path":2602,"stem":2603},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2605,"path":2606,"stem":2607},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2609,"icon":92,"path":2610,"stem":2611,"children":2612,"page":59},"FastAPI","\u002Fpython\u002Ffastapi","05.python\u002Ffastapi",[2613,2617,2621,2625,2629,2633,2637,2641],{"title":2614,"path":2615,"stem":2616},"Глибокий Typing та Pydantic v2 — від анотацій до валідації","\u002Fpython\u002Ffastapi\u002Ftyping-pydantic","05.python\u002Ffastapi\u002F15.typing-pydantic",{"title":2618,"path":2619,"stem":2620},"WSGI, ASGI та Python Web-екосистема","\u002Fpython\u002Ffastapi\u002Fwsgi-asgi-ecosystem","05.python\u002Ffastapi\u002F16.wsgi-asgi-ecosystem",{"title":2622,"path":2623,"stem":2624},"FastAPI: Перший додаток, Uvicorn та OpenAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-intro","05.python\u002Ffastapi\u002F17.fastapi-intro",{"title":2626,"path":2627,"stem":2628},"Маршрутизація, параметри запитів та APIRouter","\u002Fpython\u002Ffastapi\u002Ffastapi-routing-params","05.python\u002Ffastapi\u002F18.fastapi-routing-params",{"title":2630,"path":2631,"stem":2632},"Pydantic v2 у FastAPI — схеми, валідація та серіалізація","\u002Fpython\u002Ffastapi\u002Ffastapi-pydantic-schemas","05.python\u002Ffastapi\u002F19.fastapi-pydantic-schemas",{"title":2634,"path":2635,"stem":2636},"Dependency Injection — серце архітектури FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-dependency-injection","05.python\u002Ffastapi\u002F20.fastapi-dependency-injection",{"title":2638,"path":2639,"stem":2640},"Обробка помилок, Middleware та CORS у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-errors-middleware","05.python\u002Ffastapi\u002F21.fastapi-errors-middleware",{"title":2642,"path":2643,"stem":2644},"SQLAlchemy 2.0 — ORM, Core та Async Engine","\u002Fpython\u002Ffastapi\u002Fsqlalchemy-orm","05.python\u002Ffastapi\u002F22.sqlalchemy-orm",{"title":2646,"path":2647,"stem":2648},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2650,"icon":2651,"path":2652,"stem":2653,"children":2654,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2655,2685,2708,2745,2774,2792,2826,2838,2847],{"title":2656,"icon":2657,"path":2658,"stem":2659,"children":2660,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2661,2665,2669,2673,2677,2681],{"title":2662,"path":2663,"stem":2664},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2666,"path":2667,"stem":2668},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2670,"path":2671,"stem":2672},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2674,"path":2675,"stem":2676},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2678,"path":2679,"stem":2680},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2682,"path":2683,"stem":2684},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2686,"icon":2651,"path":2687,"stem":2688,"children":2689,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2690,2694,2700,2704],{"title":2691,"path":2692,"stem":2693},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2695,"path":2696,"stem":2697,"children":2698},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2699],{"title":2695,"path":2696,"stem":2697},{"title":2701,"path":2702,"stem":2703},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2705,"path":2706,"stem":2707},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2709,"icon":2651,"path":2710,"stem":2711,"children":2712,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2713,2717,2721,2725,2729,2733,2737,2741],{"title":2714,"path":2715,"stem":2716},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2718,"path":2719,"stem":2720},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2722,"path":2723,"stem":2724},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2726,"path":2727,"stem":2728},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2730,"path":2731,"stem":2732},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2734,"path":2735,"stem":2736},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2738,"path":2739,"stem":2740},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2742,"path":2743,"stem":2744},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2746,"icon":2651,"path":2747,"stem":2748,"children":2749,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2750,2754,2758,2762,2766,2770],{"title":2751,"path":2752,"stem":2753},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2755,"path":2756,"stem":2757},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2759,"path":2760,"stem":2761},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2763,"path":2764,"stem":2765},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2767,"path":2768,"stem":2769},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2771,"path":2772,"stem":2773},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2775,"icon":2776,"path":2777,"stem":2778,"children":2779,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2780,2784,2788],{"title":2781,"path":2782,"stem":2783},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2785,"path":2786,"stem":2787},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":2789,"path":2790,"stem":2791},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":2793,"icon":2794,"path":2795,"stem":2796,"children":2797,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[2798,2802,2806,2810,2814,2818,2822],{"title":2799,"path":2800,"stem":2801},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":2803,"path":2804,"stem":2805},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":2807,"path":2808,"stem":2809},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":2811,"path":2812,"stem":2813},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":2815,"path":2816,"stem":2817},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":2819,"path":2820,"stem":2821},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":2823,"path":2824,"stem":2825},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":2823,"icon":793,"path":2827,"stem":2828,"children":2829,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[2830,2834],{"title":2831,"path":2832,"stem":2833},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":2835,"path":2836,"stem":2837},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":2839,"icon":2840,"path":2841,"stem":2842,"children":2843,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[2844],{"title":2839,"path":2845,"stem":2846},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":2848,"icon":2849,"path":2850,"stem":2851,"children":2852,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[2853],{"title":2848,"path":2854,"stem":2855},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":2857,"icon":2858,"path":2859,"stem":2860,"children":2861,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[2862,2938],{"title":2863,"icon":2864,"path":2865,"stem":2866,"children":2867},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[2868,2870,2874,2878,2882,2886,2890,2894,2898,2902,2906,2910,2914,2918,2922,2926,2930,2934],{"title":2869,"path":2865,"stem":2866},"Docker: від нуля до production",{"title":2871,"path":2872,"stem":2873},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":2875,"path":2876,"stem":2877},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":2879,"path":2880,"stem":2881},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":2883,"path":2884,"stem":2885},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":2887,"path":2888,"stem":2889},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":2891,"path":2892,"stem":2893},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":2895,"path":2896,"stem":2897},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":2899,"path":2900,"stem":2901},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":2903,"path":2904,"stem":2905},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":2907,"path":2908,"stem":2909},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":2911,"path":2912,"stem":2913},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":2915,"path":2916,"stem":2917},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":2919,"path":2920,"stem":2921},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":2923,"path":2924,"stem":2925},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":2927,"path":2928,"stem":2929},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":2931,"path":2932,"stem":2933},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":2935,"path":2936,"stem":2937},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":2939,"icon":2940,"path":2941,"stem":2942,"children":2943},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[2944,2946,2950,2954,2958,2962,2966,2970,2974],{"title":2945,"path":2941,"stem":2942},"Kubernetes: від розробки до production",{"title":2947,"path":2948,"stem":2949},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":2951,"path":2952,"stem":2953},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":2955,"path":2956,"stem":2957},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":2959,"path":2960,"stem":2961},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":2963,"path":2964,"stem":2965},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":2967,"path":2968,"stem":2969},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":2971,"path":2972,"stem":2973},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":2975,"path":2976,"stem":2977},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":2979,"icon":2980,"path":2981,"stem":2982,"children":2983,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[2984,2988,2992,2996,3000,3004,3008,3012,3016,3020,3024],{"title":2985,"path":2986,"stem":2987},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":2989,"path":2990,"stem":2991},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":2993,"path":2994,"stem":2995},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":2997,"path":2998,"stem":2999},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":3001,"path":3002,"stem":3003},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":3005,"path":3006,"stem":3007},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":3009,"path":3010,"stem":3011},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":3013,"path":3014,"stem":3015},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":3017,"path":3018,"stem":3019},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":3021,"path":3022,"stem":3023},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":3025,"path":3026,"stem":3027},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":3029,"icon":943,"path":3030,"stem":3031,"children":3032,"page":59},"DDD","\u002Fddd","10.ddd",[3033,3037,3041,3045,3049,3053,3057,3061,3065,3069,3073,3077,3081],{"title":3034,"path":3035,"stem":3036},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":3038,"path":3039,"stem":3040},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3042,"path":3043,"stem":3044},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3046,"path":3047,"stem":3048},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3050,"path":3051,"stem":3052},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3054,"path":3055,"stem":3056},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3058,"path":3059,"stem":3060},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3062,"path":3063,"stem":3064},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3066,"path":3067,"stem":3068},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3070,"path":3071,"stem":3072},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3074,"path":3075,"stem":3076},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3078,"path":3079,"stem":3080},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3082,"path":3083,"stem":3084},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3086,"icon":3087,"path":3088,"stem":3089,"children":3090,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3091,3095,3099,3103,3107,3111,3115],{"title":3092,"path":3093,"stem":3094},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3096,"path":3097,"stem":3098},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3100,"path":3101,"stem":3102},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3104,"path":3105,"stem":3106},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3108,"path":3109,"stem":3110},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3112,"path":3113,"stem":3114},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3116,"path":3117,"stem":3118},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3120,"icon":3121,"path":3122,"stem":3123,"children":3124,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3125,3129,3133,3137,3141,3145,3149,3153,3157,3161,3165,3169,3173,3177,3181,3185,3189,3193,3197,3201,3205,3209,3213,3217,3221,3225,3229,3233,3237,3241],{"title":3126,"path":3127,"stem":3128},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3130,"path":3131,"stem":3132},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3134,"path":3135,"stem":3136},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3138,"path":3139,"stem":3140},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3142,"path":3143,"stem":3144},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3146,"path":3147,"stem":3148},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3150,"path":3151,"stem":3152},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3154,"path":3155,"stem":3156},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3158,"path":3159,"stem":3160},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3162,"path":3163,"stem":3164},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3166,"path":3167,"stem":3168},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3170,"path":3171,"stem":3172},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3174,"path":3175,"stem":3176},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3178,"path":3179,"stem":3180},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3182,"path":3183,"stem":3184},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3186,"path":3187,"stem":3188},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3190,"path":3191,"stem":3192},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3194,"path":3195,"stem":3196},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3198,"path":3199,"stem":3200},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3202,"path":3203,"stem":3204},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3206,"path":3207,"stem":3208},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3210,"path":3211,"stem":3212},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3214,"path":3215,"stem":3216},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3218,"path":3219,"stem":3220},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3222,"path":3223,"stem":3224},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3226,"path":3227,"stem":3228},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3230,"path":3231,"stem":3232},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3234,"path":3235,"stem":3236},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3238,"path":3239,"stem":3240},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3242,"path":3243,"stem":3244},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3246,"path":3247,"stem":3248,"children":3249,"page":59},"AWS","\u002Faws","13.aws",[3250,3254,3258,3262,3266,3270,3274,3278,3282,3286,3290,3294,3298,3302,3306,3310,3314,3318],{"title":3251,"path":3252,"stem":3253},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3255,"path":3256,"stem":3257},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3259,"path":3260,"stem":3261},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3263,"path":3264,"stem":3265},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3267,"path":3268,"stem":3269},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3271,"path":3272,"stem":3273},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3275,"path":3276,"stem":3277},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3279,"path":3280,"stem":3281},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3283,"path":3284,"stem":3285},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3287,"path":3288,"stem":3289},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3291,"path":3292,"stem":3293},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3295,"path":3296,"stem":3297},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3299,"path":3300,"stem":3301},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3303,"path":3304,"stem":3305},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3307,"path":3308,"stem":3309},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3311,"path":3312,"stem":3313},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3315,"path":3316,"stem":3317},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3319,"path":3320,"stem":3321},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3323,"path":3324,"stem":3325,"children":3326,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[3327,3331,3335,3339,3343,3347,3351,3355,3359,3363,3367,3371],{"title":3328,"path":3329,"stem":3330},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":3332,"path":3333,"stem":3334},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":3336,"path":3337,"stem":3338},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":3340,"path":3341,"stem":3342},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":3344,"path":3345,"stem":3346},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":3348,"path":3349,"stem":3350},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":3352,"path":3353,"stem":3354},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":3356,"path":3357,"stem":3358},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":3360,"path":3361,"stem":3362},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":3364,"path":3365,"stem":3366},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":3368,"path":3369,"stem":3370},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":3372,"path":3373,"stem":3374},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":3376,"path":3377,"stem":3378},"Тестування компонентів діаграм","\u002Ftest-components","98.test-components",{"id":3380,"title":2554,"body":3381,"description":22859,"extension":22860,"links":22861,"meta":22862,"navigation":3576,"path":2555,"seo":22863,"stem":2556,"__hash__":22864},"docs\u002F05.python\u002F00.modules-packages-venv.md",{"type":3382,"value":3383,"toc":22736},"minimark",[3384,3388,3393,3402,3410,3449,3460,3463,3467,3472,3497,3504,3547,3550,4031,4072,4076,4104,4244,4257,4261,4268,4286,4291,4298,4355,4358,4471,4475,4486,4683,4742,4749,4758,4767,4770,4817,4820,4824,4827,5155,5163,5180,5280,5287,5304,5306,5313,5319,5333,5564,5571,5690,5780,5789,5883,5890,5895,5968,5988,6008,6012,6025,6031,6101,6104,6111,6123,6135,6145,6160,6162,6169,6173,6187,6197,6414,6491,6497,6506,6690,6760,6772,6778,6788,7059,7080,7087,7093,7210,7236,7246,7248,7255,7259,7266,7294,7301,7515,7582,7590,7599,8097,8113,8120,8131,8197,8220,8222,8226,8230,8233,8400,8405,8532,8701,8705,8710,8713,8721,8726,8767,8781,8783,8787,8791,8794,8800,8810,8814,8817,10001,10008,10014,10030,10049,10058,10073,10117,10119,10123,10127,10136,10185,10192,10196,10202,10272,10285,10319,10325,10337,10462,10467,10488,10490,10494,10498,10501,10527,10542,10548,10678,10819,10826,10839,10854,10858,10861,10873,10920,10931,10996,11003,11027,11037,11041,11046,11110,11113,11119,11124,11138,11256,11261,11269,11369,11426,11431,11468,11475,11480,11488,11523,11570,11577,11624,11653,11655,11659,11669,11700,11714,11716,11722,11748,11806,11812,11901,11905,11964,12025,12034,12107,12111,12269,12358,12367,12467,12471,12477,12594,12608,12612,12620,12722,12770,12777,12786,12881,12892,12901,12911,13004,13062,13068,13637,13639,13645,13661,13708,13712,13803,13813,13817,13866,13941,13947,13956,14240,14243,14407,14499,14503,14509,14624,14629,15180,15182,15193,15200,15204,15207,15262,15272,15473,15483,15489,15655,15662,15674,15803,15810,15986,15988,15997,16019,16031,16035,16174,16180,16259,16328,16336,16484,16488,16822,16828,16890,16992,16999,17126,17131,17200,17204,17319,17333,17339,17434,17440,17662,17664,17678,17844,17860,17862,17866,17870,17877,17880,17899,17902,17904,17911,17920,17924,18138,18142,18263,18297,18299,18306,18322,18326,18493,18497,18634,18641,18644,18726,18732,18734,18740,18746,18750,18776,18780,18992,18996,19007,19156,19160,19173,19180,19296,19298,19309,19312,19320,19339,19345,19355,19694,19700,19799,19801,19808,19825,19832,19843,20007,20014,20026,20128,20135,20144,20309,20316,20333,20341,20449,20462,20464,20468,20471,20715,20727,20729,20733,20752,20756,20759,20789,20793,20796,22202,22204,22208,22503,22505,22509,22600,22602,22606,22655,22660,22732],[3385,3386,2554],"h1",{"id":3387},"модулі-пакети-та-віртуальні-середовища",[3389,3390,3392],"h2",{"id":3391},"проблема-монолітного-коду-навіщо-взагалі-ділити-програму","Проблема монолітного коду: навіщо взагалі ділити програму",[3394,3395,3396,3397,3401],"p",{},"Уявіть, що ви розробляєте платформу для онлайн-торгівлі. Перші кілька тижнів все ідеально: один файл ",[3398,3399,3400],"code",{},"main.py",", кілька функцій, чотири змінні. Але проходить місяць — і цей файл розростається до 2000 рядків. У ньому перемішані логіка авторизації, робота з базою даних, бізнес-правила знижок, генерація PDF-звітів та обробка платежів.",[3394,3403,3404,3405,3409],{},"Це явище має назву — ",[3406,3407,3408],"strong",{},"монолітний антипатерн",". Він не є проблемою теоретичною: він реально гальмує розробку, ламає командну роботу та перетворює підтримку коду на катування.",[3411,3412,3413,3427,3432,3444],"card-group",{},[3414,3415,3418,3419,3422,3423,3426],"card",{"icon":3416,"title":3417},"i-heroicons-eye-slash","Низька читабельність","Знайти функцію ",[3398,3420,3421],{},"calculate_vat"," серед 2000 рядків — це пригода. IDE допомагає, але лише до певної межі. Після неї — лише ",[3398,3424,3425],{},"Ctrl+F"," і терпіння.",[3414,3428,3431],{"icon":3429,"title":3430},"i-heroicons-users","Конфлікти у команді","Двоє розробників одночасно редагують один файл — це гарантований merge conflict у Git. Один файл = один потік змін.",[3414,3433,3436,3437,3440,3441,3443],{"icon":3434,"title":3435},"i-heroicons-arrow-path","Неможливість перевикористання","Ваша функція ",[3398,3438,3439],{},"send_email"," з ",[3398,3442,3400],{}," потрібна у новому проекті? Доведеться або копіювати, або тягнути весь монолітний файл разом із зайвим кодом.",[3414,3445,3448],{"icon":3446,"title":3447},"i-heroicons-beaker","Неможливість тестування","Як написати unit-тест для функції, що має десятки прихованих залежностей від глобального стану у тому ж файлі? Майже ніяк.",[3394,3450,3451,3452,3455,3456,3459],{},"Рішення, що пропонує Python, — це чотирирівнева система організації коду: ",[3406,3453,3454],{},"вирази → функції → модулі → пакети",". Ця стаття присвячена двом верхнім рівням і тому, як забезпечити їхню ізоляцію між проектами через ",[3406,3457,3458],{},"віртуальні середовища",".",[3461,3462],"hr",{},[3389,3464,3466],{"id":3465},"частина-i-модулі","Частина I: Модулі",[3468,3469,3471],"h3",{"id":3470},"що-таке-модуль-від-файлу-до-обєкта","Що таке модуль: від файлу до об'єкта",[3394,3473,3474,3475,3478,3479,3482,3483,3489,3490,3493,3494,3459],{},"З практичної точки зору, ",[3406,3476,3477],{},"модуль"," — це будь-який файл з розширенням ",[3398,3480,3481],{},".py",". Але це спрощення. З точки зору Python-рантайму, модуль — це ",[3406,3484,3485,3486],{},"об'єкт типу ",[3398,3487,3488],{},"types.ModuleType",", що має власний простір імен (",[3398,3491,3492],{},"namespace",") і зберігається у кеші ",[3398,3495,3496],{},"sys.modules",[3394,3498,3499,3500,3503],{},"Коли Python виконує ",[3398,3501,3502],{},"import calculator",", він не просто «підключає файл». Він:",[3505,3506,3507,3519,3525,3531,3534,3540],"ol",{},[3508,3509,3510,3511,3514,3515,3518],"li",{},"Знаходить файл ",[3398,3512,3513],{},"calculator.py"," (за алгоритмом ",[3398,3516,3517],{},"sys.path",")",[3508,3520,3521,3522,3518],{},"Компілює його у байткод (",[3398,3523,3524],{},"calculator.pyc",[3508,3526,3527,3528],{},"Створює новий об'єкт типу ",[3398,3529,3530],{},"module",[3508,3532,3533],{},"Виконує байткод у просторі імен цього об'єкта",[3508,3535,3536,3537],{},"Зберігає об'єкт у словнику ",[3398,3538,3539],{},"sys.modules['calculator']",[3508,3541,3542,3543,3546],{},"Прив'язує ім'я ",[3398,3544,3545],{},"calculator"," у поточному просторі імен",[3394,3548,3549],{},"Розглянемо цей процес на практичному прикладі. Побудуємо структуру реального mini-проекту:",[3551,3552,3553,3887],"code-tree",{},[3554,3555,3560],"pre",{"className":3556,"code":3557,"filename":3513,"language":3558,"meta":3559,"style":3559},"language-python shiki shiki-themes light-plus dark-plus dark-plus","# Модуль для математичних операцій\n\nPI = 3.1415926535  # Константа — публічний атрибут модуля\n\ndef add(a: float, b: float) -> float:\n    \"\"\"Повертає суму двох чисел.\"\"\"\n    return a + b\n\ndef subtract(a: float, b: float) -> float:\n    \"\"\"Повертає різницю двох чисел.\"\"\"\n    return a - b\n\ndef multiply(a: float, b: float) -> float:\n    \"\"\"Повертає добуток двох чисел.\"\"\"\n    return a * b\n\ndef circle_area(radius: float) -> float:\n    \"\"\"Обчислює площу кола через внутрішню константу PI.\"\"\"\n    return PI * radius ** 2\n\ndef _validate_numbers(*args) -> bool:\n    \"\"\"\n    Приватна функція за конвенцією (_prefix).\n    Не призначена для використання ззовні модуля.\n    \"\"\"\n    return all(isinstance(x, (int, float)) for x in args)\n","python","",[3398,3561,3562,3571,3578,3592,3597,3640,3647,3657,3662,3692,3698,3706,3711,3741,3747,3755,3760,3783,3789,3800,3805,3826,3832,3838,3844,3849],{"__ignoreMap":3559},[3563,3564,3567],"span",{"class":3565,"line":3566},"line",1,[3563,3568,3570],{"class":3569},"spJ8K","# Модуль для математичних операцій\n",[3563,3572,3574],{"class":3565,"line":3573},2,[3563,3575,3577],{"emptyLinePlaceholder":3576},true,"\n",[3563,3579,3581,3585,3589],{"class":3565,"line":3580},3,[3563,3582,3584],{"class":3583},"sHH4Y","PI = ",[3563,3586,3588],{"class":3587},"sJj4R","3.1415926535",[3563,3590,3591],{"class":3569},"  # Константа — публічний атрибут модуля\n",[3563,3593,3595],{"class":3565,"line":3594},4,[3563,3596,3577],{"emptyLinePlaceholder":3576},[3563,3598,3600,3604,3608,3611,3615,3618,3622,3625,3628,3630,3632,3635,3637],{"class":3565,"line":3599},5,[3563,3601,3603],{"class":3602},"su1O8","def",[3563,3605,3607],{"class":3606},"s8Opu"," add",[3563,3609,3610],{"class":3583},"(",[3563,3612,3614],{"class":3613},"siwwj","a",[3563,3616,3617],{"class":3583},": ",[3563,3619,3621],{"class":3620},"sN1BT","float",[3563,3623,3624],{"class":3583},", ",[3563,3626,3627],{"class":3613},"b",[3563,3629,3617],{"class":3583},[3563,3631,3621],{"class":3620},[3563,3633,3634],{"class":3583},") -> ",[3563,3636,3621],{"class":3620},[3563,3638,3639],{"class":3583},":\n",[3563,3641,3643],{"class":3565,"line":3642},6,[3563,3644,3646],{"class":3645},"sbdoH","    \"\"\"Повертає суму двох чисел.\"\"\"\n",[3563,3648,3650,3654],{"class":3565,"line":3649},7,[3563,3651,3653],{"class":3652},"s8xlr","    return",[3563,3655,3656],{"class":3583}," a + b\n",[3563,3658,3660],{"class":3565,"line":3659},8,[3563,3661,3577],{"emptyLinePlaceholder":3576},[3563,3663,3665,3667,3670,3672,3674,3676,3678,3680,3682,3684,3686,3688,3690],{"class":3565,"line":3664},9,[3563,3666,3603],{"class":3602},[3563,3668,3669],{"class":3606}," subtract",[3563,3671,3610],{"class":3583},[3563,3673,3614],{"class":3613},[3563,3675,3617],{"class":3583},[3563,3677,3621],{"class":3620},[3563,3679,3624],{"class":3583},[3563,3681,3627],{"class":3613},[3563,3683,3617],{"class":3583},[3563,3685,3621],{"class":3620},[3563,3687,3634],{"class":3583},[3563,3689,3621],{"class":3620},[3563,3691,3639],{"class":3583},[3563,3693,3695],{"class":3565,"line":3694},10,[3563,3696,3697],{"class":3645},"    \"\"\"Повертає різницю двох чисел.\"\"\"\n",[3563,3699,3701,3703],{"class":3565,"line":3700},11,[3563,3702,3653],{"class":3652},[3563,3704,3705],{"class":3583}," a - b\n",[3563,3707,3709],{"class":3565,"line":3708},12,[3563,3710,3577],{"emptyLinePlaceholder":3576},[3563,3712,3714,3716,3719,3721,3723,3725,3727,3729,3731,3733,3735,3737,3739],{"class":3565,"line":3713},13,[3563,3715,3603],{"class":3602},[3563,3717,3718],{"class":3606}," multiply",[3563,3720,3610],{"class":3583},[3563,3722,3614],{"class":3613},[3563,3724,3617],{"class":3583},[3563,3726,3621],{"class":3620},[3563,3728,3624],{"class":3583},[3563,3730,3627],{"class":3613},[3563,3732,3617],{"class":3583},[3563,3734,3621],{"class":3620},[3563,3736,3634],{"class":3583},[3563,3738,3621],{"class":3620},[3563,3740,3639],{"class":3583},[3563,3742,3744],{"class":3565,"line":3743},14,[3563,3745,3746],{"class":3645},"    \"\"\"Повертає добуток двох чисел.\"\"\"\n",[3563,3748,3750,3752],{"class":3565,"line":3749},15,[3563,3751,3653],{"class":3652},[3563,3753,3754],{"class":3583}," a * b\n",[3563,3756,3758],{"class":3565,"line":3757},16,[3563,3759,3577],{"emptyLinePlaceholder":3576},[3563,3761,3763,3765,3768,3770,3773,3775,3777,3779,3781],{"class":3565,"line":3762},17,[3563,3764,3603],{"class":3602},[3563,3766,3767],{"class":3606}," circle_area",[3563,3769,3610],{"class":3583},[3563,3771,3772],{"class":3613},"radius",[3563,3774,3617],{"class":3583},[3563,3776,3621],{"class":3620},[3563,3778,3634],{"class":3583},[3563,3780,3621],{"class":3620},[3563,3782,3639],{"class":3583},[3563,3784,3786],{"class":3565,"line":3785},18,[3563,3787,3788],{"class":3645},"    \"\"\"Обчислює площу кола через внутрішню константу PI.\"\"\"\n",[3563,3790,3792,3794,3797],{"class":3565,"line":3791},19,[3563,3793,3653],{"class":3652},[3563,3795,3796],{"class":3583}," PI * radius ** ",[3563,3798,3799],{"class":3587},"2\n",[3563,3801,3803],{"class":3565,"line":3802},20,[3563,3804,3577],{"emptyLinePlaceholder":3576},[3563,3806,3808,3810,3813,3816,3819,3821,3824],{"class":3565,"line":3807},21,[3563,3809,3603],{"class":3602},[3563,3811,3812],{"class":3606}," _validate_numbers",[3563,3814,3815],{"class":3583},"(*",[3563,3817,3818],{"class":3613},"args",[3563,3820,3634],{"class":3583},[3563,3822,3823],{"class":3620},"bool",[3563,3825,3639],{"class":3583},[3563,3827,3829],{"class":3565,"line":3828},22,[3563,3830,3831],{"class":3645},"    \"\"\"\n",[3563,3833,3835],{"class":3565,"line":3834},23,[3563,3836,3837],{"class":3645},"    Приватна функція за конвенцією (_prefix).\n",[3563,3839,3841],{"class":3565,"line":3840},24,[3563,3842,3843],{"class":3645},"    Не призначена для використання ззовні модуля.\n",[3563,3845,3847],{"class":3565,"line":3846},25,[3563,3848,3831],{"class":3645},[3563,3850,3852,3854,3857,3859,3862,3865,3868,3870,3872,3875,3878,3881,3884],{"class":3565,"line":3851},26,[3563,3853,3653],{"class":3652},[3563,3855,3856],{"class":3606}," all",[3563,3858,3610],{"class":3583},[3563,3860,3861],{"class":3606},"isinstance",[3563,3863,3864],{"class":3583},"(x, (",[3563,3866,3867],{"class":3620},"int",[3563,3869,3624],{"class":3583},[3563,3871,3621],{"class":3620},[3563,3873,3874],{"class":3583},")) ",[3563,3876,3877],{"class":3652},"for",[3563,3879,3880],{"class":3583}," x ",[3563,3882,3883],{"class":3652},"in",[3563,3885,3886],{"class":3583}," args)\n",[3554,3888,3890],{"className":3556,"code":3889,"filename":3400,"language":3558,"meta":3559,"style":3559},"# Головний скрипт, що використовує модуль calculator\n\nimport calculator  # Імпортуємо весь модуль\n\n# Доступ до атрибутів через ім'я модуля (крапкова нотація)\nresult = calculator.add(10, 5)\narea = calculator.circle_area(7.0)\n\nprint(f\"Сума: {result}\")              # 15\nprint(f\"Площа кола R=7: {area:.2f}\") # 153.94\nprint(f\"PI з модуля: {calculator.PI}\")\n",[3398,3891,3892,3897,3901,3912,3916,3921,3937,3947,3951,3982,4009],{"__ignoreMap":3559},[3563,3893,3894],{"class":3565,"line":3566},[3563,3895,3896],{"class":3569},"# Головний скрипт, що використовує модуль calculator\n",[3563,3898,3899],{"class":3565,"line":3573},[3563,3900,3577],{"emptyLinePlaceholder":3576},[3563,3902,3903,3906,3909],{"class":3565,"line":3580},[3563,3904,3905],{"class":3652},"import",[3563,3907,3908],{"class":3583}," calculator  ",[3563,3910,3911],{"class":3569},"# Імпортуємо весь модуль\n",[3563,3913,3914],{"class":3565,"line":3594},[3563,3915,3577],{"emptyLinePlaceholder":3576},[3563,3917,3918],{"class":3565,"line":3599},[3563,3919,3920],{"class":3569},"# Доступ до атрибутів через ім'я модуля (крапкова нотація)\n",[3563,3922,3923,3926,3929,3931,3934],{"class":3565,"line":3642},[3563,3924,3925],{"class":3583},"result = calculator.add(",[3563,3927,3928],{"class":3587},"10",[3563,3930,3624],{"class":3583},[3563,3932,3933],{"class":3587},"5",[3563,3935,3936],{"class":3583},")\n",[3563,3938,3939,3942,3945],{"class":3565,"line":3649},[3563,3940,3941],{"class":3583},"area = calculator.circle_area(",[3563,3943,3944],{"class":3587},"7.0",[3563,3946,3936],{"class":3583},[3563,3948,3949],{"class":3565,"line":3659},[3563,3950,3577],{"emptyLinePlaceholder":3576},[3563,3952,3953,3956,3958,3961,3964,3967,3970,3973,3976,3979],{"class":3565,"line":3664},[3563,3954,3955],{"class":3606},"print",[3563,3957,3610],{"class":3583},[3563,3959,3960],{"class":3602},"f",[3563,3962,3963],{"class":3645},"\"Сума: ",[3563,3965,3966],{"class":3602},"{",[3563,3968,3969],{"class":3583},"result",[3563,3971,3972],{"class":3602},"}",[3563,3974,3975],{"class":3645},"\"",[3563,3977,3978],{"class":3583},")              ",[3563,3980,3981],{"class":3569},"# 15\n",[3563,3983,3984,3986,3988,3990,3993,3995,3998,4001,4003,4006],{"class":3565,"line":3694},[3563,3985,3955],{"class":3606},[3563,3987,3610],{"class":3583},[3563,3989,3960],{"class":3602},[3563,3991,3992],{"class":3645},"\"Площа кола R=7: ",[3563,3994,3966],{"class":3602},[3563,3996,3997],{"class":3583},"area",[3563,3999,4000],{"class":3602},":.2f}",[3563,4002,3975],{"class":3645},[3563,4004,4005],{"class":3583},") ",[3563,4007,4008],{"class":3569},"# 153.94\n",[3563,4010,4011,4013,4015,4017,4020,4022,4025,4027,4029],{"class":3565,"line":3700},[3563,4012,3955],{"class":3606},[3563,4014,3610],{"class":3583},[3563,4016,3960],{"class":3602},[3563,4018,4019],{"class":3645},"\"PI з модуля: ",[3563,4021,3966],{"class":3602},[3563,4023,4024],{"class":3583},"calculator.PI",[3563,4026,3972],{"class":3602},[3563,4028,3975],{"class":3645},[3563,4030,3936],{"class":3583},[4032,4033,4035,4047,4056,4064],"terminal-preview",{"title":4034},"python main.py",[4036,4037,4039,4044,4045],"div",{"className":4038},[3565],[3563,4040,4043],{"className":4041},[4042],"opacity-40","$"," ",[3406,4046,4034],{},[4036,4048,4050,4051],{"className":4049},[3565],"Сума: ",[3563,4052,4055],{"className":4053},[4054],"text-green-400","15",[4036,4057,4059,4060],{"className":4058},[3565],"Площа кола R=7: ",[3563,4061,4063],{"className":4062},[4054],"153.94",[4036,4065,4067,4068],{"className":4066},[3565],"PI з модуля: ",[3563,4069,3588],{"className":4070},[4071],"text-blue-400",[3468,4073,4075],{"id":4074},"простір-імен-модуля-захист-від-конфліктів","Простір імен модуля: захист від конфліктів",[3394,4077,4078,4079,4081,4082,3624,4085,3624,4088,4091,4092,4096,4097,4099,4100,4103],{},"Коли ви пишете ",[3398,4080,3502],{},", Python не «вливає» імена ",[3398,4083,4084],{},"add",[3398,4086,4087],{},"subtract",[3398,4089,4090],{},"PI"," у поточний простір імен. Замість цього він створює ",[4093,4094,4095],"em",{},"одне"," ім'я ",[3398,4098,3545],{},", що вказує на об'єкт модуля. Доступ до вмісту — лише через крапку. Це і є ",[3406,4101,4102],{},"простір імен"," (namespace) — ізольований контейнер для імен.",[3554,4105,4107],{"className":3556,"code":4106,"language":3558,"meta":3559,"style":3559},"# main.py\nimport calculator\n\n# Наша власна функція add — для роботи з рядками\ndef add(text1: str, text2: str) -> str:\n    return text1 + \" \" + text2\n\n# Жодного конфлікту! Два різних простори імен:\nmy_text = add(\"Привіт\", \"Світ\")          # наша функція\ncalc_sum = calculator.add(2, 2)           # функція з модуля\n\nprint(my_text)    # \"Привіт Світ\"\nprint(calc_sum)   # 4\n",[3398,4108,4109,4114,4121,4125,4130,4161,4174,4178,4183,4202,4220,4224,4234],{"__ignoreMap":3559},[3563,4110,4111],{"class":3565,"line":3566},[3563,4112,4113],{"class":3569},"# main.py\n",[3563,4115,4116,4118],{"class":3565,"line":3573},[3563,4117,3905],{"class":3652},[3563,4119,4120],{"class":3583}," calculator\n",[3563,4122,4123],{"class":3565,"line":3580},[3563,4124,3577],{"emptyLinePlaceholder":3576},[3563,4126,4127],{"class":3565,"line":3594},[3563,4128,4129],{"class":3569},"# Наша власна функція add — для роботи з рядками\n",[3563,4131,4132,4134,4136,4138,4141,4143,4146,4148,4151,4153,4155,4157,4159],{"class":3565,"line":3599},[3563,4133,3603],{"class":3602},[3563,4135,3607],{"class":3606},[3563,4137,3610],{"class":3583},[3563,4139,4140],{"class":3613},"text1",[3563,4142,3617],{"class":3583},[3563,4144,4145],{"class":3620},"str",[3563,4147,3624],{"class":3583},[3563,4149,4150],{"class":3613},"text2",[3563,4152,3617],{"class":3583},[3563,4154,4145],{"class":3620},[3563,4156,3634],{"class":3583},[3563,4158,4145],{"class":3620},[3563,4160,3639],{"class":3583},[3563,4162,4163,4165,4168,4171],{"class":3565,"line":3642},[3563,4164,3653],{"class":3652},[3563,4166,4167],{"class":3583}," text1 + ",[3563,4169,4170],{"class":3645},"\" \"",[3563,4172,4173],{"class":3583}," + text2\n",[3563,4175,4176],{"class":3565,"line":3649},[3563,4177,3577],{"emptyLinePlaceholder":3576},[3563,4179,4180],{"class":3565,"line":3659},[3563,4181,4182],{"class":3569},"# Жодного конфлікту! Два різних простори імен:\n",[3563,4184,4185,4188,4191,4193,4196,4199],{"class":3565,"line":3664},[3563,4186,4187],{"class":3583},"my_text = add(",[3563,4189,4190],{"class":3645},"\"Привіт\"",[3563,4192,3624],{"class":3583},[3563,4194,4195],{"class":3645},"\"Світ\"",[3563,4197,4198],{"class":3583},")          ",[3563,4200,4201],{"class":3569},"# наша функція\n",[3563,4203,4204,4207,4210,4212,4214,4217],{"class":3565,"line":3694},[3563,4205,4206],{"class":3583},"calc_sum = calculator.add(",[3563,4208,4209],{"class":3587},"2",[3563,4211,3624],{"class":3583},[3563,4213,4209],{"class":3587},[3563,4215,4216],{"class":3583},")           ",[3563,4218,4219],{"class":3569},"# функція з модуля\n",[3563,4221,4222],{"class":3565,"line":3700},[3563,4223,3577],{"emptyLinePlaceholder":3576},[3563,4225,4226,4228,4231],{"class":3565,"line":3708},[3563,4227,3955],{"class":3606},[3563,4229,4230],{"class":3583},"(my_text)    ",[3563,4232,4233],{"class":3569},"# \"Привіт Світ\"\n",[3563,4235,4236,4238,4241],{"class":3565,"line":3713},[3563,4237,3955],{"class":3606},[3563,4239,4240],{"class":3583},"(calc_sum)   ",[3563,4242,4243],{"class":3569},"# 4\n",[3394,4245,4246,4247,4249,4250,4253,4254,3459],{},"Якби Python не використовував простори імен і замість ",[3398,4248,3502],{}," вставляв усі імена безпосередньо, виникала б катастрофа: будь-яка функція з будь-якого модуля могла б перезаписати будь-яку іншу. Саме тому ",[3398,4251,4252],{},"import module"," вважається більш безпечним підходом порівняно з ",[3398,4255,4256],{},"from module import *",[3468,4258,4260],{"id":4259},"поглиблене-розуміння-просторів-імен-namespaces-та-legb-правило","Поглиблене розуміння просторів імен (Namespaces) та LEGB-правило",[3394,4262,4263,4264,4267],{},"Щоб зрозуміти, як працює система імпорту та як уникнути помилок, пов'язаних із видимістю змінних, потрібно розібратися, що таке ",[3406,4265,4266],{},"простір імен (namespace)"," на низькому рівні.",[3394,4269,4270,4271,4277,4278,4281,4282,4285],{},"У Python простір імен — це ",[3406,4272,4273,4274,3518],{},"звичайний словник (",[3398,4275,4276],{},"dict",", де ключами є імена змінних (ідентифікатори), а значеннями — самі об'єкти, на які ці змінні посилаються. Коли ви пишете ",[3398,4279,4280],{},"x = 42",", Python просто додає запис ",[3398,4283,4284],{},"{\"x\": 42}"," у відповідний словник простору імен.",[4287,4288,4290],"h4",{"id":4289},"чотири-рівні-просторів-імен-та-legb-правило","Чотири рівні просторів імен та LEGB-правило",[3394,4292,4293,4294,4297],{},"Коли ви звертаєтеся до змінної, Python шукає її не скрізь, а в чітко визначеному порядку. Цей порядок описується ",[3406,4295,4296],{},"LEGB-правилом",":",[4299,4300,4301,4305,4315,4319,4322,4326,4329,4333],"steps",{},[3468,4302,4304],{"id":4303},"local-локальний","Local (Локальний)",[3394,4306,4307,4308,4310,4311,4314],{},"Змінні, визначені всередині поточної функції (через ",[3398,4309,3603],{}," або ",[3398,4312,4313],{},"lambda","). Вони створюються при виклику функції і знищуються при її завершенні.",[3468,4316,4318],{"id":4317},"enclosing-охоплюючий","Enclosing (Охоплюючий)",[3394,4320,4321],{},"Змінні у зовнішніх функціях (використовується при вкладених функціях або замиканнях).",[3468,4323,4325],{"id":4324},"global-глобальний","Global (Глобальний)",[3394,4327,4328],{},"Змінні, визначені на рівні модуля (файлу). Всі функції цього модуля мають доступ до цих змінних.",[3468,4330,4332],{"id":4331},"built-in-вбудований","Built-in (Вбудований)",[3394,4334,4335,4336,3624,4339,3624,4342,3624,4345,4347,4348,3624,4351,4354],{},"Назви, які автоматично завантажуються інтерпретатором при старті. Сюди входять вбудовані функції (",[3398,4337,4338],{},"print()",[3398,4340,4341],{},"len()",[3398,4343,4344],{},"range()",[3398,4346,4276],{},") та виключення (",[3398,4349,4350],{},"ValueError",[3398,4352,4353],{},"KeyError",").",[3394,4356,4357],{},"Схематично ієрархію пошуку імен можна зобразити у вигляді вкладених областей:",[4359,4360,4361],"plant-uml",{},[3554,4362,4366],{"className":4363,"code":4364,"language":4365,"meta":3559,"style":3559},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\n\nnode \"Вбудований (Built-in)\\n[print(), len(), ValueError]\" as B #fee2e2 {\n    node \"Глобальний (Global)\\n[змінні та функції модуля]\" as G #dbeafe {\n        node \"Охоплюючий (Enclosing)\\n[зовнішня функція]\" as E #fef3c7 {\n            node \"Локальний (Local)\\n[поточна функція]\" as L #d1fae5 {\n            }\n        }\n    }\n}\n\nnote right of L\n  Пошук імені починається тут (L)\n  і йде назовні: L -> E -> G -> B.\n  Якщо ім'я не знайдено в жодному —\n  піднімається NameError.\nend note\n@enduml\n","plantuml",[3398,4367,4368,4373,4378,4383,4388,4392,4397,4402,4407,4412,4417,4422,4427,4432,4436,4441,4446,4451,4456,4461,4466],{"__ignoreMap":3559},[3563,4369,4370],{"class":3565,"line":3566},[3563,4371,4372],{},"@startuml\n",[3563,4374,4375],{"class":3565,"line":3573},[3563,4376,4377],{},"skinparam style plain\n",[3563,4379,4380],{"class":3565,"line":3580},[3563,4381,4382],{},"skinparam backgroundColor #ffffff\n",[3563,4384,4385],{"class":3565,"line":3594},[3563,4386,4387],{},"skinparam ArrowColor #6366f1\n",[3563,4389,4390],{"class":3565,"line":3599},[3563,4391,3577],{"emptyLinePlaceholder":3576},[3563,4393,4394],{"class":3565,"line":3642},[3563,4395,4396],{},"node \"Вбудований (Built-in)\\n[print(), len(), ValueError]\" as B #fee2e2 {\n",[3563,4398,4399],{"class":3565,"line":3649},[3563,4400,4401],{},"    node \"Глобальний (Global)\\n[змінні та функції модуля]\" as G #dbeafe {\n",[3563,4403,4404],{"class":3565,"line":3659},[3563,4405,4406],{},"        node \"Охоплюючий (Enclosing)\\n[зовнішня функція]\" as E #fef3c7 {\n",[3563,4408,4409],{"class":3565,"line":3664},[3563,4410,4411],{},"            node \"Локальний (Local)\\n[поточна функція]\" as L #d1fae5 {\n",[3563,4413,4414],{"class":3565,"line":3694},[3563,4415,4416],{},"            }\n",[3563,4418,4419],{"class":3565,"line":3700},[3563,4420,4421],{},"        }\n",[3563,4423,4424],{"class":3565,"line":3708},[3563,4425,4426],{},"    }\n",[3563,4428,4429],{"class":3565,"line":3713},[3563,4430,4431],{},"}\n",[3563,4433,4434],{"class":3565,"line":3743},[3563,4435,3577],{"emptyLinePlaceholder":3576},[3563,4437,4438],{"class":3565,"line":3749},[3563,4439,4440],{},"note right of L\n",[3563,4442,4443],{"class":3565,"line":3757},[3563,4444,4445],{},"  Пошук імені починається тут (L)\n",[3563,4447,4448],{"class":3565,"line":3762},[3563,4449,4450],{},"  і йде назовні: L -> E -> G -> B.\n",[3563,4452,4453],{"class":3565,"line":3785},[3563,4454,4455],{},"  Якщо ім'я не знайдено в жодному —\n",[3563,4457,4458],{"class":3565,"line":3791},[3563,4459,4460],{},"  піднімається NameError.\n",[3563,4462,4463],{"class":3565,"line":3802},[3563,4464,4465],{},"end note\n",[3563,4467,4468],{"class":3565,"line":3807},[3563,4469,4470],{},"@enduml\n",[4287,4472,4474],{"id":4473},"практичний-експеримент-дослідження-просторів-імен","Практичний експеримент: дослідження просторів імен",[3394,4476,4477,4478,4481,4482,4485],{},"Ми можемо дослідити поточні простори імен за допомогою вбудованих функцій ",[3398,4479,4480],{},"locals()"," та ",[3398,4483,4484],{},"globals()",", які повертають відповідні словники простору імен.",[3554,4487,4489],{"className":3556,"code":4488,"language":3558,"meta":3559,"style":3559},"# namespace_demo.py\nimport math\n\nglobal_var = \"Я глобальна змінна\"\n\ndef outer_function():\n    enclosing_var = \"Я охоплююча змінна\"\n\n    def inner_function():\n        local_var = \"Я локальна змінна\"\n\n        # Дивимося на локальний простір імен внутрішньої функції\n        print(\"--- Local Namespace inside inner_function() ---\")\n        print(locals())  # Виведе тільки {'local_var': 'Я локальна змінна'}\n\n        # Спробуємо знайти global_var та print (built-in)\n        # Python пройде шлях: inner_local -> outer_enclosing -> global -> built-in\n\n    inner_function()\n\nouter_function()\n\n# Глобальний простір імен модуля\nprint(\"\\n--- Global Namespace of module ---\")\n# globals() містить імпортований 'math', 'global_var', 'outer_function' та службові атрибути\nprint(list(globals().keys())[:10])  # покажемо перші 10 ключів\n",[3398,4490,4491,4496,4503,4507,4515,4519,4529,4537,4541,4551,4559,4563,4568,4580,4595,4599,4604,4609,4613,4618,4622,4627,4631,4636,4653,4658],{"__ignoreMap":3559},[3563,4492,4493],{"class":3565,"line":3566},[3563,4494,4495],{"class":3569},"# namespace_demo.py\n",[3563,4497,4498,4500],{"class":3565,"line":3573},[3563,4499,3905],{"class":3652},[3563,4501,4502],{"class":3583}," math\n",[3563,4504,4505],{"class":3565,"line":3580},[3563,4506,3577],{"emptyLinePlaceholder":3576},[3563,4508,4509,4512],{"class":3565,"line":3594},[3563,4510,4511],{"class":3583},"global_var = ",[3563,4513,4514],{"class":3645},"\"Я глобальна змінна\"\n",[3563,4516,4517],{"class":3565,"line":3599},[3563,4518,3577],{"emptyLinePlaceholder":3576},[3563,4520,4521,4523,4526],{"class":3565,"line":3642},[3563,4522,3603],{"class":3602},[3563,4524,4525],{"class":3606}," outer_function",[3563,4527,4528],{"class":3583},"():\n",[3563,4530,4531,4534],{"class":3565,"line":3649},[3563,4532,4533],{"class":3583},"    enclosing_var = ",[3563,4535,4536],{"class":3645},"\"Я охоплююча змінна\"\n",[3563,4538,4539],{"class":3565,"line":3659},[3563,4540,3577],{"emptyLinePlaceholder":3576},[3563,4542,4543,4546,4549],{"class":3565,"line":3664},[3563,4544,4545],{"class":3602},"    def",[3563,4547,4548],{"class":3606}," inner_function",[3563,4550,4528],{"class":3583},[3563,4552,4553,4556],{"class":3565,"line":3694},[3563,4554,4555],{"class":3583},"        local_var = ",[3563,4557,4558],{"class":3645},"\"Я локальна змінна\"\n",[3563,4560,4561],{"class":3565,"line":3700},[3563,4562,3577],{"emptyLinePlaceholder":3576},[3563,4564,4565],{"class":3565,"line":3708},[3563,4566,4567],{"class":3569},"        # Дивимося на локальний простір імен внутрішньої функції\n",[3563,4569,4570,4573,4575,4578],{"class":3565,"line":3713},[3563,4571,4572],{"class":3606},"        print",[3563,4574,3610],{"class":3583},[3563,4576,4577],{"class":3645},"\"--- Local Namespace inside inner_function() ---\"",[3563,4579,3936],{"class":3583},[3563,4581,4582,4584,4586,4589,4592],{"class":3565,"line":3743},[3563,4583,4572],{"class":3606},[3563,4585,3610],{"class":3583},[3563,4587,4588],{"class":3606},"locals",[3563,4590,4591],{"class":3583},"())  ",[3563,4593,4594],{"class":3569},"# Виведе тільки {'local_var': 'Я локальна змінна'}\n",[3563,4596,4597],{"class":3565,"line":3749},[3563,4598,3577],{"emptyLinePlaceholder":3576},[3563,4600,4601],{"class":3565,"line":3757},[3563,4602,4603],{"class":3569},"        # Спробуємо знайти global_var та print (built-in)\n",[3563,4605,4606],{"class":3565,"line":3762},[3563,4607,4608],{"class":3569},"        # Python пройде шлях: inner_local -> outer_enclosing -> global -> built-in\n",[3563,4610,4611],{"class":3565,"line":3785},[3563,4612,3577],{"emptyLinePlaceholder":3576},[3563,4614,4615],{"class":3565,"line":3791},[3563,4616,4617],{"class":3583},"    inner_function()\n",[3563,4619,4620],{"class":3565,"line":3802},[3563,4621,3577],{"emptyLinePlaceholder":3576},[3563,4623,4624],{"class":3565,"line":3807},[3563,4625,4626],{"class":3583},"outer_function()\n",[3563,4628,4629],{"class":3565,"line":3828},[3563,4630,3577],{"emptyLinePlaceholder":3576},[3563,4632,4633],{"class":3565,"line":3834},[3563,4634,4635],{"class":3569},"# Глобальний простір імен модуля\n",[3563,4637,4638,4640,4642,4644,4648,4651],{"class":3565,"line":3840},[3563,4639,3955],{"class":3606},[3563,4641,3610],{"class":3583},[3563,4643,3975],{"class":3645},[3563,4645,4647],{"class":4646},"sjcCO","\\n",[3563,4649,4650],{"class":3645},"--- Global Namespace of module ---\"",[3563,4652,3936],{"class":3583},[3563,4654,4655],{"class":3565,"line":3846},[3563,4656,4657],{"class":3569},"# globals() містить імпортований 'math', 'global_var', 'outer_function' та службові атрибути\n",[3563,4659,4660,4662,4664,4667,4669,4672,4675,4677,4680],{"class":3565,"line":3851},[3563,4661,3955],{"class":3606},[3563,4663,3610],{"class":3583},[3563,4665,4666],{"class":3620},"list",[3563,4668,3610],{"class":3583},[3563,4670,4671],{"class":3606},"globals",[3563,4673,4674],{"class":3583},"().keys())[:",[3563,4676,3928],{"class":3587},[3563,4678,4679],{"class":3583},"])  ",[3563,4681,4682],{"class":3569},"# покажемо перші 10 ключів\n",[4032,4684,4686,4694,4698,4706,4709,4713],{"title":4685},"python namespace_demo.py",[4036,4687,4689,4044,4692],{"className":4688},[3565],[3563,4690,4043],{"className":4691},[4042],[3406,4693,4685],{},[4036,4695,4697],{"className":4696},[3565],"--- Local Namespace inside inner_function() ---",[4036,4699,4701,4702,3972],{"className":4700},[3565],"{'local_var': ",[3563,4703,4705],{"className":4704},[4054],"'Я локальна змінна'",[4036,4707],{"className":4708},[3565],[4036,4710,4712],{"className":4711},[3565],"--- Global Namespace of module ---",[4036,4714,4716,4717,3624,4721,3624,4725,3624,4729,3624,4733,3624,4737,4741],{"className":4715},[3565],"[",[3563,4718,4720],{"className":4719},[4071],"'__name__'",[3563,4722,4724],{"className":4723},[4071],"'__doc__'",[3563,4726,4728],{"className":4727},[4071],"'__package__'",[3563,4730,4732],{"className":4731},[4071],"'math'",[3563,4734,4736],{"className":4735},[4071],"'global_var'",[3563,4738,4740],{"className":4739},[4071],"'outer_function'","]",[4287,4743,4745,4746],{"id":4744},"модуль-як-обєкт-та-його-атрибут-__dict__","Модуль як об'єкт та його атрибут ",[3398,4747,4748],{},"__dict__",[3394,4750,4751,4752,4754,4755,4757],{},"Оскільки кожен модуль після імпорту стає об'єктом типу ",[3398,4753,3530],{},", його простір імен зберігається в спеціальному атрибуті ",[3398,4756,4748],{},". Це звичайний словник.",[3394,4759,4078,4760,4763,4764],{},[3398,4761,4762],{},"calculator.add(5, 5)",", Python під капотом виконує:\n",[3398,4765,4766],{},"calculator.__dict__['add'](5, 5)",[3394,4768,4769],{},"Це означає, що ми можемо динамічно маніпулювати простором імен модуля навіть після його імпорту (хоча цим не варто зловживати):",[3554,4771,4773],{"className":3556,"code":4772,"language":3558,"meta":3559,"style":3559},"import calculator\n\n# Динамічно додаємо нове ім'я в простір імен модуля calculator\ncalculator.new_constant = 9.99\n\n# Тепер це ім'я доступне звичайним шляхом!\nprint(calculator.new_constant)  # 9.99\n",[3398,4774,4775,4781,4785,4790,4798,4802,4807],{"__ignoreMap":3559},[3563,4776,4777,4779],{"class":3565,"line":3566},[3563,4778,3905],{"class":3652},[3563,4780,4120],{"class":3583},[3563,4782,4783],{"class":3565,"line":3573},[3563,4784,3577],{"emptyLinePlaceholder":3576},[3563,4786,4787],{"class":3565,"line":3580},[3563,4788,4789],{"class":3569},"# Динамічно додаємо нове ім'я в простір імен модуля calculator\n",[3563,4791,4792,4795],{"class":3565,"line":3594},[3563,4793,4794],{"class":3583},"calculator.new_constant = ",[3563,4796,4797],{"class":3587},"9.99\n",[3563,4799,4800],{"class":3565,"line":3599},[3563,4801,3577],{"emptyLinePlaceholder":3576},[3563,4803,4804],{"class":3565,"line":3642},[3563,4805,4806],{"class":3569},"# Тепер це ім'я доступне звичайним шляхом!\n",[3563,4808,4809,4811,4814],{"class":3565,"line":3649},[3563,4810,3955],{"class":3606},[3563,4812,4813],{"class":3583},"(calculator.new_constant)  ",[3563,4815,4816],{"class":3569},"# 9.99\n",[3394,4818,4819],{},"Цей динамізм показує, що простір імен модулів у Python є відкритим і гнучким, на відміну від статичних просторів імен у таких мовах, як C++ або C#.",[3468,4821,4823],{"id":4822},"синтаксис-імпорту-вичерпний-огляд","Синтаксис імпорту: вичерпний огляд",[3394,4825,4826],{},"Python надає кілька синтаксичних форм для імпорту, кожна з яких має власну область застосування та компроміси.",[4828,4829,4830,4895,4975,5078],"tabs",{},[4831,4832,4833,4889],"tabs-item",{"label":4252},[3554,4834,4836],{"className":3556,"code":4835,"language":3558,"meta":3559,"style":3559},"import calculator\nimport os\nimport sys\n\n# Доступ лише через ім'я модуля — жодних конфліктів\nresult = calculator.add(10, 5)\ncwd = os.getcwd()\npaths = sys.path\n",[3398,4837,4838,4844,4851,4858,4862,4867,4879,4884],{"__ignoreMap":3559},[3563,4839,4840,4842],{"class":3565,"line":3566},[3563,4841,3905],{"class":3652},[3563,4843,4120],{"class":3583},[3563,4845,4846,4848],{"class":3565,"line":3573},[3563,4847,3905],{"class":3652},[3563,4849,4850],{"class":3583}," os\n",[3563,4852,4853,4855],{"class":3565,"line":3580},[3563,4854,3905],{"class":3652},[3563,4856,4857],{"class":3583}," sys\n",[3563,4859,4860],{"class":3565,"line":3594},[3563,4861,3577],{"emptyLinePlaceholder":3576},[3563,4863,4864],{"class":3565,"line":3599},[3563,4865,4866],{"class":3569},"# Доступ лише через ім'я модуля — жодних конфліктів\n",[3563,4868,4869,4871,4873,4875,4877],{"class":3565,"line":3642},[3563,4870,3925],{"class":3583},[3563,4872,3928],{"class":3587},[3563,4874,3624],{"class":3583},[3563,4876,3933],{"class":3587},[3563,4878,3936],{"class":3583},[3563,4880,4881],{"class":3565,"line":3649},[3563,4882,4883],{"class":3583},"cwd = os.getcwd()\n",[3563,4885,4886],{"class":3565,"line":3659},[3563,4887,4888],{"class":3583},"paths = sys.path\n",[3394,4890,4891,4894],{},[3406,4892,4893],{},"Коли використовувати:"," у більшості випадків. Максимальна чіткість: завжди видно, звідки прийшло ім'я.",[4831,4896,4898,4970],{"label":4897},"from module import name",[3554,4899,4901],{"className":3556,"code":4900,"language":3558,"meta":3559,"style":3559},"from calculator import add, PI\nfrom os.path import join, exists\n\n# Доступ безпосередньо\nresult = add(10, 5)\nfull_path = join(\"\u002Fhome\", \"user\", \"project\")\n",[3398,4902,4903,4916,4928,4932,4937,4950],{"__ignoreMap":3559},[3563,4904,4905,4908,4911,4913],{"class":3565,"line":3566},[3563,4906,4907],{"class":3652},"from",[3563,4909,4910],{"class":3583}," calculator ",[3563,4912,3905],{"class":3652},[3563,4914,4915],{"class":3583}," add, PI\n",[3563,4917,4918,4920,4923,4925],{"class":3565,"line":3573},[3563,4919,4907],{"class":3652},[3563,4921,4922],{"class":3583}," os.path ",[3563,4924,3905],{"class":3652},[3563,4926,4927],{"class":3583}," join, exists\n",[3563,4929,4930],{"class":3565,"line":3580},[3563,4931,3577],{"emptyLinePlaceholder":3576},[3563,4933,4934],{"class":3565,"line":3594},[3563,4935,4936],{"class":3569},"# Доступ безпосередньо\n",[3563,4938,4939,4942,4944,4946,4948],{"class":3565,"line":3599},[3563,4940,4941],{"class":3583},"result = add(",[3563,4943,3928],{"class":3587},[3563,4945,3624],{"class":3583},[3563,4947,3933],{"class":3587},[3563,4949,3936],{"class":3583},[3563,4951,4952,4955,4958,4960,4963,4965,4968],{"class":3565,"line":3642},[3563,4953,4954],{"class":3583},"full_path = join(",[3563,4956,4957],{"class":3645},"\"\u002Fhome\"",[3563,4959,3624],{"class":3583},[3563,4961,4962],{"class":3645},"\"user\"",[3563,4964,3624],{"class":3583},[3563,4966,4967],{"class":3645},"\"project\"",[3563,4969,3936],{"class":3583},[3394,4971,4972,4974],{},[3406,4973,4893],{}," якщо з великого модуля потрібні 1-3 конкретних об'єкти, і імена не конфліктують з локальними.",[4831,4976,4978,5073],{"label":4977},"import module as alias",[3554,4979,4981],{"className":3556,"code":4980,"language":3558,"meta":3559,"style":3559},"import calculator as calc\nimport numpy as np          # галузева конвенція\nimport matplotlib.pyplot as plt  # галузева конвенція\nimport pandas as pd\n\nresult = calc.add(2, 3)\narray = np.array([1, 2, 3])\n",[3398,4982,4983,4995,5010,5024,5036,5040,5054],{"__ignoreMap":3559},[3563,4984,4985,4987,4989,4992],{"class":3565,"line":3566},[3563,4986,3905],{"class":3652},[3563,4988,4910],{"class":3583},[3563,4990,4991],{"class":3652},"as",[3563,4993,4994],{"class":3583}," calc\n",[3563,4996,4997,4999,5002,5004,5007],{"class":3565,"line":3573},[3563,4998,3905],{"class":3652},[3563,5000,5001],{"class":3583}," numpy ",[3563,5003,4991],{"class":3652},[3563,5005,5006],{"class":3583}," np          ",[3563,5008,5009],{"class":3569},"# галузева конвенція\n",[3563,5011,5012,5014,5017,5019,5022],{"class":3565,"line":3580},[3563,5013,3905],{"class":3652},[3563,5015,5016],{"class":3583}," matplotlib.pyplot ",[3563,5018,4991],{"class":3652},[3563,5020,5021],{"class":3583}," plt  ",[3563,5023,5009],{"class":3569},[3563,5025,5026,5028,5031,5033],{"class":3565,"line":3594},[3563,5027,3905],{"class":3652},[3563,5029,5030],{"class":3583}," pandas ",[3563,5032,4991],{"class":3652},[3563,5034,5035],{"class":3583}," pd\n",[3563,5037,5038],{"class":3565,"line":3599},[3563,5039,3577],{"emptyLinePlaceholder":3576},[3563,5041,5042,5045,5047,5049,5052],{"class":3565,"line":3642},[3563,5043,5044],{"class":3583},"result = calc.add(",[3563,5046,4209],{"class":3587},[3563,5048,3624],{"class":3583},[3563,5050,5051],{"class":3587},"3",[3563,5053,3936],{"class":3583},[3563,5055,5056,5059,5062,5064,5066,5068,5070],{"class":3565,"line":3649},[3563,5057,5058],{"class":3583},"array = np.array([",[3563,5060,5061],{"class":3587},"1",[3563,5063,3624],{"class":3583},[3563,5065,4209],{"class":3587},[3563,5067,3624],{"class":3583},[3563,5069,5051],{"class":3587},[3563,5071,5072],{"class":3583},"])\n",[3394,5074,5075,5077],{},[3406,5076,4893],{}," якщо ім'я модуля довге або є загальноприйнятий псевдонім у спільноті.",[4831,5079,5081,5132,5137],{"label":5080},"⚠️ from module import \\*",[3554,5082,5084],{"className":3556,"code":5083,"language":3558,"meta":3559,"style":3559},"# ❌ НІКОЛИ НЕ РОБІТЬ ТАК У PRODUCTION-КОДІ\nfrom calculator import *\n\n# Тепер у просторі імен є: add, subtract, multiply, circle_area, PI\n# Але звідки вони взялися? Невідомо без читання calculator.py\nresult = add(5, 5)  # яка це функція? наша? із calculator? з іншого модуля?\n",[3398,5085,5086,5091,5102,5106,5111,5116],{"__ignoreMap":3559},[3563,5087,5088],{"class":3565,"line":3566},[3563,5089,5090],{"class":3569},"# ❌ НІКОЛИ НЕ РОБІТЬ ТАК У PRODUCTION-КОДІ\n",[3563,5092,5093,5095,5097,5099],{"class":3565,"line":3573},[3563,5094,4907],{"class":3652},[3563,5096,4910],{"class":3583},[3563,5098,3905],{"class":3652},[3563,5100,5101],{"class":3583}," *\n",[3563,5103,5104],{"class":3565,"line":3580},[3563,5105,3577],{"emptyLinePlaceholder":3576},[3563,5107,5108],{"class":3565,"line":3594},[3563,5109,5110],{"class":3569},"# Тепер у просторі імен є: add, subtract, multiply, circle_area, PI\n",[3563,5112,5113],{"class":3565,"line":3599},[3563,5114,5115],{"class":3569},"# Але звідки вони взялися? Невідомо без читання calculator.py\n",[3563,5117,5118,5120,5122,5124,5126,5129],{"class":3565,"line":3642},[3563,5119,4941],{"class":3583},[3563,5121,3933],{"class":3587},[3563,5123,3624],{"class":3583},[3563,5125,3933],{"class":3587},[3563,5127,5128],{"class":3583},")  ",[3563,5130,5131],{"class":3569},"# яка це функція? наша? із calculator? з іншого модуля?\n",[3394,5133,5134],{},[3406,5135,5136],{},"Чому це погано:",[5138,5139,5140,5143,5152],"ul",{},[3508,5141,5142],{},"Забруднює простір імен непередбачуваною кількістю імен",[3508,5144,5145,5146,5148,5149,5151],{},"Гарантовані приховані конфлікти: якщо ",[3398,5147,3545],{}," і ваш код мають функцію ",[3398,5150,4084],{},", одна мовчки перезапише іншу",[3508,5153,5154],{},"IDE та статичні аналізатори не можуть розібратися у таких імпортах",[3468,5156,5158,5159,5162],{"id":5157},"конвенція-_private-приватні-атрибути-модуля","Конвенція ",[3398,5160,5161],{},"_private",": приватні атрибути модуля",[3394,5164,5165,5166,4310,5169,5172,5173,3459],{},"У Python немає ключових слів ",[3398,5167,5168],{},"private",[3398,5170,5171],{},"protected",". Натомість існує конвенція: ",[3406,5174,5175,5176,5179],{},"ім'я, що починається з одного підкреслення (",[3398,5177,5178],{},"_name","), є сигналом «не призначене для публічного використання»",[3554,5181,5183],{"className":3556,"code":5182,"language":3558,"meta":3559,"style":3559},"# calculator.py\nPI = 3.14159          # публічний атрибут ✅\n_precision = 10       # «приватний» атрибут — для внутрішнього використання\n\ndef add(a, b):        # публічна функція ✅\n    return a + b\n\ndef _validate(x):     # «приватна» функція — деталь реалізації\n    return isinstance(x, (int, float))\n",[3398,5184,5185,5190,5200,5210,5214,5234,5240,5244,5262],{"__ignoreMap":3559},[3563,5186,5187],{"class":3565,"line":3566},[3563,5188,5189],{"class":3569},"# calculator.py\n",[3563,5191,5192,5194,5197],{"class":3565,"line":3573},[3563,5193,3584],{"class":3583},[3563,5195,5196],{"class":3587},"3.14159",[3563,5198,5199],{"class":3569},"          # публічний атрибут ✅\n",[3563,5201,5202,5205,5207],{"class":3565,"line":3580},[3563,5203,5204],{"class":3583},"_precision = ",[3563,5206,3928],{"class":3587},[3563,5208,5209],{"class":3569},"       # «приватний» атрибут — для внутрішнього використання\n",[3563,5211,5212],{"class":3565,"line":3594},[3563,5213,3577],{"emptyLinePlaceholder":3576},[3563,5215,5216,5218,5220,5222,5224,5226,5228,5231],{"class":3565,"line":3599},[3563,5217,3603],{"class":3602},[3563,5219,3607],{"class":3606},[3563,5221,3610],{"class":3583},[3563,5223,3614],{"class":3613},[3563,5225,3624],{"class":3583},[3563,5227,3627],{"class":3613},[3563,5229,5230],{"class":3583},"):        ",[3563,5232,5233],{"class":3569},"# публічна функція ✅\n",[3563,5235,5236,5238],{"class":3565,"line":3642},[3563,5237,3653],{"class":3652},[3563,5239,3656],{"class":3583},[3563,5241,5242],{"class":3565,"line":3649},[3563,5243,3577],{"emptyLinePlaceholder":3576},[3563,5245,5246,5248,5251,5253,5256,5259],{"class":3565,"line":3659},[3563,5247,3603],{"class":3602},[3563,5249,5250],{"class":3606}," _validate",[3563,5252,3610],{"class":3583},[3563,5254,5255],{"class":3613},"x",[3563,5257,5258],{"class":3583},"):     ",[3563,5260,5261],{"class":3569},"# «приватна» функція — деталь реалізації\n",[3563,5263,5264,5266,5269,5271,5273,5275,5277],{"class":3565,"line":3664},[3563,5265,3653],{"class":3652},[3563,5267,5268],{"class":3606}," isinstance",[3563,5270,3864],{"class":3583},[3563,5272,3867],{"class":3620},[3563,5274,3624],{"class":3583},[3563,5276,3621],{"class":3620},[3563,5278,5279],{"class":3583},"))\n",[3394,5281,5282,5283,5286],{},"Технічно ",[3398,5284,5285],{},"calculator._validate(5)"," спрацює без помилок — Python лише сигналізує, але не забороняє. Проте конвенція дотримується всією екосистемою: IDE підсвічують такий виклик, linter-и видають попередження, а рецензенти коду запитають: «Навіщо ти лізеш у внутрішності чужого модуля?»",[3394,5288,5289,5290,5292,5293,5296,5297,5300,5301,3459],{},"Ця конвенція також впливає на ",[3398,5291,4256],{},": якщо ваш модуль не визначає ",[3398,5294,5295],{},"__all__",", зірковий імпорт ",[3406,5298,5299],{},"пропускає"," всі імена з підкресленням — це одна з небагатьох корисних властивостей ",[3398,5302,5303],{},"import *",[3461,5305],{},[3389,5307,5309,5310,5312],{"id":5308},"система-пошуку-модулів-syspath-зсередини","Система пошуку модулів: ",[3398,5311,3517],{}," зсередини",[3468,5314,5316,5317],{"id":5315},"алгоритм-пошуку-import","Алгоритм пошуку ",[3398,5318,3905],{},[3394,5320,5321,5322,5325,5326,5329,5330,5332],{},"Коли Python зустрічає ",[3398,5323,5324],{},"import my_module",", він не шукає файл одразу по всій файловій системі. Він послідовно перевіряє ",[3406,5327,5328],{},"ієрархічний список директорій",", що зберігається у ",[3398,5331,3517],{}," — списку рядків, де кожен рядок є абсолютним шляхом до директорії.",[4359,5334,5335],{},[3554,5336,5338],{"className":4363,"code":5337,"language":4365,"meta":3559,"style":3559},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\n\nstart\n\n:Python зустрічає: import my_module;\n\n:Перевірити sys.modules[\"my_module\"];\n\nif (знайдено у кеші?) then (Так)\n    :Повернути кешований об'єкт модуля;\n    stop\nelse (Ні)\n    :Ітерація по sys.path;\n    note right\n      sys.path — це список:\n      1. Директорія поточного скрипта\n      2. Шляхи з PYTHONPATH\n      3. Стандартна бібліотека\n      4. site-packages (pip)\n    end note\nendif\n\n:Для кожного шляху в sys.path:;\n\nif (my_module.py існує у шляху?) then (Так)\n    :Компілювати у байткод (.pyc);\n    :Створити об'єкт types.ModuleType;\n    :Виконати байткод у просторі імен модуля;\n    :Зберегти у sys.modules[\"my_module\"];\n    :Прив'язати ім'я my_module у поточному просторі;\n    stop\nelse (Ні)\n    :Перейти до наступного шляху;\n    if (Вичерпано усі шляхи?) then (Так)\n        :Підняти ModuleNotFoundError;\n        stop\n    else (Ні)\n        :Продовжити пошук;\n    endif\nendif\n@enduml\n",[3398,5339,5340,5344,5348,5352,5356,5360,5365,5369,5374,5378,5383,5387,5392,5397,5402,5407,5412,5417,5422,5427,5432,5437,5442,5447,5452,5456,5461,5466,5472,5478,5484,5490,5496,5502,5507,5512,5518,5524,5530,5536,5542,5548,5554,5559],{"__ignoreMap":3559},[3563,5341,5342],{"class":3565,"line":3566},[3563,5343,4372],{},[3563,5345,5346],{"class":3565,"line":3573},[3563,5347,4377],{},[3563,5349,5350],{"class":3565,"line":3580},[3563,5351,4382],{},[3563,5353,5354],{"class":3565,"line":3594},[3563,5355,4387],{},[3563,5357,5358],{"class":3565,"line":3599},[3563,5359,3577],{"emptyLinePlaceholder":3576},[3563,5361,5362],{"class":3565,"line":3642},[3563,5363,5364],{},"start\n",[3563,5366,5367],{"class":3565,"line":3649},[3563,5368,3577],{"emptyLinePlaceholder":3576},[3563,5370,5371],{"class":3565,"line":3659},[3563,5372,5373],{},":Python зустрічає: import my_module;\n",[3563,5375,5376],{"class":3565,"line":3664},[3563,5377,3577],{"emptyLinePlaceholder":3576},[3563,5379,5380],{"class":3565,"line":3694},[3563,5381,5382],{},":Перевірити sys.modules[\"my_module\"];\n",[3563,5384,5385],{"class":3565,"line":3700},[3563,5386,3577],{"emptyLinePlaceholder":3576},[3563,5388,5389],{"class":3565,"line":3708},[3563,5390,5391],{},"if (знайдено у кеші?) then (Так)\n",[3563,5393,5394],{"class":3565,"line":3713},[3563,5395,5396],{},"    :Повернути кешований об'єкт модуля;\n",[3563,5398,5399],{"class":3565,"line":3743},[3563,5400,5401],{},"    stop\n",[3563,5403,5404],{"class":3565,"line":3749},[3563,5405,5406],{},"else (Ні)\n",[3563,5408,5409],{"class":3565,"line":3757},[3563,5410,5411],{},"    :Ітерація по sys.path;\n",[3563,5413,5414],{"class":3565,"line":3762},[3563,5415,5416],{},"    note right\n",[3563,5418,5419],{"class":3565,"line":3785},[3563,5420,5421],{},"      sys.path — це список:\n",[3563,5423,5424],{"class":3565,"line":3791},[3563,5425,5426],{},"      1. Директорія поточного скрипта\n",[3563,5428,5429],{"class":3565,"line":3802},[3563,5430,5431],{},"      2. Шляхи з PYTHONPATH\n",[3563,5433,5434],{"class":3565,"line":3807},[3563,5435,5436],{},"      3. Стандартна бібліотека\n",[3563,5438,5439],{"class":3565,"line":3828},[3563,5440,5441],{},"      4. site-packages (pip)\n",[3563,5443,5444],{"class":3565,"line":3834},[3563,5445,5446],{},"    end note\n",[3563,5448,5449],{"class":3565,"line":3840},[3563,5450,5451],{},"endif\n",[3563,5453,5454],{"class":3565,"line":3846},[3563,5455,3577],{"emptyLinePlaceholder":3576},[3563,5457,5458],{"class":3565,"line":3851},[3563,5459,5460],{},":Для кожного шляху в sys.path:;\n",[3563,5462,5464],{"class":3565,"line":5463},27,[3563,5465,3577],{"emptyLinePlaceholder":3576},[3563,5467,5469],{"class":3565,"line":5468},28,[3563,5470,5471],{},"if (my_module.py існує у шляху?) then (Так)\n",[3563,5473,5475],{"class":3565,"line":5474},29,[3563,5476,5477],{},"    :Компілювати у байткод (.pyc);\n",[3563,5479,5481],{"class":3565,"line":5480},30,[3563,5482,5483],{},"    :Створити об'єкт types.ModuleType;\n",[3563,5485,5487],{"class":3565,"line":5486},31,[3563,5488,5489],{},"    :Виконати байткод у просторі імен модуля;\n",[3563,5491,5493],{"class":3565,"line":5492},32,[3563,5494,5495],{},"    :Зберегти у sys.modules[\"my_module\"];\n",[3563,5497,5499],{"class":3565,"line":5498},33,[3563,5500,5501],{},"    :Прив'язати ім'я my_module у поточному просторі;\n",[3563,5503,5505],{"class":3565,"line":5504},34,[3563,5506,5401],{},[3563,5508,5510],{"class":3565,"line":5509},35,[3563,5511,5406],{},[3563,5513,5515],{"class":3565,"line":5514},36,[3563,5516,5517],{},"    :Перейти до наступного шляху;\n",[3563,5519,5521],{"class":3565,"line":5520},37,[3563,5522,5523],{},"    if (Вичерпано усі шляхи?) then (Так)\n",[3563,5525,5527],{"class":3565,"line":5526},38,[3563,5528,5529],{},"        :Підняти ModuleNotFoundError;\n",[3563,5531,5533],{"class":3565,"line":5532},39,[3563,5534,5535],{},"        stop\n",[3563,5537,5539],{"class":3565,"line":5538},40,[3563,5540,5541],{},"    else (Ні)\n",[3563,5543,5545],{"class":3565,"line":5544},41,[3563,5546,5547],{},"        :Продовжити пошук;\n",[3563,5549,5551],{"class":3565,"line":5550},42,[3563,5552,5553],{},"    endif\n",[3563,5555,5557],{"class":3565,"line":5556},43,[3563,5558,5451],{},[3563,5560,5562],{"class":3565,"line":5561},44,[3563,5563,4470],{},[3468,5565,5567,5568,5570],{"id":5566},"анатомія-syspath-що-там-насправді","Анатомія ",[3398,5569,3517],{},": що там насправді",[3554,5572,5574],{"className":3556,"code":5573,"language":3558,"meta":3559,"style":3559},"import sys\n\nprint(f\"Тип sys.path: {type(sys.path)}\")  # \u003Cclass 'list'>\nprint(f\"Кількість шляхів: {len(sys.path)}\")\n\nfor i, path in enumerate(sys.path):\n    print(f\"  [{i}] {path}\")\n",[3398,5575,5576,5582,5586,5614,5638,5642,5657],{"__ignoreMap":3559},[3563,5577,5578,5580],{"class":3565,"line":3566},[3563,5579,3905],{"class":3652},[3563,5581,4857],{"class":3583},[3563,5583,5584],{"class":3565,"line":3573},[3563,5585,3577],{"emptyLinePlaceholder":3576},[3563,5587,5588,5590,5592,5594,5597,5599,5602,5605,5607,5609,5611],{"class":3565,"line":3580},[3563,5589,3955],{"class":3606},[3563,5591,3610],{"class":3583},[3563,5593,3960],{"class":3602},[3563,5595,5596],{"class":3645},"\"Тип sys.path: ",[3563,5598,3966],{"class":3602},[3563,5600,5601],{"class":3620},"type",[3563,5603,5604],{"class":3583},"(sys.path)",[3563,5606,3972],{"class":3602},[3563,5608,3975],{"class":3645},[3563,5610,5128],{"class":3583},[3563,5612,5613],{"class":3569},"# \u003Cclass 'list'>\n",[3563,5615,5616,5618,5620,5622,5625,5627,5630,5632,5634,5636],{"class":3565,"line":3594},[3563,5617,3955],{"class":3606},[3563,5619,3610],{"class":3583},[3563,5621,3960],{"class":3602},[3563,5623,5624],{"class":3645},"\"Кількість шляхів: ",[3563,5626,3966],{"class":3602},[3563,5628,5629],{"class":3606},"len",[3563,5631,5604],{"class":3583},[3563,5633,3972],{"class":3602},[3563,5635,3975],{"class":3645},[3563,5637,3936],{"class":3583},[3563,5639,5640],{"class":3565,"line":3599},[3563,5641,3577],{"emptyLinePlaceholder":3576},[3563,5643,5644,5646,5649,5651,5654],{"class":3565,"line":3642},[3563,5645,3877],{"class":3652},[3563,5647,5648],{"class":3583}," i, path ",[3563,5650,3883],{"class":3652},[3563,5652,5653],{"class":3606}," enumerate",[3563,5655,5656],{"class":3583},"(sys.path):\n",[3563,5658,5659,5662,5664,5666,5669,5671,5674,5676,5679,5681,5684,5686,5688],{"class":3565,"line":3649},[3563,5660,5661],{"class":3606},"    print",[3563,5663,3610],{"class":3583},[3563,5665,3960],{"class":3602},[3563,5667,5668],{"class":3645},"\"  [",[3563,5670,3966],{"class":3602},[3563,5672,5673],{"class":3583},"i",[3563,5675,3972],{"class":3602},[3563,5677,5678],{"class":3645},"] ",[3563,5680,3966],{"class":3602},[3563,5682,5683],{"class":3583},"path",[3563,5685,3972],{"class":3602},[3563,5687,3975],{"class":3645},[3563,5689,3936],{"class":3583},[4032,5691,5693,5701,5709,5718,5732,5740,5752,5760,5772],{"title":5692},"python inspect_path.py",[4036,5694,5696,4044,5699],{"className":5695},[3565],[3563,5697,4043],{"className":5698},[4042],[3406,5700,5692],{},[4036,5702,5704,5705],{"className":5703},[3565],"Тип sys.path: ",[3563,5706,5708],{"className":5707},[4071],"\u003Cclass 'list'>",[4036,5710,5712,5713],{"className":5711},[3565],"Кількість шляхів: ",[3563,5714,5717],{"className":5715},[5716],"text-yellow-400","6",[4036,5719,5721,5722,5726,5727],{"className":5720},[3565],"  [0] ",[3563,5723,5725],{"className":5724},[4054],"\u002Fhome\u002Fuser\u002Fmyproject","  ",[3563,5728,5731],{"className":5729},[5730],"text-gray-400","# директорія запущеного скрипта",[4036,5733,5735,5736],{"className":5734},[3565],"  [1] ",[3563,5737,5739],{"className":5738},[5730],"\u002Fusr\u002Flib\u002Fpython312.zip",[4036,5741,5743,5744,5726,5748],{"className":5742},[3565],"  [2] ",[3563,5745,5747],{"className":5746},[4071],"\u002Fusr\u002Flib\u002Fpython3.12",[3563,5749,5751],{"className":5750},[5730],"# стандартна бібліотека",[4036,5753,5755,5756],{"className":5754},[3565],"  [3] ",[3563,5757,5759],{"className":5758},[4071],"\u002Fusr\u002Flib\u002Fpython3.12\u002Flib-dynload",[4036,5761,5763,5764,5726,5768],{"className":5762},[3565],"  [4] ",[3563,5765,5767],{"className":5766},[4054],"\u002Fhome\u002Fuser\u002F.venv\u002Flib\u002Fpython3.12\u002Fsite-packages",[3563,5769,5771],{"className":5770},[5730],"# pip-пакети",[4036,5773,5775,5776],{"className":5774},[3565],"  [5] ",[3563,5777,5779],{"className":5778},[4071],"\u002Fusr\u002Flib\u002Fpython3\u002Fdist-packages",[3394,5781,5782,5788],{},[3406,5783,5784,5785,5787],{},"Звідки формується ",[3398,5786,3517],{},"?"," Це не магія — список складається з кількох джерел у визначеному порядку пріоритету:",[5790,5791,5792,5827,5839,5858],"field-group",{},[5793,5794,5797,5798,5801,5802,5805,5806,5808,5809,5811,5812,5814,5815,5818,5819,5822,5823,5826],"field",{"name":5795,"type":5796},"sys.path[0] — директорія скрипта","string","При запуску ",[3398,5799,5800],{},"python \u002Fhome\u002Fuser\u002Fproject\u002Fmain.py"," Python автоматично ставить на перше місце ",[3398,5803,5804],{},"\u002Fhome\u002Fuser\u002Fproject\u002F",". Саме тому ",[3398,5807,3502],{}," працює, якщо ",[3398,5810,3513],{}," лежить поруч з ",[3398,5813,3400],{},". При запуску через ",[3398,5816,5817],{},"-m"," або в інтерактивному режимі ",[3398,5820,5821],{},"sys.path[0]"," дорівнює ",[3398,5824,5825],{},"''"," (порожній рядок = поточна директорія shell).",[5793,5828,5831,5832,5835,5836,5838],{"name":5829,"type":5830},"PYTHONPATH — змінна середовища","list[str]","Якщо встановлена змінна середовища ",[3398,5833,5834],{},"PYTHONPATH=\u002Fmy\u002Flibs:\u002Fother\u002Flibs",", Python вставляє ці шляхи після ",[3398,5837,5821],{},". Це спосіб глобально зареєструвати власні бібліотеки без встановлення через pip. Рідко потрібен у сучасних проектах з venv.",[5793,5840,5842,5843,3624,5846,3624,5849,3624,5852,5855,5856,3459],{"name":5841,"type":5830},"Стандартна бібліотека","Шляхи до вбудованих модулів Python: ",[3398,5844,5845],{},"os",[3398,5847,5848],{},"sys",[3398,5850,5851],{},"json",[3398,5853,5854],{},"datetime"," тощо. Їхнє точне розташування залежить від ОС та версії Python, але вони завжди присутні у ",[3398,5857,3517],{},[5793,5859,5861,5862,5865,5866,5869,5870,5873,5874,3624,5877,3624,5880,3459],{"name":5860,"type":5830},"site-packages — pip-пакети","Директорія, куди ",[3398,5863,5864],{},"pip install"," встановлює сторонні пакети. Зазвичай знаходиться у ",[3398,5867,5868],{},"~\u002F.local\u002Flib\u002FpythonX.Y\u002Fsite-packages\u002F"," (глобально) або ",[3398,5871,5872],{},"venv\u002Flib\u002FpythonX.Y\u002Fsite-packages\u002F"," (у venv). Саме тут лежать ваші ",[3398,5875,5876],{},"requests",[3398,5878,5879],{},"Django",[3398,5881,5882],{},"numpy",[3468,5884,5886,5887,5889],{"id":5885},"маніпуляції-з-syspath-коли-і-як","Маніпуляції з ",[3398,5888,3517],{},": коли і як",[3394,5891,5892,5894],{},[3398,5893,3517],{}," — це звичайний Python-список, тому його можна змінювати в рантаймі. Це дає потужні (і небезпечні) можливості:",[3554,5896,5898],{"className":3556,"code":5897,"language":3558,"meta":3559,"style":3559},"import sys\n\n# Додати власний шлях перед усіма іншими (найвищий пріоритет)\nsys.path.insert(0, '\u002Fpath\u002Fto\u002Fmy\u002Fcustom\u002Flibs')\n\n# Або в кінець (найнижчий пріоритет)\nsys.path.append('\u002Fpath\u002Fto\u002Ffallback\u002Flibs')\n\n# Тепер Python шукатиме модулі і там\nimport my_custom_module  # знайде у \u002Fpath\u002Fto\u002Fmy\u002Fcustom\u002Flibs\n",[3398,5899,5900,5906,5910,5915,5930,5934,5939,5949,5953,5958],{"__ignoreMap":3559},[3563,5901,5902,5904],{"class":3565,"line":3566},[3563,5903,3905],{"class":3652},[3563,5905,4857],{"class":3583},[3563,5907,5908],{"class":3565,"line":3573},[3563,5909,3577],{"emptyLinePlaceholder":3576},[3563,5911,5912],{"class":3565,"line":3580},[3563,5913,5914],{"class":3569},"# Додати власний шлях перед усіма іншими (найвищий пріоритет)\n",[3563,5916,5917,5920,5923,5925,5928],{"class":3565,"line":3594},[3563,5918,5919],{"class":3583},"sys.path.insert(",[3563,5921,5922],{"class":3587},"0",[3563,5924,3624],{"class":3583},[3563,5926,5927],{"class":3645},"'\u002Fpath\u002Fto\u002Fmy\u002Fcustom\u002Flibs'",[3563,5929,3936],{"class":3583},[3563,5931,5932],{"class":3565,"line":3599},[3563,5933,3577],{"emptyLinePlaceholder":3576},[3563,5935,5936],{"class":3565,"line":3642},[3563,5937,5938],{"class":3569},"# Або в кінець (найнижчий пріоритет)\n",[3563,5940,5941,5944,5947],{"class":3565,"line":3649},[3563,5942,5943],{"class":3583},"sys.path.append(",[3563,5945,5946],{"class":3645},"'\u002Fpath\u002Fto\u002Ffallback\u002Flibs'",[3563,5948,3936],{"class":3583},[3563,5950,5951],{"class":3565,"line":3659},[3563,5952,3577],{"emptyLinePlaceholder":3576},[3563,5954,5955],{"class":3565,"line":3664},[3563,5956,5957],{"class":3569},"# Тепер Python шукатиме модулі і там\n",[3563,5959,5960,5962,5965],{"class":3565,"line":3694},[3563,5961,3905],{"class":3652},[3563,5963,5964],{"class":3583}," my_custom_module  ",[3563,5966,5967],{"class":3569},"# знайде у \u002Fpath\u002Fto\u002Fmy\u002Fcustom\u002Flibs\n",[5969,5970,5971,5976,5977,5979,5980,5983,5984,5987],"warning",{},[3406,5972,5886,5973,5975],{},[3398,5974,3517],{}," у production-коді — антипатерн."," Якщо ви додаєте шлях до ",[3398,5978,3517],{}," у своєму коді, це означає, що ваша структура проекту або система встановлення пакетів налаштована неправильно. Правильне рішення — використовувати ",[3398,5981,5982],{},"pip install -e ."," для локальної розробки або коректно структурований пакет. ",[3398,5985,5986],{},"sys.path.append(...)"," допустимий лише у тимчасових скриптах та скриптах налагодження.",[3394,5989,5990,5991,5994,5995,5998,5999,6001,6002,6004,6005,6007],{},"Альтернатива — файл ",[3398,5992,5993],{},".pth"," у директорії ",[3398,5996,5997],{},"site-packages",": Python автоматично читає всі ",[3398,6000,5993],{},"-файли при запуску та додає зазначені в них шляхи до ",[3398,6003,3517],{},". Команда ",[3398,6006,5982],{}," (editable install) використовує саме цей механізм.",[4287,6009,6011],{"id":6010},"як-влаштований-імпорт-під-капотом-finder-та-loader","Як влаштований імпорт під капотом: Finder та Loader",[3394,6013,6014,6015,6017,6018,4481,6021,6024],{},"Багато розробників думають, що ",[3398,6016,3905],{}," — це просто пошук файлу на диску. Насправді Python використовує складну, але дуже гнучку двохетапну систему імпорту, що базується на ",[3406,6019,6020],{},"пошуковцях (Finders)",[3406,6022,6023],{},"завантажувачах (Loaders)",". Ця система повністю документована у PEP 302.",[3394,6026,6027,6028,6030],{},"Коли ви викликаєте ",[3398,6029,5324],{},", виконуються такі кроки:",[3505,6032,6033,6075],{},[3508,6034,6035,6038,6039,6042,6043,6067,6070,6071,6074],{},[3406,6036,6037],{},"Пошук модуля (Find Phase)",":\nPython проходить по списку пошуковців, що зберігаються в ",[3398,6040,6041],{},"sys.meta_path",". Типово там містяться:",[5138,6044,6045,6053,6059],{},[3508,6046,6047,6050,6051,4354],{},[3398,6048,6049],{},"BuiltinImporter"," (для вбудованих модулів, наприклад, ",[3398,6052,5848],{},[3508,6054,6055,6058],{},[3398,6056,6057],{},"FrozenImporter"," (для \"заморожених\" модулів, написаних на C і скомпільованих у двійковий файл інтерпретатора).",[3508,6060,6061,6064,6065,4354],{},[3398,6062,6063],{},"PathFinder"," (шукає файли на диску за шляхами із ",[3398,6066,3517],{},[6068,6069],"br",{},"Кожен пошуковець намагається знайти модуль. Якщо знаходить, він повертає спеціальний об'єкт — специфікацію модуля (",[3398,6072,6073],{},"ModuleSpec","), яка містить метадані: ім'я модуля, посилання на завантажувач та шлях до файлу.",[3508,6076,6077,6080,6081,6083,6084,6087,6088],{},[3406,6078,6079],{},"Завантаження модуля (Load Phase)",":\nОтримавши ",[3398,6082,6073],{},", Python викликає відповідний завантажувач (",[3398,6085,6086],{},"Loader","). Завантажувач:",[5138,6089,6090,6093,6098],{},[3508,6091,6092],{},"Створює порожній об'єкт модуля.",[3508,6094,6095,6096,3459],{},"Записує його в ",[3398,6097,3496],{},[3508,6099,6100],{},"Виконує код файлу модуля в контексті цього об'єкта.",[3394,6102,6103],{},"Цей механізм дозволяє розробникам писати власні імпортери (import hooks). Наприклад, можна написати Finder\u002FLoader, який імпортує модулі безпосередньо з ZIP-архівів, бази даних або навіть завантажує їх через HTTP з віддаленого сервера!",[4287,6105,6107,6108,6110],{"id":6106},"що-таке-pth-файли","Що таке ",[3398,6109,5993],{},"-файли",[3394,6112,6113,6114,6116,6117,6119,6120,3459],{},"Файли з розширенням ",[3398,6115,5993],{}," (path configuration files) — це дуже простий і зручний спосіб додавання шляхів до ",[3398,6118,3517],{}," без ручного редагування коду або налаштування змінної ",[3398,6121,6122],{},"PYTHONPATH",[3394,6124,6125,6126,6129,6130,6132,6133,3459],{},"Якщо покласти файл ",[3398,6127,6128],{},"my_paths.pth"," у директорію ",[3398,6131,5997],{}," вашого віртуального середовища, Python під час ініціалізації прочитає його рядки і додасть усі вказані там шляхи до ",[3398,6134,3517],{},[3394,6136,6137,6138,6140,6141,6144],{},"Кожен рядок у ",[3398,6139,5993],{},"-файлі має містити один абсолютний або відносний шлях. Якщо рядок починається з ",[3398,6142,6143],{},"import ",", Python навіть виконає цей код (це використовується деякими складними бібліотеками для автоналаштування).",[3394,6146,6147,6148,6150,6151,3624,6153,6156,6157,6159],{},"Саме цей механізм використовується при встановленні локального пакета в \"режимі редагування\":\n",[3398,6149,5982],{},"\nЗамість того, щоб копіювати файли вашого проекту в ",[3398,6152,5997],{},[3398,6154,6155],{},"pip"," просто створює там ",[3398,6158,5993],{},"-файл, який містить шлях до вашої робочої директорії. Це дозволяє вам редагувати код, і зміни будуть миттєво видимі без повторного встановлення пакета.",[3461,6161],{},[3389,6163,6165,6166,6168],{"id":6164},"кешування-імпортів-sysmodules-та-singleton-поведінка","Кешування імпортів: ",[3398,6167,3496],{}," та Singleton-поведінка",[3468,6170,6172],{"id":6171},"чому-модуль-завантажується-лише-один-раз","Чому модуль завантажується лише один раз",[3394,6174,6175,6176,3624,6178,3624,6180,6182,6183,6186],{},"Python є мовою, де один і той самий модуль (",[3398,6177,5845],{},[3398,6179,5851],{},[3398,6181,5854],{},") може бути імпортований у десятках різних файлів одного проекту. Якби кожен ",[3398,6184,6185],{},"import os"," перечитував файл з диска та виконував байткод заново — продуктивність була б катастрофічною.",[3394,6188,6189,6190,6193,6194,6196],{},"Рішення — ",[3406,6191,6192],{},"кеш модулів",": словник ",[3398,6195,3496],{},", що зберігає всі вже завантажені модулі.",[3554,6198,6200],{"className":3556,"code":6199,"language":3558,"meta":3559,"style":3559},"# main.py — демонстрація кешування\nimport sys\n\nprint(\"=== Перший імпорт ===\")\nimport calculator  # \u003C— тут: файл читається, байткод виконується\n\nprint(\"\\n=== Другий імпорт ===\")\nimport calculator  # \u003C— тут: Python бачить 'calculator' у sys.modules → пропускає\n\nprint(\"\\n=== Третій імпорт ===\")\nimport calculator  # \u003C— те саме: кеш-хіт, нульова вартість\n\nprint(f\"\\n'calculator' у кеші? {'calculator' in sys.modules}\")\n\n# Отримати об'єкт модуля з кешу напряму\ncached = sys.modules['calculator']\nprint(f\"Той самий об'єкт? {calculator is cached}\")   # True\nprint(f\"Виклик через кеш: {cached.add(1, 2)}\")        # 3\n",[3398,6201,6202,6207,6213,6217,6228,6237,6241,6256,6265,6269,6284,6293,6297,6329,6333,6338,6348,6380],{"__ignoreMap":3559},[3563,6203,6204],{"class":3565,"line":3566},[3563,6205,6206],{"class":3569},"# main.py — демонстрація кешування\n",[3563,6208,6209,6211],{"class":3565,"line":3573},[3563,6210,3905],{"class":3652},[3563,6212,4857],{"class":3583},[3563,6214,6215],{"class":3565,"line":3580},[3563,6216,3577],{"emptyLinePlaceholder":3576},[3563,6218,6219,6221,6223,6226],{"class":3565,"line":3594},[3563,6220,3955],{"class":3606},[3563,6222,3610],{"class":3583},[3563,6224,6225],{"class":3645},"\"=== Перший імпорт ===\"",[3563,6227,3936],{"class":3583},[3563,6229,6230,6232,6234],{"class":3565,"line":3599},[3563,6231,3905],{"class":3652},[3563,6233,3908],{"class":3583},[3563,6235,6236],{"class":3569},"# \u003C— тут: файл читається, байткод виконується\n",[3563,6238,6239],{"class":3565,"line":3642},[3563,6240,3577],{"emptyLinePlaceholder":3576},[3563,6242,6243,6245,6247,6249,6251,6254],{"class":3565,"line":3649},[3563,6244,3955],{"class":3606},[3563,6246,3610],{"class":3583},[3563,6248,3975],{"class":3645},[3563,6250,4647],{"class":4646},[3563,6252,6253],{"class":3645},"=== Другий імпорт ===\"",[3563,6255,3936],{"class":3583},[3563,6257,6258,6260,6262],{"class":3565,"line":3659},[3563,6259,3905],{"class":3652},[3563,6261,3908],{"class":3583},[3563,6263,6264],{"class":3569},"# \u003C— тут: Python бачить 'calculator' у sys.modules → пропускає\n",[3563,6266,6267],{"class":3565,"line":3664},[3563,6268,3577],{"emptyLinePlaceholder":3576},[3563,6270,6271,6273,6275,6277,6279,6282],{"class":3565,"line":3694},[3563,6272,3955],{"class":3606},[3563,6274,3610],{"class":3583},[3563,6276,3975],{"class":3645},[3563,6278,4647],{"class":4646},[3563,6280,6281],{"class":3645},"=== Третій імпорт ===\"",[3563,6283,3936],{"class":3583},[3563,6285,6286,6288,6290],{"class":3565,"line":3700},[3563,6287,3905],{"class":3652},[3563,6289,3908],{"class":3583},[3563,6291,6292],{"class":3569},"# \u003C— те саме: кеш-хіт, нульова вартість\n",[3563,6294,6295],{"class":3565,"line":3708},[3563,6296,3577],{"emptyLinePlaceholder":3576},[3563,6298,6299,6301,6303,6305,6307,6309,6312,6314,6317,6320,6323,6325,6327],{"class":3565,"line":3713},[3563,6300,3955],{"class":3606},[3563,6302,3610],{"class":3583},[3563,6304,3960],{"class":3602},[3563,6306,3975],{"class":3645},[3563,6308,4647],{"class":4646},[3563,6310,6311],{"class":3645},"'calculator' у кеші? ",[3563,6313,3966],{"class":3602},[3563,6315,6316],{"class":3645},"'calculator'",[3563,6318,6319],{"class":3602}," in",[3563,6321,6322],{"class":3583}," sys.modules",[3563,6324,3972],{"class":3602},[3563,6326,3975],{"class":3645},[3563,6328,3936],{"class":3583},[3563,6330,6331],{"class":3565,"line":3743},[3563,6332,3577],{"emptyLinePlaceholder":3576},[3563,6334,6335],{"class":3565,"line":3749},[3563,6336,6337],{"class":3569},"# Отримати об'єкт модуля з кешу напряму\n",[3563,6339,6340,6343,6345],{"class":3565,"line":3757},[3563,6341,6342],{"class":3583},"cached = sys.modules[",[3563,6344,6316],{"class":3645},[3563,6346,6347],{"class":3583},"]\n",[3563,6349,6350,6352,6354,6356,6359,6361,6364,6367,6370,6372,6374,6377],{"class":3565,"line":3762},[3563,6351,3955],{"class":3606},[3563,6353,3610],{"class":3583},[3563,6355,3960],{"class":3602},[3563,6357,6358],{"class":3645},"\"Той самий об'єкт? ",[3563,6360,3966],{"class":3602},[3563,6362,6363],{"class":3583},"calculator ",[3563,6365,6366],{"class":3602},"is",[3563,6368,6369],{"class":3583}," cached",[3563,6371,3972],{"class":3602},[3563,6373,3975],{"class":3645},[3563,6375,6376],{"class":3583},")   ",[3563,6378,6379],{"class":3569},"# True\n",[3563,6381,6382,6384,6386,6388,6391,6393,6396,6398,6400,6402,6404,6406,6408,6411],{"class":3565,"line":3785},[3563,6383,3955],{"class":3606},[3563,6385,3610],{"class":3583},[3563,6387,3960],{"class":3602},[3563,6389,6390],{"class":3645},"\"Виклик через кеш: ",[3563,6392,3966],{"class":3602},[3563,6394,6395],{"class":3583},"cached.add(",[3563,6397,5061],{"class":3587},[3563,6399,3624],{"class":3583},[3563,6401,4209],{"class":3587},[3563,6403,3518],{"class":3583},[3563,6405,3972],{"class":3602},[3563,6407,3975],{"class":3645},[3563,6409,6410],{"class":3583},")        ",[3563,6412,6413],{"class":3569},"# 3\n",[4032,6415,6417,6425,6429,6440,6443,6447,6454,6457,6461,6467,6470,6477,6484],{"title":6416},"Кешування: модуль завантажується лише раз",[4036,6418,6420,4044,6423],{"className":6419},[3565],[3563,6421,4043],{"className":6422},[4042],[3406,6424,4034],{},[4036,6426,6428],{"className":6427},[3565],"=== Перший імпорт ===",[4036,6430,6432,5726,6436],{"className":6431},[3565],[3563,6433,6435],{"className":6434},[4071],"Модуль calculator завантажено!",[3563,6437,6439],{"className":6438},[5730],"# виводиться лише раз",[4036,6441],{"className":6442},[3565],[4036,6444,6446],{"className":6445},[3565],"=== Другий імпорт ===",[4036,6448,6450],{"className":6449},[3565],[3563,6451,6453],{"className":6452},[5730],"# нічого — кеш-хіт",[4036,6455],{"className":6456},[3565],[4036,6458,6460],{"className":6459},[3565],"=== Третій імпорт ===",[4036,6462,6464],{"className":6463},[3565],[3563,6465,6453],{"className":6466},[5730],[4036,6468],{"className":6469},[3565],[4036,6471,6311,6473],{"className":6472},[3565],[3563,6474,6476],{"className":6475},[4054],"True",[4036,6478,6480,6481],{"className":6479},[3565],"Той самий об'єкт? ",[3563,6482,6476],{"className":6483},[4054],[4036,6485,6487,6488],{"className":6486},[3565],"Виклик через кеш: ",[3563,6489,5051],{"className":6490},[5716],[4287,6492,6494,6495],{"id":6493},"експеримент-ручне-керування-кешем-у-sysmodules","Експеримент: ручне керування кешем у ",[3398,6496,3496],{},[3394,6498,6499,6500,6502,6503,6505],{},"Щоб краще зрозуміти роль ",[3398,6501,3496],{},", ми можемо втрутитися в його роботу безпосередньо. Якщо ми видалимо модуль із цього словника, Python \"забуде\", що він його колись імпортував, і при наступному ",[3398,6504,3905],{}," виконає код заново (так, ніби це перший імпорт).",[3554,6507,6509],{"className":3556,"code":6508,"language":3558,"meta":3559,"style":3559},"# sys_modules_experiment.py\nimport sys\n\nprint(\"--- Крок 1: Перший імпорт ---\")\nimport calculator  # Виведе повідомлення про завантаження\n\nprint(\"\\n--- Крок 2: Другий імпорт (кешований) ---\")\nimport calculator  # Нічого не виведе, оскільки calculator вже у sys.modules\n\n# Перевіряємо наявність у кеші\nprint(f\"\\ncalculator у sys.modules? {'calculator' in sys.modules}\")\n\nprint(\"\\n--- Крок 3: Видалення з sys.modules та повторний імпорт ---\")\n# Ручне видалення запису з кешу\ndel sys.modules['calculator']\n\nprint(f\"calculator у sys.modules після видалення? {'calculator' in sys.modules}\")\n\nimport calculator  # Python знову завантажує та виконує код модуля!\n",[3398,6510,6511,6516,6522,6526,6537,6546,6550,6565,6574,6578,6583,6612,6616,6631,6636,6648,6652,6677,6681],{"__ignoreMap":3559},[3563,6512,6513],{"class":3565,"line":3566},[3563,6514,6515],{"class":3569},"# sys_modules_experiment.py\n",[3563,6517,6518,6520],{"class":3565,"line":3573},[3563,6519,3905],{"class":3652},[3563,6521,4857],{"class":3583},[3563,6523,6524],{"class":3565,"line":3580},[3563,6525,3577],{"emptyLinePlaceholder":3576},[3563,6527,6528,6530,6532,6535],{"class":3565,"line":3594},[3563,6529,3955],{"class":3606},[3563,6531,3610],{"class":3583},[3563,6533,6534],{"class":3645},"\"--- Крок 1: Перший імпорт ---\"",[3563,6536,3936],{"class":3583},[3563,6538,6539,6541,6543],{"class":3565,"line":3599},[3563,6540,3905],{"class":3652},[3563,6542,3908],{"class":3583},[3563,6544,6545],{"class":3569},"# Виведе повідомлення про завантаження\n",[3563,6547,6548],{"class":3565,"line":3642},[3563,6549,3577],{"emptyLinePlaceholder":3576},[3563,6551,6552,6554,6556,6558,6560,6563],{"class":3565,"line":3649},[3563,6553,3955],{"class":3606},[3563,6555,3610],{"class":3583},[3563,6557,3975],{"class":3645},[3563,6559,4647],{"class":4646},[3563,6561,6562],{"class":3645},"--- Крок 2: Другий імпорт (кешований) ---\"",[3563,6564,3936],{"class":3583},[3563,6566,6567,6569,6571],{"class":3565,"line":3659},[3563,6568,3905],{"class":3652},[3563,6570,3908],{"class":3583},[3563,6572,6573],{"class":3569},"# Нічого не виведе, оскільки calculator вже у sys.modules\n",[3563,6575,6576],{"class":3565,"line":3664},[3563,6577,3577],{"emptyLinePlaceholder":3576},[3563,6579,6580],{"class":3565,"line":3694},[3563,6581,6582],{"class":3569},"# Перевіряємо наявність у кеші\n",[3563,6584,6585,6587,6589,6591,6593,6595,6598,6600,6602,6604,6606,6608,6610],{"class":3565,"line":3700},[3563,6586,3955],{"class":3606},[3563,6588,3610],{"class":3583},[3563,6590,3960],{"class":3602},[3563,6592,3975],{"class":3645},[3563,6594,4647],{"class":4646},[3563,6596,6597],{"class":3645},"calculator у sys.modules? ",[3563,6599,3966],{"class":3602},[3563,6601,6316],{"class":3645},[3563,6603,6319],{"class":3602},[3563,6605,6322],{"class":3583},[3563,6607,3972],{"class":3602},[3563,6609,3975],{"class":3645},[3563,6611,3936],{"class":3583},[3563,6613,6614],{"class":3565,"line":3708},[3563,6615,3577],{"emptyLinePlaceholder":3576},[3563,6617,6618,6620,6622,6624,6626,6629],{"class":3565,"line":3713},[3563,6619,3955],{"class":3606},[3563,6621,3610],{"class":3583},[3563,6623,3975],{"class":3645},[3563,6625,4647],{"class":4646},[3563,6627,6628],{"class":3645},"--- Крок 3: Видалення з sys.modules та повторний імпорт ---\"",[3563,6630,3936],{"class":3583},[3563,6632,6633],{"class":3565,"line":3743},[3563,6634,6635],{"class":3569},"# Ручне видалення запису з кешу\n",[3563,6637,6638,6641,6644,6646],{"class":3565,"line":3749},[3563,6639,6640],{"class":3652},"del",[3563,6642,6643],{"class":3583}," sys.modules[",[3563,6645,6316],{"class":3645},[3563,6647,6347],{"class":3583},[3563,6649,6650],{"class":3565,"line":3757},[3563,6651,3577],{"emptyLinePlaceholder":3576},[3563,6653,6654,6656,6658,6660,6663,6665,6667,6669,6671,6673,6675],{"class":3565,"line":3762},[3563,6655,3955],{"class":3606},[3563,6657,3610],{"class":3583},[3563,6659,3960],{"class":3602},[3563,6661,6662],{"class":3645},"\"calculator у sys.modules після видалення? ",[3563,6664,3966],{"class":3602},[3563,6666,6316],{"class":3645},[3563,6668,6319],{"class":3602},[3563,6670,6322],{"class":3583},[3563,6672,3972],{"class":3602},[3563,6674,3975],{"class":3645},[3563,6676,3936],{"class":3583},[3563,6678,6679],{"class":3565,"line":3785},[3563,6680,3577],{"emptyLinePlaceholder":3576},[3563,6682,6683,6685,6687],{"class":3565,"line":3791},[3563,6684,3905],{"class":3652},[3563,6686,3908],{"class":3583},[3563,6688,6689],{"class":3569},"# Python знову завантажує та виконує код модуля!\n",[4032,6691,6693,6701,6705,6711,6714,6718,6725,6728,6734,6737,6741,6750],{"title":6692},"python sys_modules_experiment.py",[4036,6694,6696,4044,6699],{"className":6695},[3565],[3563,6697,4043],{"className":6698},[4042],[3406,6700,6692],{},[4036,6702,6704],{"className":6703},[3565],"--- Крок 1: Перший імпорт ---",[4036,6706,6708],{"className":6707},[3565],[3563,6709,6435],{"className":6710},[4071],[4036,6712],{"className":6713},[3565],[4036,6715,6717],{"className":6716},[3565],"--- Крок 2: Другий імпорт (кешований) ---",[4036,6719,6721],{"className":6720},[3565],[3563,6722,6724],{"className":6723},[5730],"# Кеш-хіт: повторного виводу немає",[4036,6726],{"className":6727},[3565],[4036,6729,6597,6731],{"className":6730},[3565],[3563,6732,6476],{"className":6733},[4054],[4036,6735],{"className":6736},[3565],[4036,6738,6740],{"className":6739},[3565],"--- Крок 3: Видалення з sys.modules та повторний імпорт ---",[4036,6742,6744,6745],{"className":6743},[3565],"calculator у sys.modules після видалення? ",[3563,6746,6749],{"className":6747},[6748],"text-rose-400","False",[4036,6751,6753,5726,6756],{"className":6752},[3565],[3563,6754,6435],{"className":6755},[4071],[3563,6757,6759],{"className":6758},[5730],"# Код виконався знову!",[5969,6761,6762,6763,3624,6765,6771],{},"Хоча цей трюк демонструє роботу ",[3398,6764,3496],{},[3406,6766,6767,6768,6770],{},"ніколи не видаляйте модулі з ",[3398,6769,3496],{}," вручну в реальних проектах",". Це може зламати зв'язки між модулями та спричинити непередбачувані побічні ефекти (наприклад, якщо інші частини коду вже мають посилання на старий об'єкт модуля).",[3468,6773,6775,6777],{"id":6774},"sysmodules-як-singleton-реєстр-спільний-стан",[3398,6776,3496],{}," як Singleton-реєстр: спільний стан",[3394,6779,6780,6781,6784,6785,3459],{},"Той факт, що Python повертає ",[3406,6782,6783],{},"один і той самий об'єкт модуля"," всім імпортерам, породжує важливий архітектурний наслідок: ",[3406,6786,6787],{},"модуль з глобальними змінними веде себе як Singleton",[3554,6789,6791],{"className":3556,"code":6790,"language":3558,"meta":3559,"style":3559},"# state.py — модуль зі спільним станом\nprint(\"Ініціалізація state.py\")\nrequest_count = 0\nactive_connections = []\n\n# module_a.py — реєструє запити\nimport state\n\ndef handle_request(url: str) -> None:\n    state.request_count += 1\n    state.active_connections.append(url)\n    print(f\"[A] Запит #{state.request_count} до {url}\")\n\n# module_b.py — читає статистику\nimport state\n\ndef get_stats() -> dict:\n    return {\n        \"total\": state.request_count,\n        \"active\": len(state.active_connections)\n    }\n\n# main.py\nimport module_a\nimport module_b\n\nmodule_a.handle_request(\"\u002Fapi\u002Fusers\")\nmodule_a.handle_request(\"\u002Fapi\u002Fproducts\")\n\nstats = module_b.get_stats()\nprint(f\"Статистика: {stats}\")\n# {'total': 2, 'active': 2}\n# module_b бачить зміни, зроблені module_a!\n",[3398,6792,6793,6798,6809,6817,6822,6826,6831,6838,6842,6865,6873,6878,6909,6913,6918,6924,6928,6942,6949,6957,6969,6973,6977,6981,6988,6995,6999,7009,7018,7022,7027,7049,7054],{"__ignoreMap":3559},[3563,6794,6795],{"class":3565,"line":3566},[3563,6796,6797],{"class":3569},"# state.py — модуль зі спільним станом\n",[3563,6799,6800,6802,6804,6807],{"class":3565,"line":3573},[3563,6801,3955],{"class":3606},[3563,6803,3610],{"class":3583},[3563,6805,6806],{"class":3645},"\"Ініціалізація state.py\"",[3563,6808,3936],{"class":3583},[3563,6810,6811,6814],{"class":3565,"line":3580},[3563,6812,6813],{"class":3583},"request_count = ",[3563,6815,6816],{"class":3587},"0\n",[3563,6818,6819],{"class":3565,"line":3594},[3563,6820,6821],{"class":3583},"active_connections = []\n",[3563,6823,6824],{"class":3565,"line":3599},[3563,6825,3577],{"emptyLinePlaceholder":3576},[3563,6827,6828],{"class":3565,"line":3642},[3563,6829,6830],{"class":3569},"# module_a.py — реєструє запити\n",[3563,6832,6833,6835],{"class":3565,"line":3649},[3563,6834,3905],{"class":3652},[3563,6836,6837],{"class":3583}," state\n",[3563,6839,6840],{"class":3565,"line":3659},[3563,6841,3577],{"emptyLinePlaceholder":3576},[3563,6843,6844,6846,6849,6851,6854,6856,6858,6860,6863],{"class":3565,"line":3664},[3563,6845,3603],{"class":3602},[3563,6847,6848],{"class":3606}," handle_request",[3563,6850,3610],{"class":3583},[3563,6852,6853],{"class":3613},"url",[3563,6855,3617],{"class":3583},[3563,6857,4145],{"class":3620},[3563,6859,3634],{"class":3583},[3563,6861,6862],{"class":3602},"None",[3563,6864,3639],{"class":3583},[3563,6866,6867,6870],{"class":3565,"line":3694},[3563,6868,6869],{"class":3583},"    state.request_count += ",[3563,6871,6872],{"class":3587},"1\n",[3563,6874,6875],{"class":3565,"line":3700},[3563,6876,6877],{"class":3583},"    state.active_connections.append(url)\n",[3563,6879,6880,6882,6884,6886,6889,6891,6894,6896,6899,6901,6903,6905,6907],{"class":3565,"line":3708},[3563,6881,5661],{"class":3606},[3563,6883,3610],{"class":3583},[3563,6885,3960],{"class":3602},[3563,6887,6888],{"class":3645},"\"[A] Запит #",[3563,6890,3966],{"class":3602},[3563,6892,6893],{"class":3583},"state.request_count",[3563,6895,3972],{"class":3602},[3563,6897,6898],{"class":3645}," до ",[3563,6900,3966],{"class":3602},[3563,6902,6853],{"class":3583},[3563,6904,3972],{"class":3602},[3563,6906,3975],{"class":3645},[3563,6908,3936],{"class":3583},[3563,6910,6911],{"class":3565,"line":3713},[3563,6912,3577],{"emptyLinePlaceholder":3576},[3563,6914,6915],{"class":3565,"line":3743},[3563,6916,6917],{"class":3569},"# module_b.py — читає статистику\n",[3563,6919,6920,6922],{"class":3565,"line":3749},[3563,6921,3905],{"class":3652},[3563,6923,6837],{"class":3583},[3563,6925,6926],{"class":3565,"line":3757},[3563,6927,3577],{"emptyLinePlaceholder":3576},[3563,6929,6930,6932,6935,6938,6940],{"class":3565,"line":3762},[3563,6931,3603],{"class":3602},[3563,6933,6934],{"class":3606}," get_stats",[3563,6936,6937],{"class":3583},"() -> ",[3563,6939,4276],{"class":3620},[3563,6941,3639],{"class":3583},[3563,6943,6944,6946],{"class":3565,"line":3785},[3563,6945,3653],{"class":3652},[3563,6947,6948],{"class":3583}," {\n",[3563,6950,6951,6954],{"class":3565,"line":3791},[3563,6952,6953],{"class":3645},"        \"total\"",[3563,6955,6956],{"class":3583},": state.request_count,\n",[3563,6958,6959,6962,6964,6966],{"class":3565,"line":3802},[3563,6960,6961],{"class":3645},"        \"active\"",[3563,6963,3617],{"class":3583},[3563,6965,5629],{"class":3606},[3563,6967,6968],{"class":3583},"(state.active_connections)\n",[3563,6970,6971],{"class":3565,"line":3807},[3563,6972,4426],{"class":3583},[3563,6974,6975],{"class":3565,"line":3828},[3563,6976,3577],{"emptyLinePlaceholder":3576},[3563,6978,6979],{"class":3565,"line":3834},[3563,6980,4113],{"class":3569},[3563,6982,6983,6985],{"class":3565,"line":3840},[3563,6984,3905],{"class":3652},[3563,6986,6987],{"class":3583}," module_a\n",[3563,6989,6990,6992],{"class":3565,"line":3846},[3563,6991,3905],{"class":3652},[3563,6993,6994],{"class":3583}," module_b\n",[3563,6996,6997],{"class":3565,"line":3851},[3563,6998,3577],{"emptyLinePlaceholder":3576},[3563,7000,7001,7004,7007],{"class":3565,"line":5463},[3563,7002,7003],{"class":3583},"module_a.handle_request(",[3563,7005,7006],{"class":3645},"\"\u002Fapi\u002Fusers\"",[3563,7008,3936],{"class":3583},[3563,7010,7011,7013,7016],{"class":3565,"line":5468},[3563,7012,7003],{"class":3583},[3563,7014,7015],{"class":3645},"\"\u002Fapi\u002Fproducts\"",[3563,7017,3936],{"class":3583},[3563,7019,7020],{"class":3565,"line":5474},[3563,7021,3577],{"emptyLinePlaceholder":3576},[3563,7023,7024],{"class":3565,"line":5480},[3563,7025,7026],{"class":3583},"stats = module_b.get_stats()\n",[3563,7028,7029,7031,7033,7035,7038,7040,7043,7045,7047],{"class":3565,"line":5486},[3563,7030,3955],{"class":3606},[3563,7032,3610],{"class":3583},[3563,7034,3960],{"class":3602},[3563,7036,7037],{"class":3645},"\"Статистика: ",[3563,7039,3966],{"class":3602},[3563,7041,7042],{"class":3583},"stats",[3563,7044,3972],{"class":3602},[3563,7046,3975],{"class":3645},[3563,7048,3936],{"class":3583},[3563,7050,7051],{"class":3565,"line":5492},[3563,7052,7053],{"class":3569},"# {'total': 2, 'active': 2}\n",[3563,7055,7056],{"class":3565,"line":5498},[3563,7057,7058],{"class":3569},"# module_b бачить зміни, зроблені module_a!\n",[3394,7060,7061,7062,7065,7066,3440,7069,7071,7072,7075,7076,7079],{},"Обидва модулі отримали ",[3406,7063,7064],{},"одне й те саме посилання"," на об'єкт ",[3398,7067,7068],{},"state",[3398,7070,3496],{},". Зміни від ",[3398,7073,7074],{},"module_a"," одразу видимі у ",[3398,7077,7078],{},"module_b",". Це потужний механізм для глобальної конфігурації та стану, але він вимагає свідомого підходу — ненавмисні зміни глобальних змінних модуля є поширеним джерелом важко відтворюваних багів.",[3468,7081,7083,7084],{"id":7082},"перезавантаження-модуля-importlibreload","Перезавантаження модуля: ",[3398,7085,7086],{},"importlib.reload",[3394,7088,7089,7090,7092],{},"У нормальному виробничому коді кеш ",[3398,7091,3496],{}," є бажаною поведінкою. Але при інтерактивній розробці (Jupyter Notebook, REPL) виникає ситуація: ви змінили файл модуля, але Python все одно використовує стару закешовану версію.",[3554,7094,7096],{"className":3556,"code":7095,"language":3558,"meta":3559,"style":3559},"import importlib\nimport calculator\n\n# Поточна версія\nprint(calculator.add(1, 2))   # 3\n\n# ... ви зміни код calculator.py: add тепер повертає a + b + 100 ...\n\n# Звичайний import нічого не зробить:\nimport calculator\nprint(calculator.add(1, 2))   # все одно 3!\n\n# Примусово перезавантажити:\nimportlib.reload(calculator)\nprint(calculator.add(1, 2))   # тепер 103 ✅\n",[3398,7097,7098,7105,7111,7115,7120,7138,7142,7147,7151,7156,7162,7179,7183,7188,7193],{"__ignoreMap":3559},[3563,7099,7100,7102],{"class":3565,"line":3566},[3563,7101,3905],{"class":3652},[3563,7103,7104],{"class":3583}," importlib\n",[3563,7106,7107,7109],{"class":3565,"line":3573},[3563,7108,3905],{"class":3652},[3563,7110,4120],{"class":3583},[3563,7112,7113],{"class":3565,"line":3580},[3563,7114,3577],{"emptyLinePlaceholder":3576},[3563,7116,7117],{"class":3565,"line":3594},[3563,7118,7119],{"class":3569},"# Поточна версія\n",[3563,7121,7122,7124,7127,7129,7131,7133,7136],{"class":3565,"line":3599},[3563,7123,3955],{"class":3606},[3563,7125,7126],{"class":3583},"(calculator.add(",[3563,7128,5061],{"class":3587},[3563,7130,3624],{"class":3583},[3563,7132,4209],{"class":3587},[3563,7134,7135],{"class":3583},"))   ",[3563,7137,6413],{"class":3569},[3563,7139,7140],{"class":3565,"line":3642},[3563,7141,3577],{"emptyLinePlaceholder":3576},[3563,7143,7144],{"class":3565,"line":3649},[3563,7145,7146],{"class":3569},"# ... ви зміни код calculator.py: add тепер повертає a + b + 100 ...\n",[3563,7148,7149],{"class":3565,"line":3659},[3563,7150,3577],{"emptyLinePlaceholder":3576},[3563,7152,7153],{"class":3565,"line":3664},[3563,7154,7155],{"class":3569},"# Звичайний import нічого не зробить:\n",[3563,7157,7158,7160],{"class":3565,"line":3694},[3563,7159,3905],{"class":3652},[3563,7161,4120],{"class":3583},[3563,7163,7164,7166,7168,7170,7172,7174,7176],{"class":3565,"line":3700},[3563,7165,3955],{"class":3606},[3563,7167,7126],{"class":3583},[3563,7169,5061],{"class":3587},[3563,7171,3624],{"class":3583},[3563,7173,4209],{"class":3587},[3563,7175,7135],{"class":3583},[3563,7177,7178],{"class":3569},"# все одно 3!\n",[3563,7180,7181],{"class":3565,"line":3708},[3563,7182,3577],{"emptyLinePlaceholder":3576},[3563,7184,7185],{"class":3565,"line":3713},[3563,7186,7187],{"class":3569},"# Примусово перезавантажити:\n",[3563,7189,7190],{"class":3565,"line":3743},[3563,7191,7192],{"class":3583},"importlib.reload(calculator)\n",[3563,7194,7195,7197,7199,7201,7203,7205,7207],{"class":3565,"line":3749},[3563,7196,3955],{"class":3606},[3563,7198,7126],{"class":3583},[3563,7200,5061],{"class":3587},[3563,7202,3624],{"class":3583},[3563,7204,4209],{"class":3587},[3563,7206,7135],{"class":3583},[3563,7208,7209],{"class":3569},"# тепер 103 ✅\n",[3394,7211,7212,4044,7214,7217,7218,7220,7221,7224,7225,7228,7229,7232,7233,7235],{},[3398,7213,7086],{},[3406,7215,7216],{},"не видаляє"," об'єкт модуля з ",[3398,7219,3496],{}," — він повторно виконує код файлу в ",[3406,7222,7223],{},"тому ж самому"," об'єкті модуля, оновлюючи його атрибути. Це має важливе обмеження: якщо ви зробили ",[3398,7226,7227],{},"from calculator import add"," (імпорт із прив'язкою до локального імені), ",[3398,7230,7231],{},"reload(calculator)"," оновить модуль, але ваша локальна змінна ",[3398,7234,4084],{}," все одно вказуватиме на стару функцію.",[7237,7238,7239,7241,7242,7245],"caution",{},[3398,7240,7086],{}," — виключно ",[3406,7243,7244],{},"інструмент для розробки",". У production-коді перезавантаження модулів у рантаймі є джерелом важко передбачуваних помилок, пов'язаних із невідповідністю об'єктів, що були створені до і після reload. Не використовуйте його у фінальному коді.",[3461,7247],{},[3389,7249,7251,7252],{"id":7250},"подвійне-призначення-файлу-if-__name__-__main__","Подвійне призначення файлу: ",[3398,7253,7254],{},"if __name__ == \"__main__\"",[3468,7256,7258],{"id":7257},"як-python-визначає-хто-головний","Як Python визначає «хто головний»",[3394,7260,7261,7262,7265],{},"Кожен модуль Python несе атрибут ",[3398,7263,7264],{},"__name__",". Його значення залежить від того, в якому контексті виконується файл:",[5138,7267,7268,7282],{},[3508,7269,7270,7271,7274,7275,7278,7279],{},"Якщо файл ",[3406,7272,7273],{},"запускається напряму"," (",[3398,7276,7277],{},"python calculator.py","): ",[3398,7280,7281],{},"__name__ == \"__main__\"",[3508,7283,7270,7284,7287,7288,7291,7292,3518],{},[3406,7285,7286],{},"імпортується"," в інший модуль: ",[3398,7289,7290],{},"__name__ == \"calculator\""," (ім'я без ",[3398,7293,3481],{},[3394,7295,7296,7297,7300],{},"Це розмежування дозволяє одному файлу виконувати ",[3406,7298,7299],{},"дві різні ролі"," залежно від контексту: як самостійний скрипт із власною логікою запуску, і як бібліотека для інших модулів.",[3554,7302,7304],{"className":3556,"code":7303,"language":3558,"meta":3559,"style":3559},"# calculator.py\nPI = 3.14159\n\ndef add(a, b):\n    return a + b\n\ndef subtract(a, b):\n    return a - b\n\ndef _run_tests():\n    \"\"\"Вбудовані smoke-тести.\"\"\"\n    assert add(2, 3) == 5, \"add(2, 3) має дорівнювати 5\"\n    assert subtract(10, 3) == 7, \"subtract(10, 3) має дорівнювати 7\"\n    print(\"✅ Всі smoke-тести пройдено!\")\n\n# Цей блок виконується ЛИШЕ при запуску: python calculator.py\n# При import calculator — він повністю ігнорується\nif __name__ == \"__main__\":\n    print(f\"Запуск calculator.py як головного скрипта.\")\n    print(f\"Поточне __name__: {__name__}\")\n    _run_tests()\n",[3398,7305,7306,7310,7317,7321,7338,7344,7348,7364,7370,7374,7383,7388,7412,7435,7446,7450,7455,7460,7476,7489,7510],{"__ignoreMap":3559},[3563,7307,7308],{"class":3565,"line":3566},[3563,7309,5189],{"class":3569},[3563,7311,7312,7314],{"class":3565,"line":3573},[3563,7313,3584],{"class":3583},[3563,7315,7316],{"class":3587},"3.14159\n",[3563,7318,7319],{"class":3565,"line":3580},[3563,7320,3577],{"emptyLinePlaceholder":3576},[3563,7322,7323,7325,7327,7329,7331,7333,7335],{"class":3565,"line":3594},[3563,7324,3603],{"class":3602},[3563,7326,3607],{"class":3606},[3563,7328,3610],{"class":3583},[3563,7330,3614],{"class":3613},[3563,7332,3624],{"class":3583},[3563,7334,3627],{"class":3613},[3563,7336,7337],{"class":3583},"):\n",[3563,7339,7340,7342],{"class":3565,"line":3599},[3563,7341,3653],{"class":3652},[3563,7343,3656],{"class":3583},[3563,7345,7346],{"class":3565,"line":3642},[3563,7347,3577],{"emptyLinePlaceholder":3576},[3563,7349,7350,7352,7354,7356,7358,7360,7362],{"class":3565,"line":3649},[3563,7351,3603],{"class":3602},[3563,7353,3669],{"class":3606},[3563,7355,3610],{"class":3583},[3563,7357,3614],{"class":3613},[3563,7359,3624],{"class":3583},[3563,7361,3627],{"class":3613},[3563,7363,7337],{"class":3583},[3563,7365,7366,7368],{"class":3565,"line":3659},[3563,7367,3653],{"class":3652},[3563,7369,3705],{"class":3583},[3563,7371,7372],{"class":3565,"line":3664},[3563,7373,3577],{"emptyLinePlaceholder":3576},[3563,7375,7376,7378,7381],{"class":3565,"line":3694},[3563,7377,3603],{"class":3602},[3563,7379,7380],{"class":3606}," _run_tests",[3563,7382,4528],{"class":3583},[3563,7384,7385],{"class":3565,"line":3700},[3563,7386,7387],{"class":3645},"    \"\"\"Вбудовані smoke-тести.\"\"\"\n",[3563,7389,7390,7393,7396,7398,7400,7402,7405,7407,7409],{"class":3565,"line":3708},[3563,7391,7392],{"class":3652},"    assert",[3563,7394,7395],{"class":3583}," add(",[3563,7397,4209],{"class":3587},[3563,7399,3624],{"class":3583},[3563,7401,5051],{"class":3587},[3563,7403,7404],{"class":3583},") == ",[3563,7406,3933],{"class":3587},[3563,7408,3624],{"class":3583},[3563,7410,7411],{"class":3645},"\"add(2, 3) має дорівнювати 5\"\n",[3563,7413,7414,7416,7419,7421,7423,7425,7427,7430,7432],{"class":3565,"line":3713},[3563,7415,7392],{"class":3652},[3563,7417,7418],{"class":3583}," subtract(",[3563,7420,3928],{"class":3587},[3563,7422,3624],{"class":3583},[3563,7424,5051],{"class":3587},[3563,7426,7404],{"class":3583},[3563,7428,7429],{"class":3587},"7",[3563,7431,3624],{"class":3583},[3563,7433,7434],{"class":3645},"\"subtract(10, 3) має дорівнювати 7\"\n",[3563,7436,7437,7439,7441,7444],{"class":3565,"line":3743},[3563,7438,5661],{"class":3606},[3563,7440,3610],{"class":3583},[3563,7442,7443],{"class":3645},"\"✅ Всі smoke-тести пройдено!\"",[3563,7445,3936],{"class":3583},[3563,7447,7448],{"class":3565,"line":3749},[3563,7449,3577],{"emptyLinePlaceholder":3576},[3563,7451,7452],{"class":3565,"line":3757},[3563,7453,7454],{"class":3569},"# Цей блок виконується ЛИШЕ при запуску: python calculator.py\n",[3563,7456,7457],{"class":3565,"line":3762},[3563,7458,7459],{"class":3569},"# При import calculator — він повністю ігнорується\n",[3563,7461,7462,7465,7468,7471,7474],{"class":3565,"line":3785},[3563,7463,7464],{"class":3652},"if",[3563,7466,7467],{"class":3613}," __name__",[3563,7469,7470],{"class":3583}," == ",[3563,7472,7473],{"class":3645},"\"__main__\"",[3563,7475,3639],{"class":3583},[3563,7477,7478,7480,7482,7484,7487],{"class":3565,"line":3791},[3563,7479,5661],{"class":3606},[3563,7481,3610],{"class":3583},[3563,7483,3960],{"class":3602},[3563,7485,7486],{"class":3645},"\"Запуск calculator.py як головного скрипта.\"",[3563,7488,3936],{"class":3583},[3563,7490,7491,7493,7495,7497,7500,7502,7504,7506,7508],{"class":3565,"line":3802},[3563,7492,5661],{"class":3606},[3563,7494,3610],{"class":3583},[3563,7496,3960],{"class":3602},[3563,7498,7499],{"class":3645},"\"Поточне __name__: ",[3563,7501,3966],{"class":3602},[3563,7503,7264],{"class":3613},[3563,7505,3972],{"class":3602},[3563,7507,3975],{"class":3645},[3563,7509,3936],{"class":3583},[3563,7511,7512],{"class":3565,"line":3807},[3563,7513,7514],{"class":3583},"    _run_tests()\n",[4032,7516,7518,7530,7534,7542,7549,7552,7564,7571],{"title":7517},"Два контексти одного файлу",[4036,7519,7521,4044,7524,5726,7526],{"className":7520},[3565],[3563,7522,4043],{"className":7523},[4042],[3406,7525,7277],{},[3563,7527,7529],{"className":7528},[5730],"# запуск напряму",[4036,7531,7533],{"className":7532},[3565],"Запуск calculator.py як головного скрипта.",[4036,7535,7537,7538],{"className":7536},[3565],"Поточне __name__: ",[3563,7539,7541],{"className":7540},[4054],"__main__",[4036,7543,7545],{"className":7544},[3565],[3563,7546,7548],{"className":7547},[4054],"✅ Всі smoke-тести пройдено!",[4036,7550],{"className":7551},[3565],[4036,7553,7555,4044,7558,5726,7560],{"className":7554},[3565],[3563,7556,4043],{"className":7557},[4042],[3406,7559,4034],{},[3563,7561,7563],{"className":7562},[5730],"# main.py робить: import calculator",[4036,7565,7567],{"className":7566},[3565],[3563,7568,7570],{"className":7569},[5730],"# Нічого з if-блоку не виконується!",[4036,7572,7574,7575,5726,7578],{"className":7573},[3565],"calculator.__name__ == ",[3563,7576,6316],{"className":7577},[4071],[3563,7579,7581],{"className":7580},[5730],"# не __main__",[3468,7583,7585,7586,7589],{"id":7584},"патерн-main-структурований-точок-входу","Патерн ",[3398,7587,7588],{},"main()",": структурований точок входу",[3394,7591,7592,7593,7595,7596,7598],{},"Поєднання ",[3398,7594,7254],{}," зі спеціальною функцією ",[3398,7597,7588],{}," є галузевим стандартом для скриптів, що мають власну логіку виконання:",[3554,7600,7602],{"className":3556,"code":7601,"language":3558,"meta":3559,"style":3559},"# data_processor.py\nimport sys\nimport json\n\ndef load_data(filepath: str) -> dict:\n    \"\"\"Завантажує JSON з файлу.\"\"\"\n    with open(filepath) as f:\n        return json.load(f)\n\ndef process(data: dict) -> list:\n    \"\"\"Бізнес-логіка обробки даних.\"\"\"\n    return [item for item in data.get(\"items\", []) if item.get(\"active\")]\n\ndef save_results(results: list, output_path: str) -> None:\n    \"\"\"Зберігає результати.\"\"\"\n    with open(output_path, \"w\") as f:\n        json.dump(results, f, indent=2)\n\ndef main() -> int:\n    \"\"\"\n    Точка входу програми.\n    Повертає код завершення: 0 = успіх, 1 = помилка.\n    \"\"\"\n    if len(sys.argv) != 3:\n        print(f\"Використання: python {sys.argv[0]} \u003Cinput.json> \u003Coutput.json>\")\n        return 1\n\n    input_path = sys.argv[1]\n    output_path = sys.argv[2]\n\n    try:\n        data = load_data(input_path)\n        results = process(data)\n        save_results(results, output_path)\n        print(f\"✅ Оброблено {len(results)} записів → {output_path}\")\n        return 0\n    except FileNotFoundError as e:\n        print(f\"❌ Файл не знайдено: {e}\")\n        return 1\n    except json.JSONDecodeError as e:\n        print(f\"❌ Невалідний JSON: {e}\")\n        return 1\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())  # sys.exit передає код завершення в оболонку\n",[3398,7603,7604,7609,7615,7622,7626,7648,7653,7669,7677,7681,7703,7708,7742,7746,7777,7782,7800,7815,7819,7832,7836,7841,7846,7850,7865,7892,7899,7903,7912,7921,7925,7932,7937,7942,7947,7980,7987,8001,8023,8029,8040,8061,8067,8071,8075,8088],{"__ignoreMap":3559},[3563,7605,7606],{"class":3565,"line":3566},[3563,7607,7608],{"class":3569},"# data_processor.py\n",[3563,7610,7611,7613],{"class":3565,"line":3573},[3563,7612,3905],{"class":3652},[3563,7614,4857],{"class":3583},[3563,7616,7617,7619],{"class":3565,"line":3580},[3563,7618,3905],{"class":3652},[3563,7620,7621],{"class":3583}," json\n",[3563,7623,7624],{"class":3565,"line":3594},[3563,7625,3577],{"emptyLinePlaceholder":3576},[3563,7627,7628,7630,7633,7635,7638,7640,7642,7644,7646],{"class":3565,"line":3599},[3563,7629,3603],{"class":3602},[3563,7631,7632],{"class":3606}," load_data",[3563,7634,3610],{"class":3583},[3563,7636,7637],{"class":3613},"filepath",[3563,7639,3617],{"class":3583},[3563,7641,4145],{"class":3620},[3563,7643,3634],{"class":3583},[3563,7645,4276],{"class":3620},[3563,7647,3639],{"class":3583},[3563,7649,7650],{"class":3565,"line":3642},[3563,7651,7652],{"class":3645},"    \"\"\"Завантажує JSON з файлу.\"\"\"\n",[3563,7654,7655,7658,7661,7664,7666],{"class":3565,"line":3649},[3563,7656,7657],{"class":3652},"    with",[3563,7659,7660],{"class":3606}," open",[3563,7662,7663],{"class":3583},"(filepath) ",[3563,7665,4991],{"class":3652},[3563,7667,7668],{"class":3583}," f:\n",[3563,7670,7671,7674],{"class":3565,"line":3659},[3563,7672,7673],{"class":3652},"        return",[3563,7675,7676],{"class":3583}," json.load(f)\n",[3563,7678,7679],{"class":3565,"line":3664},[3563,7680,3577],{"emptyLinePlaceholder":3576},[3563,7682,7683,7685,7688,7690,7693,7695,7697,7699,7701],{"class":3565,"line":3694},[3563,7684,3603],{"class":3602},[3563,7686,7687],{"class":3606}," process",[3563,7689,3610],{"class":3583},[3563,7691,7692],{"class":3613},"data",[3563,7694,3617],{"class":3583},[3563,7696,4276],{"class":3620},[3563,7698,3634],{"class":3583},[3563,7700,4666],{"class":3620},[3563,7702,3639],{"class":3583},[3563,7704,7705],{"class":3565,"line":3700},[3563,7706,7707],{"class":3645},"    \"\"\"Бізнес-логіка обробки даних.\"\"\"\n",[3563,7709,7710,7712,7715,7717,7720,7722,7725,7728,7731,7733,7736,7739],{"class":3565,"line":3708},[3563,7711,3653],{"class":3652},[3563,7713,7714],{"class":3583}," [item ",[3563,7716,3877],{"class":3652},[3563,7718,7719],{"class":3583}," item ",[3563,7721,3883],{"class":3652},[3563,7723,7724],{"class":3583}," data.get(",[3563,7726,7727],{"class":3645},"\"items\"",[3563,7729,7730],{"class":3583},", []) ",[3563,7732,7464],{"class":3652},[3563,7734,7735],{"class":3583}," item.get(",[3563,7737,7738],{"class":3645},"\"active\"",[3563,7740,7741],{"class":3583},")]\n",[3563,7743,7744],{"class":3565,"line":3713},[3563,7745,3577],{"emptyLinePlaceholder":3576},[3563,7747,7748,7750,7753,7755,7758,7760,7762,7764,7767,7769,7771,7773,7775],{"class":3565,"line":3743},[3563,7749,3603],{"class":3602},[3563,7751,7752],{"class":3606}," save_results",[3563,7754,3610],{"class":3583},[3563,7756,7757],{"class":3613},"results",[3563,7759,3617],{"class":3583},[3563,7761,4666],{"class":3620},[3563,7763,3624],{"class":3583},[3563,7765,7766],{"class":3613},"output_path",[3563,7768,3617],{"class":3583},[3563,7770,4145],{"class":3620},[3563,7772,3634],{"class":3583},[3563,7774,6862],{"class":3602},[3563,7776,3639],{"class":3583},[3563,7778,7779],{"class":3565,"line":3749},[3563,7780,7781],{"class":3645},"    \"\"\"Зберігає результати.\"\"\"\n",[3563,7783,7784,7786,7788,7791,7794,7796,7798],{"class":3565,"line":3757},[3563,7785,7657],{"class":3652},[3563,7787,7660],{"class":3606},[3563,7789,7790],{"class":3583},"(output_path, ",[3563,7792,7793],{"class":3645},"\"w\"",[3563,7795,4005],{"class":3583},[3563,7797,4991],{"class":3652},[3563,7799,7668],{"class":3583},[3563,7801,7802,7805,7808,7811,7813],{"class":3565,"line":3762},[3563,7803,7804],{"class":3583},"        json.dump(results, f, ",[3563,7806,7807],{"class":3613},"indent",[3563,7809,7810],{"class":3583},"=",[3563,7812,4209],{"class":3587},[3563,7814,3936],{"class":3583},[3563,7816,7817],{"class":3565,"line":3785},[3563,7818,3577],{"emptyLinePlaceholder":3576},[3563,7820,7821,7823,7826,7828,7830],{"class":3565,"line":3791},[3563,7822,3603],{"class":3602},[3563,7824,7825],{"class":3606}," main",[3563,7827,6937],{"class":3583},[3563,7829,3867],{"class":3620},[3563,7831,3639],{"class":3583},[3563,7833,7834],{"class":3565,"line":3802},[3563,7835,3831],{"class":3645},[3563,7837,7838],{"class":3565,"line":3807},[3563,7839,7840],{"class":3645},"    Точка входу програми.\n",[3563,7842,7843],{"class":3565,"line":3828},[3563,7844,7845],{"class":3645},"    Повертає код завершення: 0 = успіх, 1 = помилка.\n",[3563,7847,7848],{"class":3565,"line":3834},[3563,7849,3831],{"class":3645},[3563,7851,7852,7855,7858,7861,7863],{"class":3565,"line":3840},[3563,7853,7854],{"class":3652},"    if",[3563,7856,7857],{"class":3606}," len",[3563,7859,7860],{"class":3583},"(sys.argv) != ",[3563,7862,5051],{"class":3587},[3563,7864,3639],{"class":3583},[3563,7866,7867,7869,7871,7873,7876,7878,7881,7883,7885,7887,7890],{"class":3565,"line":3846},[3563,7868,4572],{"class":3606},[3563,7870,3610],{"class":3583},[3563,7872,3960],{"class":3602},[3563,7874,7875],{"class":3645},"\"Використання: python ",[3563,7877,3966],{"class":3602},[3563,7879,7880],{"class":3583},"sys.argv[",[3563,7882,5922],{"class":3587},[3563,7884,4741],{"class":3583},[3563,7886,3972],{"class":3602},[3563,7888,7889],{"class":3645}," \u003Cinput.json> \u003Coutput.json>\"",[3563,7891,3936],{"class":3583},[3563,7893,7894,7896],{"class":3565,"line":3851},[3563,7895,7673],{"class":3652},[3563,7897,7898],{"class":3587}," 1\n",[3563,7900,7901],{"class":3565,"line":5463},[3563,7902,3577],{"emptyLinePlaceholder":3576},[3563,7904,7905,7908,7910],{"class":3565,"line":5468},[3563,7906,7907],{"class":3583},"    input_path = sys.argv[",[3563,7909,5061],{"class":3587},[3563,7911,6347],{"class":3583},[3563,7913,7914,7917,7919],{"class":3565,"line":5474},[3563,7915,7916],{"class":3583},"    output_path = sys.argv[",[3563,7918,4209],{"class":3587},[3563,7920,6347],{"class":3583},[3563,7922,7923],{"class":3565,"line":5480},[3563,7924,3577],{"emptyLinePlaceholder":3576},[3563,7926,7927,7930],{"class":3565,"line":5486},[3563,7928,7929],{"class":3652},"    try",[3563,7931,3639],{"class":3583},[3563,7933,7934],{"class":3565,"line":5492},[3563,7935,7936],{"class":3583},"        data = load_data(input_path)\n",[3563,7938,7939],{"class":3565,"line":5498},[3563,7940,7941],{"class":3583},"        results = process(data)\n",[3563,7943,7944],{"class":3565,"line":5504},[3563,7945,7946],{"class":3583},"        save_results(results, output_path)\n",[3563,7948,7949,7951,7953,7955,7958,7960,7962,7965,7967,7970,7972,7974,7976,7978],{"class":3565,"line":5509},[3563,7950,4572],{"class":3606},[3563,7952,3610],{"class":3583},[3563,7954,3960],{"class":3602},[3563,7956,7957],{"class":3645},"\"✅ Оброблено ",[3563,7959,3966],{"class":3602},[3563,7961,5629],{"class":3606},[3563,7963,7964],{"class":3583},"(results)",[3563,7966,3972],{"class":3602},[3563,7968,7969],{"class":3645}," записів → ",[3563,7971,3966],{"class":3602},[3563,7973,7766],{"class":3583},[3563,7975,3972],{"class":3602},[3563,7977,3975],{"class":3645},[3563,7979,3936],{"class":3583},[3563,7981,7982,7984],{"class":3565,"line":5514},[3563,7983,7673],{"class":3652},[3563,7985,7986],{"class":3587}," 0\n",[3563,7988,7989,7992,7995,7998],{"class":3565,"line":5520},[3563,7990,7991],{"class":3652},"    except",[3563,7993,7994],{"class":3620}," FileNotFoundError",[3563,7996,7997],{"class":3652}," as",[3563,7999,8000],{"class":3583}," e:\n",[3563,8002,8003,8005,8007,8009,8012,8014,8017,8019,8021],{"class":3565,"line":5526},[3563,8004,4572],{"class":3606},[3563,8006,3610],{"class":3583},[3563,8008,3960],{"class":3602},[3563,8010,8011],{"class":3645},"\"❌ Файл не знайдено: ",[3563,8013,3966],{"class":3602},[3563,8015,8016],{"class":3583},"e",[3563,8018,3972],{"class":3602},[3563,8020,3975],{"class":3645},[3563,8022,3936],{"class":3583},[3563,8024,8025,8027],{"class":3565,"line":5532},[3563,8026,7673],{"class":3652},[3563,8028,7898],{"class":3587},[3563,8030,8031,8033,8036,8038],{"class":3565,"line":5538},[3563,8032,7991],{"class":3652},[3563,8034,8035],{"class":3583}," json.JSONDecodeError ",[3563,8037,4991],{"class":3652},[3563,8039,8000],{"class":3583},[3563,8041,8042,8044,8046,8048,8051,8053,8055,8057,8059],{"class":3565,"line":5544},[3563,8043,4572],{"class":3606},[3563,8045,3610],{"class":3583},[3563,8047,3960],{"class":3602},[3563,8049,8050],{"class":3645},"\"❌ Невалідний JSON: ",[3563,8052,3966],{"class":3602},[3563,8054,8016],{"class":3583},[3563,8056,3972],{"class":3602},[3563,8058,3975],{"class":3645},[3563,8060,3936],{"class":3583},[3563,8062,8063,8065],{"class":3565,"line":5550},[3563,8064,7673],{"class":3652},[3563,8066,7898],{"class":3587},[3563,8068,8069],{"class":3565,"line":5556},[3563,8070,3577],{"emptyLinePlaceholder":3576},[3563,8072,8073],{"class":3565,"line":5561},[3563,8074,3577],{"emptyLinePlaceholder":3576},[3563,8076,8078,8080,8082,8084,8086],{"class":3565,"line":8077},45,[3563,8079,7464],{"class":3652},[3563,8081,7467],{"class":3613},[3563,8083,7470],{"class":3583},[3563,8085,7473],{"class":3645},[3563,8087,3639],{"class":3583},[3563,8089,8091,8094],{"class":3565,"line":8090},46,[3563,8092,8093],{"class":3583},"    sys.exit(main())  ",[3563,8095,8096],{"class":3569},"# sys.exit передає код завершення в оболонку\n",[3394,8098,8099,8100,8102,8103,8106,8107,8110,8111,3459],{},"Цей підхід дає три переваги: ",[3398,8101,7588],{}," є звичайною функцією, яку можна легко тестувати; ",[3398,8104,8105],{},"return 1"," \u002F ",[3398,8108,8109],{},"return 0"," дозволяє коректно сигналізувати про помилки в bash-скриптах; модуль залишається повністю придатним для ",[3398,8112,3905],{},[3468,8114,8116,8119],{"id":8115},"python-m-запуск-модуля-як-скрипта",[3398,8117,8118],{},"python -m",": запуск модуля як скрипта",[3394,8121,8122,8123,8126,8127,8130],{},"Окрім ",[3398,8124,8125],{},"python script.py",", Python підтримує синтаксис ",[3398,8128,8129],{},"python -m module_name",". Різниця тонка, але важлива:",[8132,8133,8134,8151],"table",{},[8135,8136,8137],"thead",{},[8138,8139,8140,8144,8148],"tr",{},[8141,8142,8143],"th",{},"Команда",[8141,8145,8146],{},[3398,8147,5821],{},[8141,8149,8150],{},"Для чого",[8152,8153,8154,8168,8184],"tbody",{},[8138,8155,8156,8162,8165],{},[8157,8158,8159],"td",{},[3398,8160,8161],{},"python path\u002Fto\u002Fscript.py",[8157,8163,8164],{},"директорія скрипта",[8157,8166,8167],{},"прості скрипти",[8138,8169,8170,8175,8181],{},[8157,8171,8172],{},[3398,8173,8174],{},"python -m package.module",[8157,8176,8177,8180],{},[3406,8178,8179],{},"коренева"," директорія проекту",[8157,8182,8183],{},"модулі всередині пакетів",[8138,8185,8186,8191,8194],{},[8157,8187,8188],{},[3398,8189,8190],{},"python -m venv .venv",[8157,8192,8193],{},"—",[8157,8195,8196],{},"вбудовані інструменти",[3394,8198,8199,8200,8202,8203,8205,8206,8209,8210,8213,8214,8217,8218,3459],{},"Прапорець ",[3398,8201,5817],{}," каже Python знайти модуль за ",[3398,8204,3517],{}," і запустити його з ",[3398,8207,8208],{},"__name__ = \"__main__\"",". Це критично для пакетів, де відносні імпорти (",[3398,8211,8212],{},"from .utils import helper",") не працюють при прямому ",[3398,8215,8216],{},"python package\u002Fmodule.py",", але коректно розв'язуються при ",[3398,8219,8174],{},[3461,8221],{},[3389,8223,8225],{"id":8224},"циклічні-імпорти-архітектурний-антипатерн","Циклічні імпорти: архітектурний антипатерн",[3468,8227,8229],{"id":8228},"як-виникає-циклічний-імпорт","Як виникає циклічний імпорт",[3394,8231,8232],{},"Циклічний імпорт виникає, коли модуль A імпортує модуль B, а модуль B імпортує модуль A (прямо чи через ланцюг інших модулів). Python обробляє цей сценарій, але результат часто несподіваний.",[3554,8234,8236],{"className":3556,"code":8235,"language":3558,"meta":3559,"style":3559},"# a.py\nprint(\"Завантаження a.py...\")\nimport b  # Python призупиняє a.py і завантажує b.py\n\ndef func_a():\n    b.func_b()\n    print(\"func_a виконана\")\n\nprint(\"a.py завантажено.\")\n\n# b.py\nprint(\"Завантаження b.py...\")\nimport a  # Python бачить: a вже є у sys.modules (частково!)\n\ndef func_b():\n    print(\"func_b виконана\")\n\nprint(\"b.py завантажено.\")\n\n# main.py\nimport a\na.func_a()  # AttributeError: partially initialized module 'b'...\n",[3398,8237,8238,8243,8254,8264,8268,8277,8282,8293,8297,8308,8312,8317,8328,8338,8342,8351,8362,8366,8377,8381,8385,8392],{"__ignoreMap":3559},[3563,8239,8240],{"class":3565,"line":3566},[3563,8241,8242],{"class":3569},"# a.py\n",[3563,8244,8245,8247,8249,8252],{"class":3565,"line":3573},[3563,8246,3955],{"class":3606},[3563,8248,3610],{"class":3583},[3563,8250,8251],{"class":3645},"\"Завантаження a.py...\"",[3563,8253,3936],{"class":3583},[3563,8255,8256,8258,8261],{"class":3565,"line":3580},[3563,8257,3905],{"class":3652},[3563,8259,8260],{"class":3583}," b  ",[3563,8262,8263],{"class":3569},"# Python призупиняє a.py і завантажує b.py\n",[3563,8265,8266],{"class":3565,"line":3594},[3563,8267,3577],{"emptyLinePlaceholder":3576},[3563,8269,8270,8272,8275],{"class":3565,"line":3599},[3563,8271,3603],{"class":3602},[3563,8273,8274],{"class":3606}," func_a",[3563,8276,4528],{"class":3583},[3563,8278,8279],{"class":3565,"line":3642},[3563,8280,8281],{"class":3583},"    b.func_b()\n",[3563,8283,8284,8286,8288,8291],{"class":3565,"line":3649},[3563,8285,5661],{"class":3606},[3563,8287,3610],{"class":3583},[3563,8289,8290],{"class":3645},"\"func_a виконана\"",[3563,8292,3936],{"class":3583},[3563,8294,8295],{"class":3565,"line":3659},[3563,8296,3577],{"emptyLinePlaceholder":3576},[3563,8298,8299,8301,8303,8306],{"class":3565,"line":3664},[3563,8300,3955],{"class":3606},[3563,8302,3610],{"class":3583},[3563,8304,8305],{"class":3645},"\"a.py завантажено.\"",[3563,8307,3936],{"class":3583},[3563,8309,8310],{"class":3565,"line":3694},[3563,8311,3577],{"emptyLinePlaceholder":3576},[3563,8313,8314],{"class":3565,"line":3700},[3563,8315,8316],{"class":3569},"# b.py\n",[3563,8318,8319,8321,8323,8326],{"class":3565,"line":3708},[3563,8320,3955],{"class":3606},[3563,8322,3610],{"class":3583},[3563,8324,8325],{"class":3645},"\"Завантаження b.py...\"",[3563,8327,3936],{"class":3583},[3563,8329,8330,8332,8335],{"class":3565,"line":3713},[3563,8331,3905],{"class":3652},[3563,8333,8334],{"class":3583}," a  ",[3563,8336,8337],{"class":3569},"# Python бачить: a вже є у sys.modules (частково!)\n",[3563,8339,8340],{"class":3565,"line":3743},[3563,8341,3577],{"emptyLinePlaceholder":3576},[3563,8343,8344,8346,8349],{"class":3565,"line":3749},[3563,8345,3603],{"class":3602},[3563,8347,8348],{"class":3606}," func_b",[3563,8350,4528],{"class":3583},[3563,8352,8353,8355,8357,8360],{"class":3565,"line":3757},[3563,8354,5661],{"class":3606},[3563,8356,3610],{"class":3583},[3563,8358,8359],{"class":3645},"\"func_b виконана\"",[3563,8361,3936],{"class":3583},[3563,8363,8364],{"class":3565,"line":3762},[3563,8365,3577],{"emptyLinePlaceholder":3576},[3563,8367,8368,8370,8372,8375],{"class":3565,"line":3785},[3563,8369,3955],{"class":3606},[3563,8371,3610],{"class":3583},[3563,8373,8374],{"class":3645},"\"b.py завантажено.\"",[3563,8376,3936],{"class":3583},[3563,8378,8379],{"class":3565,"line":3791},[3563,8380,3577],{"emptyLinePlaceholder":3576},[3563,8382,8383],{"class":3565,"line":3802},[3563,8384,4113],{"class":3569},[3563,8386,8387,8389],{"class":3565,"line":3807},[3563,8388,3905],{"class":3652},[3563,8390,8391],{"class":3583}," a\n",[3563,8393,8394,8397],{"class":3565,"line":3828},[3563,8395,8396],{"class":3583},"a.func_a()  ",[3563,8398,8399],{"class":3569},"# AttributeError: partially initialized module 'b'...\n",[3394,8401,8402],{},[3406,8403,8404],{},"Що відбувається покроково:",[4299,8406,8407,8414,8425,8431,8439,8448,8480,8486,8496,8502,8512,8523],{},[3468,8408,8410,8411],{"id":8409},"python-починає-виконувати-apy","Python починає виконувати ",[3398,8412,8413],{},"a.py",[3394,8415,8416,8417,8420,8421,8424],{},"Виводить ",[3398,8418,8419],{},"Завантаження a.py...",". Бачить ",[3398,8422,8423],{},"import b"," — призупиняється.",[3468,8426,8410,8428],{"id":8427},"python-починає-виконувати-bpy",[3398,8429,8430],{},"b.py",[3394,8432,8416,8433,8420,8436,3459],{},[3398,8434,8435],{},"Завантаження b.py...",[3398,8437,8438],{},"import a",[3468,8440,8442,8443,8445,8446],{"id":8441},"python-виявляє-a-у-sysmodules","Python виявляє ",[3398,8444,3614],{}," у ",[3398,8447,3496],{},[3394,8449,8450,8451,8453,8454,8457,8458,8460,8461,8464,8465,8467,8468,8471,8472,8475,8476,8479],{},"Але ",[3398,8452,3614],{}," ще ",[3406,8455,8456],{},"не повністю завантажений"," — він призупинений на рядку ",[3398,8459,8423],{},". Python не падає в рекурсію, а повертає ",[3406,8462,8463],{},"частковий"," об'єкт ",[3398,8466,3614],{},". На момент повернення у ",[3398,8469,8470],{},"a.__dict__"," ще немає ",[3398,8473,8474],{},"func_a"," (оголошення ",[3398,8477,8478],{},"def func_a()"," ще не виконане!).",[3468,8481,8483,8485],{"id":8482},"bpy-успішно-завантажується",[3398,8484,8430],{}," успішно завантажується",[3394,8487,8488,8489,8492,8493],{},"Визначає ",[3398,8490,8491],{},"func_b",", виводить ",[3398,8494,8495],{},"b.py завантажено.",[3468,8497,8499,8500],{"id":8498},"виконання-повертається-до-apy","Виконання повертається до ",[3398,8501,8413],{},[3394,8503,8504,8506,8507,8492,8509],{},[3398,8505,8413],{}," продовжує: визначає ",[3398,8508,8474],{},[3398,8510,8511],{},"a.py завантажено.",[3468,8513,8515,8516,8519,8520],{"id":8514},"виклик-afunc_a-bfunc_b","Виклик ",[3398,8517,8518],{},"a.func_a()"," → ",[3398,8521,8522],{},"b.func_b()",[3394,8524,8525,8526,8528,8529,8531],{},"Якщо ",[3398,8527,8430],{}," намагається використати щось з ",[3398,8530,3614],{}," на рівні модуля (не всередині функції), воно буде недоступне.",[4359,8533,8534],{},[3554,8535,8537],{"className":4363,"code":8536,"language":4365,"meta":3559,"style":3559},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\n\nparticipant \"Python\" as PY #f3f4f6\nparticipant \"a.py\\n(частково завантажений)\" as A #fef3c7\nparticipant \"b.py\" as B #d1fae5\nparticipant \"sys.modules\" as SM #e0e7ff\n\nPY -> A : Виконати a.py\nA -> SM : Зареєструвати a (частково)\nnote right of SM\n  sys.modules['a'] = \u003Cmodule a>\n  (але func_a ще не визначена!)\nend note\n\nA -> B : import b → виконати b.py\nB -> SM : Перевірити: 'a' у sys.modules?\nSM --> B : Так! Повернути частковий об'єкт a\nnote right of B\n  b.py отримує модуль a,\n  але у ньому немає func_a!\nend note\n\nB -> SM : Зареєструвати b (повністю)\nB --> A : import b завершено\nA -> SM : Оновити a (додати func_a)\n\nnote bottom of SM\n  Тепер a повний.\n  Але якщо b.py використовував a.func_a\n  на рівні модуля — вже пізно!\nend note\n@enduml\n",[3398,8538,8539,8543,8547,8551,8555,8559,8564,8569,8574,8579,8583,8588,8593,8598,8603,8608,8612,8616,8621,8626,8631,8636,8641,8646,8650,8654,8659,8664,8669,8673,8678,8683,8688,8693,8697],{"__ignoreMap":3559},[3563,8540,8541],{"class":3565,"line":3566},[3563,8542,4372],{},[3563,8544,8545],{"class":3565,"line":3573},[3563,8546,4377],{},[3563,8548,8549],{"class":3565,"line":3580},[3563,8550,4382],{},[3563,8552,8553],{"class":3565,"line":3594},[3563,8554,4387],{},[3563,8556,8557],{"class":3565,"line":3599},[3563,8558,3577],{"emptyLinePlaceholder":3576},[3563,8560,8561],{"class":3565,"line":3642},[3563,8562,8563],{},"participant \"Python\" as PY #f3f4f6\n",[3563,8565,8566],{"class":3565,"line":3649},[3563,8567,8568],{},"participant \"a.py\\n(частково завантажений)\" as A #fef3c7\n",[3563,8570,8571],{"class":3565,"line":3659},[3563,8572,8573],{},"participant \"b.py\" as B #d1fae5\n",[3563,8575,8576],{"class":3565,"line":3664},[3563,8577,8578],{},"participant \"sys.modules\" as SM #e0e7ff\n",[3563,8580,8581],{"class":3565,"line":3694},[3563,8582,3577],{"emptyLinePlaceholder":3576},[3563,8584,8585],{"class":3565,"line":3700},[3563,8586,8587],{},"PY -> A : Виконати a.py\n",[3563,8589,8590],{"class":3565,"line":3708},[3563,8591,8592],{},"A -> SM : Зареєструвати a (частково)\n",[3563,8594,8595],{"class":3565,"line":3713},[3563,8596,8597],{},"note right of SM\n",[3563,8599,8600],{"class":3565,"line":3743},[3563,8601,8602],{},"  sys.modules['a'] = \u003Cmodule a>\n",[3563,8604,8605],{"class":3565,"line":3749},[3563,8606,8607],{},"  (але func_a ще не визначена!)\n",[3563,8609,8610],{"class":3565,"line":3757},[3563,8611,4465],{},[3563,8613,8614],{"class":3565,"line":3762},[3563,8615,3577],{"emptyLinePlaceholder":3576},[3563,8617,8618],{"class":3565,"line":3785},[3563,8619,8620],{},"A -> B : import b → виконати b.py\n",[3563,8622,8623],{"class":3565,"line":3791},[3563,8624,8625],{},"B -> SM : Перевірити: 'a' у sys.modules?\n",[3563,8627,8628],{"class":3565,"line":3802},[3563,8629,8630],{},"SM --> B : Так! Повернути частковий об'єкт a\n",[3563,8632,8633],{"class":3565,"line":3807},[3563,8634,8635],{},"note right of B\n",[3563,8637,8638],{"class":3565,"line":3828},[3563,8639,8640],{},"  b.py отримує модуль a,\n",[3563,8642,8643],{"class":3565,"line":3834},[3563,8644,8645],{},"  але у ньому немає func_a!\n",[3563,8647,8648],{"class":3565,"line":3840},[3563,8649,4465],{},[3563,8651,8652],{"class":3565,"line":3846},[3563,8653,3577],{"emptyLinePlaceholder":3576},[3563,8655,8656],{"class":3565,"line":3851},[3563,8657,8658],{},"B -> SM : Зареєструвати b (повністю)\n",[3563,8660,8661],{"class":3565,"line":5463},[3563,8662,8663],{},"B --> A : import b завершено\n",[3563,8665,8666],{"class":3565,"line":5468},[3563,8667,8668],{},"A -> SM : Оновити a (додати func_a)\n",[3563,8670,8671],{"class":3565,"line":5474},[3563,8672,3577],{"emptyLinePlaceholder":3576},[3563,8674,8675],{"class":3565,"line":5480},[3563,8676,8677],{},"note bottom of SM\n",[3563,8679,8680],{"class":3565,"line":5486},[3563,8681,8682],{},"  Тепер a повний.\n",[3563,8684,8685],{"class":3565,"line":5492},[3563,8686,8687],{},"  Але якщо b.py використовував a.func_a\n",[3563,8689,8690],{"class":3565,"line":5498},[3563,8691,8692],{},"  на рівні модуля — вже пізно!\n",[3563,8694,8695],{"class":3565,"line":5504},[3563,8696,4465],{},[3563,8698,8699],{"class":3565,"line":5509},[3563,8700,4470],{},[3468,8702,8704],{"id":8703},"правильні-рішення","Правильні рішення",[3394,8706,8707],{},[3406,8708,8709],{},"Рішення 1 (найкраще): Рефакторинг — виділення спільного коду у третій модуль.",[3394,8711,8712],{},"Циклічний імпорт майже завжди є симптомом поганої архітектури: два модулі мають взаємні залежності, що означає, що вони не є незалежними одиницями. Правильне рішення — знайти спільний код і винести його у незалежний модуль.",[3554,8714,8719],{"className":8715,"code":8717,"language":8718},[8716],"language-text","❌ Погана архітектура:          ✅ Правильна архітектура:\n  a.py ←→ b.py                   shared.py (незалежний)\n                                  a.py → shared.py\n                                  b.py → shared.py, a.py\n","text",[3398,8720,8717],{"__ignoreMap":3559},[3394,8722,8723],{},[3406,8724,8725],{},"Рішення 2 (тимчасове): Локальний імпорт всередині функції.",[3554,8727,8729],{"className":3556,"code":8728,"language":3558,"meta":3559,"style":3559},"# a.py\ndef func_a():\n    import b  # ← імпорт всередині функції, відкладений до виклику\n    b.func_b()\n    print(\"func_a виконана\")\n",[3398,8730,8731,8735,8743,8753,8757],{"__ignoreMap":3559},[3563,8732,8733],{"class":3565,"line":3566},[3563,8734,8242],{"class":3569},[3563,8736,8737,8739,8741],{"class":3565,"line":3573},[3563,8738,3603],{"class":3602},[3563,8740,8274],{"class":3606},[3563,8742,4528],{"class":3583},[3563,8744,8745,8748,8750],{"class":3565,"line":3580},[3563,8746,8747],{"class":3652},"    import",[3563,8749,8260],{"class":3583},[3563,8751,8752],{"class":3569},"# ← імпорт всередині функції, відкладений до виклику\n",[3563,8754,8755],{"class":3565,"line":3594},[3563,8756,8281],{"class":3583},[3563,8758,8759,8761,8763,8765],{"class":3565,"line":3599},[3563,8760,5661],{"class":3606},[3563,8762,3610],{"class":3583},[3563,8764,8290],{"class":3645},[3563,8766,3936],{"class":3583},[3394,8768,8769,8770,8773,8774,8777,8778,8780],{},"Коли ",[3398,8771,8772],{},"func_a()"," буде викликана, обидва модулі вже будуть повністю завантажені, тому ",[3398,8775,8776],{},"b.func_b"," буде доступна. Але це «милиця» — вона ховає архітектурну проблему і уповільнює виклик функції (перевірка ",[3398,8779,3496],{}," при кожному виклику).",[3461,8782],{},[3389,8784,8786],{"id":8785},"частина-ii-пакети","Частина II: Пакети",[3468,8788,8790],{"id":8789},"від-модулів-до-ієрархії-навіщо-потрібні-пакети","Від модулів до ієрархії: навіщо потрібні пакети",[3394,8792,8793],{},"Коли проект виростає за межі кількох модулів, виникає нова проблема організації: навіть правильно розділений на модулі код перетворюється на хаотичний набір файлів, якщо всі вони лежать в одній директорії.",[3554,8795,8798],{"className":8796,"code":8797,"language":8718},[8716],"❌ Хаос без пакетів:          ✅ Структура з пакетами:\nmyproject\u002F                    myproject\u002F\n  main.py                       main.py\n  users.py                      users\u002F\n  user_auth.py                    __init__.py\n  user_profile.py                 auth.py\n  products.py                     profile.py\n  product_catalog.py            products\u002F\n  product_pricing.py              __init__.py\n  orders.py                       catalog.py\n  order_processing.py             pricing.py\n  order_notifications.py        orders\u002F\n  database.py                     __init__.py\n  api_client.py                   processing.py\n  utils.py                        notifications.py\n                                database.py\n                                utils.py\n",[3398,8799,8797],{"__ignoreMap":3559},[3394,8801,8802,8805,8806,8809],{},[3406,8803,8804],{},"Пакет"," — це директорія, що містить спеціальний файл ",[3398,8807,8808],{},"__init__.py",". Наявність цього файлу є сигналом для Python: «ця директорія — не просто папка, це модульна одиниця».",[3468,8811,8813],{"id":8812},"анатомія-пакета-реальний-проект-e-shop","Анатомія пакета: реальний проект e-shop",[3394,8815,8816],{},"Побудуємо повноцінний пакет для інтернет-магазину та дослідимо кожен його елемент:",[3551,8818,8819,8949,9352,9582,9605,9801],{},[3554,8820,8823],{"className":3556,"code":8821,"filename":8822,"language":3558,"meta":3559,"style":3559},"\"\"\"\nПакет 'shop' — ядро платформи інтернет-магазину.\nЦей файл виконується при першому import shop або import shop.anything.\n\"\"\"\nprint(\"Ініціалізація пакета shop...\")\n\n# Версія пакета — доступна як shop.__version__\n__version__ = \"1.0.0\"\n\n# Публічний API пакета: що буде доступно при 'from shop import *'\n__all__ = [\"get_product\", \"list_products\", \"get_customer\"]\n\n# \"Фасад\": імпортуємо ключові функції на рівень пакета\n# Тепер можна писати: import shop; shop.list_products()\n# замість: import shop.products; shop.products.list_products()\nfrom .products import list_products, get_product\nfrom .customers import get_customer\n","shop\u002F__init__.py",[3398,8824,8825,8830,8835,8840,8844,8855,8859,8864,8875,8879,8884,8906,8910,8915,8920,8925,8937],{"__ignoreMap":3559},[3563,8826,8827],{"class":3565,"line":3566},[3563,8828,8829],{"class":3645},"\"\"\"\n",[3563,8831,8832],{"class":3565,"line":3573},[3563,8833,8834],{"class":3645},"Пакет 'shop' — ядро платформи інтернет-магазину.\n",[3563,8836,8837],{"class":3565,"line":3580},[3563,8838,8839],{"class":3645},"Цей файл виконується при першому import shop або import shop.anything.\n",[3563,8841,8842],{"class":3565,"line":3594},[3563,8843,8829],{"class":3645},[3563,8845,8846,8848,8850,8853],{"class":3565,"line":3599},[3563,8847,3955],{"class":3606},[3563,8849,3610],{"class":3583},[3563,8851,8852],{"class":3645},"\"Ініціалізація пакета shop...\"",[3563,8854,3936],{"class":3583},[3563,8856,8857],{"class":3565,"line":3642},[3563,8858,3577],{"emptyLinePlaceholder":3576},[3563,8860,8861],{"class":3565,"line":3649},[3563,8862,8863],{"class":3569},"# Версія пакета — доступна як shop.__version__\n",[3563,8865,8866,8869,8872],{"class":3565,"line":3659},[3563,8867,8868],{"class":3613},"__version__",[3563,8870,8871],{"class":3583}," = ",[3563,8873,8874],{"class":3645},"\"1.0.0\"\n",[3563,8876,8877],{"class":3565,"line":3664},[3563,8878,3577],{"emptyLinePlaceholder":3576},[3563,8880,8881],{"class":3565,"line":3694},[3563,8882,8883],{"class":3569},"# Публічний API пакета: що буде доступно при 'from shop import *'\n",[3563,8885,8886,8888,8891,8894,8896,8899,8901,8904],{"class":3565,"line":3700},[3563,8887,5295],{"class":3613},[3563,8889,8890],{"class":3583}," = [",[3563,8892,8893],{"class":3645},"\"get_product\"",[3563,8895,3624],{"class":3583},[3563,8897,8898],{"class":3645},"\"list_products\"",[3563,8900,3624],{"class":3583},[3563,8902,8903],{"class":3645},"\"get_customer\"",[3563,8905,6347],{"class":3583},[3563,8907,8908],{"class":3565,"line":3708},[3563,8909,3577],{"emptyLinePlaceholder":3576},[3563,8911,8912],{"class":3565,"line":3713},[3563,8913,8914],{"class":3569},"# \"Фасад\": імпортуємо ключові функції на рівень пакета\n",[3563,8916,8917],{"class":3565,"line":3743},[3563,8918,8919],{"class":3569},"# Тепер можна писати: import shop; shop.list_products()\n",[3563,8921,8922],{"class":3565,"line":3749},[3563,8923,8924],{"class":3569},"# замість: import shop.products; shop.products.list_products()\n",[3563,8926,8927,8929,8932,8934],{"class":3565,"line":3757},[3563,8928,4907],{"class":3652},[3563,8930,8931],{"class":3583}," .products ",[3563,8933,3905],{"class":3652},[3563,8935,8936],{"class":3583}," list_products, get_product\n",[3563,8938,8939,8941,8944,8946],{"class":3565,"line":3762},[3563,8940,4907],{"class":3652},[3563,8942,8943],{"class":3583}," .customers ",[3563,8945,3905],{"class":3652},[3563,8947,8948],{"class":3583}," get_customer\n",[3554,8950,8953],{"className":3556,"code":8951,"filename":8952,"language":3558,"meta":3559,"style":3559},"\"\"\"Модуль для управління товарами.\"\"\"\n\n_products_db = [\n    {\"id\": 1, \"name\": \"Ноутбук\", \"price\": 35000, \"active\": True},\n    {\"id\": 2, \"name\": \"Миша\", \"price\": 850, \"active\": True},\n    {\"id\": 3, \"name\": \"Клавіатура\", \"price\": 2100, \"active\": False},\n]\n\ndef list_products(active_only: bool = True) -> list:\n    \"\"\"Повертає список товарів. За замовчуванням — тільки активні.\"\"\"\n    if active_only:\n        return [p for p in _products_db if p[\"active\"]]\n    return list(_products_db)\n\ndef get_product(product_id: int) -> dict | None:\n    \"\"\"Знаходить товар за ID або повертає None.\"\"\"\n    for product in _products_db:\n        if product[\"id\"] == product_id:\n            return product\n    return None\n\ndef calculate_price_with_vat(product_id: int, vat_rate: float = 0.20) -> float:\n    \"\"\"Розраховує ціну з ПДВ.\"\"\"\n    product = get_product(product_id)\n    if product is None:\n        raise ValueError(f\"Товар {product_id} не знайдено\")\n    return product[\"price\"] * (1 + vat_rate)\n","shop\u002Fproducts.py",[3398,8954,8955,8960,8964,8969,9012,9050,9088,9092,9096,9122,9127,9134,9161,9171,9175,9202,9207,9220,9233,9241,9248,9252,9287,9292,9297,9310,9336],{"__ignoreMap":3559},[3563,8956,8957],{"class":3565,"line":3566},[3563,8958,8959],{"class":3645},"\"\"\"Модуль для управління товарами.\"\"\"\n",[3563,8961,8962],{"class":3565,"line":3573},[3563,8963,3577],{"emptyLinePlaceholder":3576},[3563,8965,8966],{"class":3565,"line":3580},[3563,8967,8968],{"class":3583},"_products_db = [\n",[3563,8970,8971,8974,8977,8979,8981,8983,8986,8988,8991,8993,8996,8998,9001,9003,9005,9007,9009],{"class":3565,"line":3594},[3563,8972,8973],{"class":3583},"    {",[3563,8975,8976],{"class":3645},"\"id\"",[3563,8978,3617],{"class":3583},[3563,8980,5061],{"class":3587},[3563,8982,3624],{"class":3583},[3563,8984,8985],{"class":3645},"\"name\"",[3563,8987,3617],{"class":3583},[3563,8989,8990],{"class":3645},"\"Ноутбук\"",[3563,8992,3624],{"class":3583},[3563,8994,8995],{"class":3645},"\"price\"",[3563,8997,3617],{"class":3583},[3563,8999,9000],{"class":3587},"35000",[3563,9002,3624],{"class":3583},[3563,9004,7738],{"class":3645},[3563,9006,3617],{"class":3583},[3563,9008,6476],{"class":3602},[3563,9010,9011],{"class":3583},"},\n",[3563,9013,9014,9016,9018,9020,9022,9024,9026,9028,9031,9033,9035,9037,9040,9042,9044,9046,9048],{"class":3565,"line":3599},[3563,9015,8973],{"class":3583},[3563,9017,8976],{"class":3645},[3563,9019,3617],{"class":3583},[3563,9021,4209],{"class":3587},[3563,9023,3624],{"class":3583},[3563,9025,8985],{"class":3645},[3563,9027,3617],{"class":3583},[3563,9029,9030],{"class":3645},"\"Миша\"",[3563,9032,3624],{"class":3583},[3563,9034,8995],{"class":3645},[3563,9036,3617],{"class":3583},[3563,9038,9039],{"class":3587},"850",[3563,9041,3624],{"class":3583},[3563,9043,7738],{"class":3645},[3563,9045,3617],{"class":3583},[3563,9047,6476],{"class":3602},[3563,9049,9011],{"class":3583},[3563,9051,9052,9054,9056,9058,9060,9062,9064,9066,9069,9071,9073,9075,9078,9080,9082,9084,9086],{"class":3565,"line":3642},[3563,9053,8973],{"class":3583},[3563,9055,8976],{"class":3645},[3563,9057,3617],{"class":3583},[3563,9059,5051],{"class":3587},[3563,9061,3624],{"class":3583},[3563,9063,8985],{"class":3645},[3563,9065,3617],{"class":3583},[3563,9067,9068],{"class":3645},"\"Клавіатура\"",[3563,9070,3624],{"class":3583},[3563,9072,8995],{"class":3645},[3563,9074,3617],{"class":3583},[3563,9076,9077],{"class":3587},"2100",[3563,9079,3624],{"class":3583},[3563,9081,7738],{"class":3645},[3563,9083,3617],{"class":3583},[3563,9085,6749],{"class":3602},[3563,9087,9011],{"class":3583},[3563,9089,9090],{"class":3565,"line":3649},[3563,9091,6347],{"class":3583},[3563,9093,9094],{"class":3565,"line":3659},[3563,9095,3577],{"emptyLinePlaceholder":3576},[3563,9097,9098,9100,9103,9105,9108,9110,9112,9114,9116,9118,9120],{"class":3565,"line":3664},[3563,9099,3603],{"class":3602},[3563,9101,9102],{"class":3606}," list_products",[3563,9104,3610],{"class":3583},[3563,9106,9107],{"class":3613},"active_only",[3563,9109,3617],{"class":3583},[3563,9111,3823],{"class":3620},[3563,9113,8871],{"class":3583},[3563,9115,6476],{"class":3602},[3563,9117,3634],{"class":3583},[3563,9119,4666],{"class":3620},[3563,9121,3639],{"class":3583},[3563,9123,9124],{"class":3565,"line":3694},[3563,9125,9126],{"class":3645},"    \"\"\"Повертає список товарів. За замовчуванням — тільки активні.\"\"\"\n",[3563,9128,9129,9131],{"class":3565,"line":3700},[3563,9130,7854],{"class":3652},[3563,9132,9133],{"class":3583}," active_only:\n",[3563,9135,9136,9138,9141,9143,9146,9148,9151,9153,9156,9158],{"class":3565,"line":3708},[3563,9137,7673],{"class":3652},[3563,9139,9140],{"class":3583}," [p ",[3563,9142,3877],{"class":3652},[3563,9144,9145],{"class":3583}," p ",[3563,9147,3883],{"class":3652},[3563,9149,9150],{"class":3583}," _products_db ",[3563,9152,7464],{"class":3652},[3563,9154,9155],{"class":3583}," p[",[3563,9157,7738],{"class":3645},[3563,9159,9160],{"class":3583},"]]\n",[3563,9162,9163,9165,9168],{"class":3565,"line":3713},[3563,9164,3653],{"class":3652},[3563,9166,9167],{"class":3620}," list",[3563,9169,9170],{"class":3583},"(_products_db)\n",[3563,9172,9173],{"class":3565,"line":3743},[3563,9174,3577],{"emptyLinePlaceholder":3576},[3563,9176,9177,9179,9182,9184,9187,9189,9191,9193,9195,9198,9200],{"class":3565,"line":3749},[3563,9178,3603],{"class":3602},[3563,9180,9181],{"class":3606}," get_product",[3563,9183,3610],{"class":3583},[3563,9185,9186],{"class":3613},"product_id",[3563,9188,3617],{"class":3583},[3563,9190,3867],{"class":3620},[3563,9192,3634],{"class":3583},[3563,9194,4276],{"class":3620},[3563,9196,9197],{"class":3583}," | ",[3563,9199,6862],{"class":3602},[3563,9201,3639],{"class":3583},[3563,9203,9204],{"class":3565,"line":3757},[3563,9205,9206],{"class":3645},"    \"\"\"Знаходить товар за ID або повертає None.\"\"\"\n",[3563,9208,9209,9212,9215,9217],{"class":3565,"line":3762},[3563,9210,9211],{"class":3652},"    for",[3563,9213,9214],{"class":3583}," product ",[3563,9216,3883],{"class":3652},[3563,9218,9219],{"class":3583}," _products_db:\n",[3563,9221,9222,9225,9228,9230],{"class":3565,"line":3785},[3563,9223,9224],{"class":3652},"        if",[3563,9226,9227],{"class":3583}," product[",[3563,9229,8976],{"class":3645},[3563,9231,9232],{"class":3583},"] == product_id:\n",[3563,9234,9235,9238],{"class":3565,"line":3791},[3563,9236,9237],{"class":3652},"            return",[3563,9239,9240],{"class":3583}," product\n",[3563,9242,9243,9245],{"class":3565,"line":3802},[3563,9244,3653],{"class":3652},[3563,9246,9247],{"class":3602}," None\n",[3563,9249,9250],{"class":3565,"line":3807},[3563,9251,3577],{"emptyLinePlaceholder":3576},[3563,9253,9254,9256,9259,9261,9263,9265,9267,9269,9272,9274,9276,9278,9281,9283,9285],{"class":3565,"line":3828},[3563,9255,3603],{"class":3602},[3563,9257,9258],{"class":3606}," calculate_price_with_vat",[3563,9260,3610],{"class":3583},[3563,9262,9186],{"class":3613},[3563,9264,3617],{"class":3583},[3563,9266,3867],{"class":3620},[3563,9268,3624],{"class":3583},[3563,9270,9271],{"class":3613},"vat_rate",[3563,9273,3617],{"class":3583},[3563,9275,3621],{"class":3620},[3563,9277,8871],{"class":3583},[3563,9279,9280],{"class":3587},"0.20",[3563,9282,3634],{"class":3583},[3563,9284,3621],{"class":3620},[3563,9286,3639],{"class":3583},[3563,9288,9289],{"class":3565,"line":3834},[3563,9290,9291],{"class":3645},"    \"\"\"Розраховує ціну з ПДВ.\"\"\"\n",[3563,9293,9294],{"class":3565,"line":3840},[3563,9295,9296],{"class":3583},"    product = get_product(product_id)\n",[3563,9298,9299,9301,9303,9305,9308],{"class":3565,"line":3846},[3563,9300,7854],{"class":3652},[3563,9302,9214],{"class":3583},[3563,9304,6366],{"class":3602},[3563,9306,9307],{"class":3602}," None",[3563,9309,3639],{"class":3583},[3563,9311,9312,9315,9318,9320,9322,9325,9327,9329,9331,9334],{"class":3565,"line":3851},[3563,9313,9314],{"class":3652},"        raise",[3563,9316,9317],{"class":3620}," ValueError",[3563,9319,3610],{"class":3583},[3563,9321,3960],{"class":3602},[3563,9323,9324],{"class":3645},"\"Товар ",[3563,9326,3966],{"class":3602},[3563,9328,9186],{"class":3583},[3563,9330,3972],{"class":3602},[3563,9332,9333],{"class":3645}," не знайдено\"",[3563,9335,3936],{"class":3583},[3563,9337,9338,9340,9342,9344,9347,9349],{"class":3565,"line":5463},[3563,9339,3653],{"class":3652},[3563,9341,9227],{"class":3583},[3563,9343,8995],{"class":3645},[3563,9345,9346],{"class":3583},"] * (",[3563,9348,5061],{"class":3587},[3563,9350,9351],{"class":3583}," + vat_rate)\n",[3554,9353,9356],{"className":3556,"code":9354,"filename":9355,"language":3558,"meta":3559,"style":3559},"\"\"\"Модуль для управління клієнтами.\"\"\"\n\n_customers_db = {\n    \"CUST-001\": {\"name\": \"Олена Ковальчук\", \"email\": \"olena@example.com\"},\n    \"CUST-002\": {\"name\": \"Іван Мельник\",    \"email\": \"ivan@example.com\"},\n}\n\ndef get_customer(customer_id: str) -> dict | None:\n    \"\"\"Повертає дані клієнта або None.\"\"\"\n    return _customers_db.get(customer_id)\n\ndef register_customer(customer_id: str, name: str, email: str) -> dict:\n    \"\"\"Реєструє нового клієнта.\"\"\"\n    if customer_id in _customers_db:\n        raise ValueError(f\"Клієнт {customer_id} вже існує\")\n    customer = {\"name\": name, \"email\": email}\n    _customers_db[customer_id] = customer\n    return customer\n","shop\u002Fcustomers.py",[3398,9357,9358,9363,9367,9372,9399,9425,9429,9433,9459,9464,9471,9475,9514,9519,9531,9555,9570,9575],{"__ignoreMap":3559},[3563,9359,9360],{"class":3565,"line":3566},[3563,9361,9362],{"class":3645},"\"\"\"Модуль для управління клієнтами.\"\"\"\n",[3563,9364,9365],{"class":3565,"line":3573},[3563,9366,3577],{"emptyLinePlaceholder":3576},[3563,9368,9369],{"class":3565,"line":3580},[3563,9370,9371],{"class":3583},"_customers_db = {\n",[3563,9373,9374,9377,9380,9382,9384,9387,9389,9392,9394,9397],{"class":3565,"line":3594},[3563,9375,9376],{"class":3645},"    \"CUST-001\"",[3563,9378,9379],{"class":3583},": {",[3563,9381,8985],{"class":3645},[3563,9383,3617],{"class":3583},[3563,9385,9386],{"class":3645},"\"Олена Ковальчук\"",[3563,9388,3624],{"class":3583},[3563,9390,9391],{"class":3645},"\"email\"",[3563,9393,3617],{"class":3583},[3563,9395,9396],{"class":3645},"\"olena@example.com\"",[3563,9398,9011],{"class":3583},[3563,9400,9401,9404,9406,9408,9410,9413,9416,9418,9420,9423],{"class":3565,"line":3599},[3563,9402,9403],{"class":3645},"    \"CUST-002\"",[3563,9405,9379],{"class":3583},[3563,9407,8985],{"class":3645},[3563,9409,3617],{"class":3583},[3563,9411,9412],{"class":3645},"\"Іван Мельник\"",[3563,9414,9415],{"class":3583},",    ",[3563,9417,9391],{"class":3645},[3563,9419,3617],{"class":3583},[3563,9421,9422],{"class":3645},"\"ivan@example.com\"",[3563,9424,9011],{"class":3583},[3563,9426,9427],{"class":3565,"line":3642},[3563,9428,4431],{"class":3583},[3563,9430,9431],{"class":3565,"line":3649},[3563,9432,3577],{"emptyLinePlaceholder":3576},[3563,9434,9435,9437,9440,9442,9445,9447,9449,9451,9453,9455,9457],{"class":3565,"line":3659},[3563,9436,3603],{"class":3602},[3563,9438,9439],{"class":3606}," get_customer",[3563,9441,3610],{"class":3583},[3563,9443,9444],{"class":3613},"customer_id",[3563,9446,3617],{"class":3583},[3563,9448,4145],{"class":3620},[3563,9450,3634],{"class":3583},[3563,9452,4276],{"class":3620},[3563,9454,9197],{"class":3583},[3563,9456,6862],{"class":3602},[3563,9458,3639],{"class":3583},[3563,9460,9461],{"class":3565,"line":3664},[3563,9462,9463],{"class":3645},"    \"\"\"Повертає дані клієнта або None.\"\"\"\n",[3563,9465,9466,9468],{"class":3565,"line":3694},[3563,9467,3653],{"class":3652},[3563,9469,9470],{"class":3583}," _customers_db.get(customer_id)\n",[3563,9472,9473],{"class":3565,"line":3700},[3563,9474,3577],{"emptyLinePlaceholder":3576},[3563,9476,9477,9479,9482,9484,9486,9488,9490,9492,9495,9497,9499,9501,9504,9506,9508,9510,9512],{"class":3565,"line":3708},[3563,9478,3603],{"class":3602},[3563,9480,9481],{"class":3606}," register_customer",[3563,9483,3610],{"class":3583},[3563,9485,9444],{"class":3613},[3563,9487,3617],{"class":3583},[3563,9489,4145],{"class":3620},[3563,9491,3624],{"class":3583},[3563,9493,9494],{"class":3613},"name",[3563,9496,3617],{"class":3583},[3563,9498,4145],{"class":3620},[3563,9500,3624],{"class":3583},[3563,9502,9503],{"class":3613},"email",[3563,9505,3617],{"class":3583},[3563,9507,4145],{"class":3620},[3563,9509,3634],{"class":3583},[3563,9511,4276],{"class":3620},[3563,9513,3639],{"class":3583},[3563,9515,9516],{"class":3565,"line":3713},[3563,9517,9518],{"class":3645},"    \"\"\"Реєструє нового клієнта.\"\"\"\n",[3563,9520,9521,9523,9526,9528],{"class":3565,"line":3743},[3563,9522,7854],{"class":3652},[3563,9524,9525],{"class":3583}," customer_id ",[3563,9527,3883],{"class":3602},[3563,9529,9530],{"class":3583}," _customers_db:\n",[3563,9532,9533,9535,9537,9539,9541,9544,9546,9548,9550,9553],{"class":3565,"line":3749},[3563,9534,9314],{"class":3652},[3563,9536,9317],{"class":3620},[3563,9538,3610],{"class":3583},[3563,9540,3960],{"class":3602},[3563,9542,9543],{"class":3645},"\"Клієнт ",[3563,9545,3966],{"class":3602},[3563,9547,9444],{"class":3583},[3563,9549,3972],{"class":3602},[3563,9551,9552],{"class":3645}," вже існує\"",[3563,9554,3936],{"class":3583},[3563,9556,9557,9560,9562,9565,9567],{"class":3565,"line":3757},[3563,9558,9559],{"class":3583},"    customer = {",[3563,9561,8985],{"class":3645},[3563,9563,9564],{"class":3583},": name, ",[3563,9566,9391],{"class":3645},[3563,9568,9569],{"class":3583},": email}\n",[3563,9571,9572],{"class":3565,"line":3762},[3563,9573,9574],{"class":3583},"    _customers_db[customer_id] = customer\n",[3563,9576,9577,9579],{"class":3565,"line":3785},[3563,9578,3653],{"class":3652},[3563,9580,9581],{"class":3583}," customer\n",[3554,9583,9586],{"className":3556,"code":9584,"filename":9585,"language":3558,"meta":3559,"style":3559},"\"\"\"Підпакет для управління замовленнями.\"\"\"\nfrom .processing import create_order, get_order_status\n","shop\u002Forders\u002F__init__.py",[3398,9587,9588,9593],{"__ignoreMap":3559},[3563,9589,9590],{"class":3565,"line":3566},[3563,9591,9592],{"class":3645},"\"\"\"Підпакет для управління замовленнями.\"\"\"\n",[3563,9594,9595,9597,9600,9602],{"class":3565,"line":3573},[3563,9596,4907],{"class":3652},[3563,9598,9599],{"class":3583}," .processing ",[3563,9601,3905],{"class":3652},[3563,9603,9604],{"class":3583}," create_order, get_order_status\n",[3554,9606,9609],{"className":3556,"code":9607,"filename":9608,"language":3558,"meta":3559,"style":3559},"\"\"\"Модуль обробки замовлень.\"\"\"\n\n_orders = {}\n\ndef create_order(customer_id: str, product_ids: list) -> dict:\n    \"\"\"Створює нове замовлення.\"\"\"\n    order_id = f\"ORD-{len(_orders) + 1:04d}\"\n    order = {\n        \"id\": order_id,\n        \"customer_id\": customer_id,\n        \"product_ids\": product_ids,\n        \"status\": \"pending\"\n    }\n    _orders[order_id] = order\n    return order\n\ndef get_order_status(order_id: str) -> str | None:\n    order = _orders.get(order_id)\n    return order[\"status\"] if order else None\n","shop\u002Forders\u002Fprocessing.py",[3398,9610,9611,9616,9620,9625,9629,9659,9664,9689,9694,9702,9710,9718,9728,9732,9737,9744,9748,9774,9779],{"__ignoreMap":3559},[3563,9612,9613],{"class":3565,"line":3566},[3563,9614,9615],{"class":3645},"\"\"\"Модуль обробки замовлень.\"\"\"\n",[3563,9617,9618],{"class":3565,"line":3573},[3563,9619,3577],{"emptyLinePlaceholder":3576},[3563,9621,9622],{"class":3565,"line":3580},[3563,9623,9624],{"class":3583},"_orders = {}\n",[3563,9626,9627],{"class":3565,"line":3594},[3563,9628,3577],{"emptyLinePlaceholder":3576},[3563,9630,9631,9633,9636,9638,9640,9642,9644,9646,9649,9651,9653,9655,9657],{"class":3565,"line":3599},[3563,9632,3603],{"class":3602},[3563,9634,9635],{"class":3606}," create_order",[3563,9637,3610],{"class":3583},[3563,9639,9444],{"class":3613},[3563,9641,3617],{"class":3583},[3563,9643,4145],{"class":3620},[3563,9645,3624],{"class":3583},[3563,9647,9648],{"class":3613},"product_ids",[3563,9650,3617],{"class":3583},[3563,9652,4666],{"class":3620},[3563,9654,3634],{"class":3583},[3563,9656,4276],{"class":3620},[3563,9658,3639],{"class":3583},[3563,9660,9661],{"class":3565,"line":3642},[3563,9662,9663],{"class":3645},"    \"\"\"Створює нове замовлення.\"\"\"\n",[3563,9665,9666,9669,9671,9674,9676,9678,9681,9683,9686],{"class":3565,"line":3649},[3563,9667,9668],{"class":3583},"    order_id = ",[3563,9670,3960],{"class":3602},[3563,9672,9673],{"class":3645},"\"ORD-",[3563,9675,3966],{"class":3602},[3563,9677,5629],{"class":3606},[3563,9679,9680],{"class":3583},"(_orders) + ",[3563,9682,5061],{"class":3587},[3563,9684,9685],{"class":3602},":04d}",[3563,9687,9688],{"class":3645},"\"\n",[3563,9690,9691],{"class":3565,"line":3659},[3563,9692,9693],{"class":3583},"    order = {\n",[3563,9695,9696,9699],{"class":3565,"line":3664},[3563,9697,9698],{"class":3645},"        \"id\"",[3563,9700,9701],{"class":3583},": order_id,\n",[3563,9703,9704,9707],{"class":3565,"line":3694},[3563,9705,9706],{"class":3645},"        \"customer_id\"",[3563,9708,9709],{"class":3583},": customer_id,\n",[3563,9711,9712,9715],{"class":3565,"line":3700},[3563,9713,9714],{"class":3645},"        \"product_ids\"",[3563,9716,9717],{"class":3583},": product_ids,\n",[3563,9719,9720,9723,9725],{"class":3565,"line":3708},[3563,9721,9722],{"class":3645},"        \"status\"",[3563,9724,3617],{"class":3583},[3563,9726,9727],{"class":3645},"\"pending\"\n",[3563,9729,9730],{"class":3565,"line":3713},[3563,9731,4426],{"class":3583},[3563,9733,9734],{"class":3565,"line":3743},[3563,9735,9736],{"class":3583},"    _orders[order_id] = order\n",[3563,9738,9739,9741],{"class":3565,"line":3749},[3563,9740,3653],{"class":3652},[3563,9742,9743],{"class":3583}," order\n",[3563,9745,9746],{"class":3565,"line":3757},[3563,9747,3577],{"emptyLinePlaceholder":3576},[3563,9749,9750,9752,9755,9757,9760,9762,9764,9766,9768,9770,9772],{"class":3565,"line":3762},[3563,9751,3603],{"class":3602},[3563,9753,9754],{"class":3606}," get_order_status",[3563,9756,3610],{"class":3583},[3563,9758,9759],{"class":3613},"order_id",[3563,9761,3617],{"class":3583},[3563,9763,4145],{"class":3620},[3563,9765,3634],{"class":3583},[3563,9767,4145],{"class":3620},[3563,9769,9197],{"class":3583},[3563,9771,6862],{"class":3602},[3563,9773,3639],{"class":3583},[3563,9775,9776],{"class":3565,"line":3785},[3563,9777,9778],{"class":3583},"    order = _orders.get(order_id)\n",[3563,9780,9781,9783,9786,9789,9791,9793,9796,9799],{"class":3565,"line":3791},[3563,9782,3653],{"class":3652},[3563,9784,9785],{"class":3583}," order[",[3563,9787,9788],{"class":3645},"\"status\"",[3563,9790,5678],{"class":3583},[3563,9792,7464],{"class":3652},[3563,9794,9795],{"class":3583}," order ",[3563,9797,9798],{"class":3652},"else",[3563,9800,9247],{"class":3602},[3554,9802,9804],{"className":3556,"code":9803,"filename":3400,"language":3558,"meta":3559,"style":3559},"# main.py — використання пакета shop\n\n# Спосіб 1: через \"фасад\" __init__.py\nimport shop\nprint(f\"Версія: {shop.__version__}\")\nproducts = shop.list_products()\nprint(f\"Активних товарів: {len(products)}\")\n\n# Спосіб 2: прямий імпорт підмодуля\nfrom shop.products import calculate_price_with_vat\nprice = calculate_price_with_vat(1)\nprint(f\"Ноутбук з ПДВ: {price:.0f} грн\")\n\n# Спосіб 3: підпакет\nfrom shop.orders import create_order\norder = create_order(\"CUST-001\", [1, 2])\nprint(f\"Замовлення: {order['id']}\")\n",[3398,9805,9806,9811,9815,9820,9827,9851,9856,9880,9884,9889,9901,9910,9934,9938,9943,9955,9974],{"__ignoreMap":3559},[3563,9807,9808],{"class":3565,"line":3566},[3563,9809,9810],{"class":3569},"# main.py — використання пакета shop\n",[3563,9812,9813],{"class":3565,"line":3573},[3563,9814,3577],{"emptyLinePlaceholder":3576},[3563,9816,9817],{"class":3565,"line":3580},[3563,9818,9819],{"class":3569},"# Спосіб 1: через \"фасад\" __init__.py\n",[3563,9821,9822,9824],{"class":3565,"line":3594},[3563,9823,3905],{"class":3652},[3563,9825,9826],{"class":3583}," shop\n",[3563,9828,9829,9831,9833,9835,9838,9840,9843,9845,9847,9849],{"class":3565,"line":3599},[3563,9830,3955],{"class":3606},[3563,9832,3610],{"class":3583},[3563,9834,3960],{"class":3602},[3563,9836,9837],{"class":3645},"\"Версія: ",[3563,9839,3966],{"class":3602},[3563,9841,9842],{"class":3583},"shop.",[3563,9844,8868],{"class":3613},[3563,9846,3972],{"class":3602},[3563,9848,3975],{"class":3645},[3563,9850,3936],{"class":3583},[3563,9852,9853],{"class":3565,"line":3642},[3563,9854,9855],{"class":3583},"products = shop.list_products()\n",[3563,9857,9858,9860,9862,9864,9867,9869,9871,9874,9876,9878],{"class":3565,"line":3649},[3563,9859,3955],{"class":3606},[3563,9861,3610],{"class":3583},[3563,9863,3960],{"class":3602},[3563,9865,9866],{"class":3645},"\"Активних товарів: ",[3563,9868,3966],{"class":3602},[3563,9870,5629],{"class":3606},[3563,9872,9873],{"class":3583},"(products)",[3563,9875,3972],{"class":3602},[3563,9877,3975],{"class":3645},[3563,9879,3936],{"class":3583},[3563,9881,9882],{"class":3565,"line":3659},[3563,9883,3577],{"emptyLinePlaceholder":3576},[3563,9885,9886],{"class":3565,"line":3664},[3563,9887,9888],{"class":3569},"# Спосіб 2: прямий імпорт підмодуля\n",[3563,9890,9891,9893,9896,9898],{"class":3565,"line":3694},[3563,9892,4907],{"class":3652},[3563,9894,9895],{"class":3583}," shop.products ",[3563,9897,3905],{"class":3652},[3563,9899,9900],{"class":3583}," calculate_price_with_vat\n",[3563,9902,9903,9906,9908],{"class":3565,"line":3700},[3563,9904,9905],{"class":3583},"price = calculate_price_with_vat(",[3563,9907,5061],{"class":3587},[3563,9909,3936],{"class":3583},[3563,9911,9912,9914,9916,9918,9921,9923,9926,9929,9932],{"class":3565,"line":3708},[3563,9913,3955],{"class":3606},[3563,9915,3610],{"class":3583},[3563,9917,3960],{"class":3602},[3563,9919,9920],{"class":3645},"\"Ноутбук з ПДВ: ",[3563,9922,3966],{"class":3602},[3563,9924,9925],{"class":3583},"price",[3563,9927,9928],{"class":3602},":.0f}",[3563,9930,9931],{"class":3645}," грн\"",[3563,9933,3936],{"class":3583},[3563,9935,9936],{"class":3565,"line":3713},[3563,9937,3577],{"emptyLinePlaceholder":3576},[3563,9939,9940],{"class":3565,"line":3743},[3563,9941,9942],{"class":3569},"# Спосіб 3: підпакет\n",[3563,9944,9945,9947,9950,9952],{"class":3565,"line":3749},[3563,9946,4907],{"class":3652},[3563,9948,9949],{"class":3583}," shop.orders ",[3563,9951,3905],{"class":3652},[3563,9953,9954],{"class":3583}," create_order\n",[3563,9956,9957,9960,9963,9966,9968,9970,9972],{"class":3565,"line":3757},[3563,9958,9959],{"class":3583},"order = create_order(",[3563,9961,9962],{"class":3645},"\"CUST-001\"",[3563,9964,9965],{"class":3583},", [",[3563,9967,5061],{"class":3587},[3563,9969,3624],{"class":3583},[3563,9971,4209],{"class":3587},[3563,9973,5072],{"class":3583},[3563,9975,9976,9978,9980,9982,9985,9987,9990,9993,9995,9997,9999],{"class":3565,"line":3762},[3563,9977,3955],{"class":3606},[3563,9979,3610],{"class":3583},[3563,9981,3960],{"class":3602},[3563,9983,9984],{"class":3645},"\"Замовлення: ",[3563,9986,3966],{"class":3602},[3563,9988,9989],{"class":3583},"order[",[3563,9991,9992],{"class":3645},"'id'",[3563,9994,4741],{"class":3583},[3563,9996,3972],{"class":3602},[3563,9998,3975],{"class":3645},[3563,10000,3936],{"class":3583},[3468,10002,10004,10005,10007],{"id":10003},"роль-__init__py-ворота-пакета","Роль ",[3398,10006,8808],{},": ворота пакета",[3394,10009,10010,10011,10013],{},"Файл ",[3398,10012,8808],{}," виконує три ключові функції.",[3394,10015,10016,10019,10020,10022,10023,10026,10027,10029],{},[3406,10017,10018],{},"Функція 1: Позначення директорії як пакета."," Без ",[3398,10021,8808],{}," Python 3 усе одно ",[4093,10024,10025],{},"може"," знайти пакет (завдяки механізму «namespace packages»), але поведінка буде непередбачуваною. Явний ",[3398,10028,8808],{}," є гарантією.",[3394,10031,10032,10035,10036,10038,10039,4310,10042,10045,10046,10048],{},[3406,10033,10034],{},"Функція 2: Ініціалізаційний код."," Все, що у ",[3398,10037,8808],{},", виконується при першому ",[3398,10040,10041],{},"import shop",[3398,10043,10044],{},"import shop.products"," — але лише один раз (кеш ",[3398,10047,3496],{},"). Тут доречно: підключення до БД, завантаження конфігурації, ініціалізація глобального стану.",[3394,10050,10051,10054,10055,10057],{},[3406,10052,10053],{},"Функція 3: «Фасад» публічного API."," Це найважливіша архітектурна роль. Ре-експортуючи функції у ",[3398,10056,8808],{},", ви:",[5138,10059,10060,10070],{},[3508,10061,10062,10063,10066,10067],{},"Спрощуєте зовнішній API: ",[3398,10064,10065],{},"shop.list_products()"," замість ",[3398,10068,10069],{},"shop.products.list_products()",[3508,10071,10072],{},"Дозволяєте змінювати внутрішню структуру пакета без зламу зовнішнього коду",[3554,10074,10076],{"className":3556,"code":10075,"language":3558,"meta":3559,"style":3559},"# До рефакторингу: shop\u002Fproducts.py\n# Після рефакторингу: shop\u002Fcatalog\u002Fproducts.py\n\n# Але __init__.py залишається незмінним:\nfrom .catalog.products import list_products  # ← просто змінили шлях\n# Зовнішній код 'shop.list_products()' не сломається!\n",[3398,10077,10078,10083,10088,10092,10097,10112],{"__ignoreMap":3559},[3563,10079,10080],{"class":3565,"line":3566},[3563,10081,10082],{"class":3569},"# До рефакторингу: shop\u002Fproducts.py\n",[3563,10084,10085],{"class":3565,"line":3573},[3563,10086,10087],{"class":3569},"# Після рефакторингу: shop\u002Fcatalog\u002Fproducts.py\n",[3563,10089,10090],{"class":3565,"line":3580},[3563,10091,3577],{"emptyLinePlaceholder":3576},[3563,10093,10094],{"class":3565,"line":3594},[3563,10095,10096],{"class":3569},"# Але __init__.py залишається незмінним:\n",[3563,10098,10099,10101,10104,10106,10109],{"class":3565,"line":3599},[3563,10100,4907],{"class":3652},[3563,10102,10103],{"class":3583}," .catalog.products ",[3563,10105,3905],{"class":3652},[3563,10107,10108],{"class":3583}," list_products  ",[3563,10110,10111],{"class":3569},"# ← просто змінили шлях\n",[3563,10113,10114],{"class":3565,"line":3642},[3563,10115,10116],{"class":3569},"# Зовнішній код 'shop.list_products()' не сломається!\n",[3461,10118],{},[3389,10120,10122],{"id":10121},"абсолютний-та-відносний-імпорт","Абсолютний та відносний імпорт",[3468,10124,10126],{"id":10125},"абсолютний-імпорт-повний-шлях-від-кореня","Абсолютний імпорт: повний шлях від кореня",[3394,10128,10129,10132,10133,10135],{},[3406,10130,10131],{},"Абсолютний імпорт"," вказує повний шлях від кореня проекту (або від директорії у ",[3398,10134,3517],{},"):",[3554,10137,10139],{"className":3556,"code":10138,"language":3558,"meta":3559,"style":3559},"# Де б не знаходився цей файл у структурі проекту:\nimport shop.products                        # весь модуль\nfrom shop.products import list_products     # конкретна функція\nfrom shop.orders.processing import create_order  # з підпакета\n",[3398,10140,10141,10146,10156,10170],{"__ignoreMap":3559},[3563,10142,10143],{"class":3565,"line":3566},[3563,10144,10145],{"class":3569},"# Де б не знаходився цей файл у структурі проекту:\n",[3563,10147,10148,10150,10153],{"class":3565,"line":3573},[3563,10149,3905],{"class":3652},[3563,10151,10152],{"class":3583}," shop.products                        ",[3563,10154,10155],{"class":3569},"# весь модуль\n",[3563,10157,10158,10160,10162,10164,10167],{"class":3565,"line":3580},[3563,10159,4907],{"class":3652},[3563,10161,9895],{"class":3583},[3563,10163,3905],{"class":3652},[3563,10165,10166],{"class":3583}," list_products     ",[3563,10168,10169],{"class":3569},"# конкретна функція\n",[3563,10171,10172,10174,10177,10179,10182],{"class":3565,"line":3594},[3563,10173,4907],{"class":3652},[3563,10175,10176],{"class":3583}," shop.orders.processing ",[3563,10178,3905],{"class":3652},[3563,10180,10181],{"class":3583}," create_order  ",[3563,10183,10184],{"class":3569},"# з підпакета\n",[3394,10186,10187,10188,10191],{},"Абсолютні імпорти є однозначними: завжди зрозуміло, звідки береться модуль. ",[3406,10189,10190],{},"PEP 8 рекомендує абсолютний імпорт як основний"," для міжпакетних залежностей.",[3468,10193,10195],{"id":10194},"відносний-імпорт-шлях-відносно-поточного-модуля","Відносний імпорт: шлях відносно поточного модуля",[3394,10197,10198,10201],{},[3406,10199,10200],{},"Відносний імпорт"," використовує крапкову нотацію для вказівки шляху відносно поточного модуля:",[3554,10203,10205],{"className":3556,"code":10204,"language":3558,"meta":3559,"style":3559},"# Всередині shop\u002Forders\u002Fprocessing.py:\nfrom . import notifications       # . = поточний пакет (shop\u002Forders\u002F)\nfrom .notifications import send   # конкретна функція з сусіднього модуля\nfrom .. import products           # .. = батьківський пакет (shop\u002F)\nfrom ..customers import get_customer  # конкретна функція з батька\n",[3398,10206,10207,10212,10227,10242,10257],{"__ignoreMap":3559},[3563,10208,10209],{"class":3565,"line":3566},[3563,10210,10211],{"class":3569},"# Всередині shop\u002Forders\u002Fprocessing.py:\n",[3563,10213,10214,10216,10219,10221,10224],{"class":3565,"line":3573},[3563,10215,4907],{"class":3652},[3563,10217,10218],{"class":3583}," . ",[3563,10220,3905],{"class":3652},[3563,10222,10223],{"class":3583}," notifications       ",[3563,10225,10226],{"class":3569},"# . = поточний пакет (shop\u002Forders\u002F)\n",[3563,10228,10229,10231,10234,10236,10239],{"class":3565,"line":3580},[3563,10230,4907],{"class":3652},[3563,10232,10233],{"class":3583}," .notifications ",[3563,10235,3905],{"class":3652},[3563,10237,10238],{"class":3583}," send   ",[3563,10240,10241],{"class":3569},"# конкретна функція з сусіднього модуля\n",[3563,10243,10244,10246,10249,10251,10254],{"class":3565,"line":3594},[3563,10245,4907],{"class":3652},[3563,10247,10248],{"class":3583}," .. ",[3563,10250,3905],{"class":3652},[3563,10252,10253],{"class":3583}," products           ",[3563,10255,10256],{"class":3569},"# .. = батьківський пакет (shop\u002F)\n",[3563,10258,10259,10261,10264,10266,10269],{"class":3565,"line":3599},[3563,10260,4907],{"class":3652},[3563,10262,10263],{"class":3583}," ..customers ",[3563,10265,3905],{"class":3652},[3563,10267,10268],{"class":3583}," get_customer  ",[3563,10270,10271],{"class":3569},"# конкретна функція з батька\n",[3394,10273,10274,10275,10278,10279,10281,10282,10284],{},"Відносні імпорти мають суттєве обмеження: вони ",[3406,10276,10277],{},"не працюють"," у файлі, що виконується як головний скрипт (",[3398,10280,7281],{},"). Тому не використовуйте відносні імпорти у ",[3398,10283,3400],{}," або в будь-якому файлі, що планується запускати напряму.",[10286,10287,10288,10293],"tip",{},[3394,10289,10290],{},[3406,10291,10292],{},"Коли використовувати відносний vs абсолютний імпорт:",[5138,10294,10295,10304],{},[3508,10296,10297,10300,10301],{},[3406,10298,10299],{},"Абсолютний"," — для імпорту між різними пакетами: ",[3398,10302,10303],{},"from shop.products import ...",[3508,10305,10306,10309,10310,10312,10313,10316,10317],{},[3406,10307,10308],{},"Відносний"," — для зв'язків усередині одного пакета: ",[3398,10311,8212],{}," — гарантує, що пакет використовує свій власний ",[3398,10314,10315],{},"utils",", а не однойменний модуль з іншого місця у ",[3398,10318,3517],{},[3468,10320,10322,10324],{"id":10321},"__all__-контракт-публічного-api",[3398,10323,5295],{},": контракт публічного API",[3394,10326,10327,10328,8445,10330,10332,10333,10336],{},"Змінна ",[3398,10329,5295],{},[3398,10331,8808],{}," або у будь-якому модулі — це список рядків, що визначає, ",[3406,10334,10335],{},"які імена є публічним API"," цього модуля\u002Fпакета:",[3554,10338,10340],{"className":3556,"code":10339,"language":3558,"meta":3559,"style":3559},"# shop\u002Fproducts.py\n\n__all__ = [\"list_products\", \"get_product\", \"calculate_price_with_vat\"]\n# _products_db та будь-які внутрішні допоміжні функції\n# не включені в __all__ і не будуть імпортовані через 'from shop.products import *'\n\ndef list_products(active_only=True): ...\ndef get_product(product_id): ...\ndef calculate_price_with_vat(product_id, vat_rate=0.20): ...\ndef _validate_product(data): ...  # внутрішня, не у __all__\n\n_products_db = [...]              # приватні дані, не у __all__\n",[3398,10341,10342,10347,10351,10370,10375,10380,10384,10401,10413,10433,10450,10454],{"__ignoreMap":3559},[3563,10343,10344],{"class":3565,"line":3566},[3563,10345,10346],{"class":3569},"# shop\u002Fproducts.py\n",[3563,10348,10349],{"class":3565,"line":3573},[3563,10350,3577],{"emptyLinePlaceholder":3576},[3563,10352,10353,10355,10357,10359,10361,10363,10365,10368],{"class":3565,"line":3580},[3563,10354,5295],{"class":3613},[3563,10356,8890],{"class":3583},[3563,10358,8898],{"class":3645},[3563,10360,3624],{"class":3583},[3563,10362,8893],{"class":3645},[3563,10364,3624],{"class":3583},[3563,10366,10367],{"class":3645},"\"calculate_price_with_vat\"",[3563,10369,6347],{"class":3583},[3563,10371,10372],{"class":3565,"line":3594},[3563,10373,10374],{"class":3569},"# _products_db та будь-які внутрішні допоміжні функції\n",[3563,10376,10377],{"class":3565,"line":3599},[3563,10378,10379],{"class":3569},"# не включені в __all__ і не будуть імпортовані через 'from shop.products import *'\n",[3563,10381,10382],{"class":3565,"line":3642},[3563,10383,3577],{"emptyLinePlaceholder":3576},[3563,10385,10386,10388,10390,10392,10394,10396,10398],{"class":3565,"line":3649},[3563,10387,3603],{"class":3602},[3563,10389,9102],{"class":3606},[3563,10391,3610],{"class":3583},[3563,10393,9107],{"class":3613},[3563,10395,7810],{"class":3583},[3563,10397,6476],{"class":3602},[3563,10399,10400],{"class":3583},"): ...\n",[3563,10402,10403,10405,10407,10409,10411],{"class":3565,"line":3659},[3563,10404,3603],{"class":3602},[3563,10406,9181],{"class":3606},[3563,10408,3610],{"class":3583},[3563,10410,9186],{"class":3613},[3563,10412,10400],{"class":3583},[3563,10414,10415,10417,10419,10421,10423,10425,10427,10429,10431],{"class":3565,"line":3664},[3563,10416,3603],{"class":3602},[3563,10418,9258],{"class":3606},[3563,10420,3610],{"class":3583},[3563,10422,9186],{"class":3613},[3563,10424,3624],{"class":3583},[3563,10426,9271],{"class":3613},[3563,10428,7810],{"class":3583},[3563,10430,9280],{"class":3587},[3563,10432,10400],{"class":3583},[3563,10434,10435,10437,10440,10442,10444,10447],{"class":3565,"line":3694},[3563,10436,3603],{"class":3602},[3563,10438,10439],{"class":3606}," _validate_product",[3563,10441,3610],{"class":3583},[3563,10443,7692],{"class":3613},[3563,10445,10446],{"class":3583},"): ...  ",[3563,10448,10449],{"class":3569},"# внутрішня, не у __all__\n",[3563,10451,10452],{"class":3565,"line":3700},[3563,10453,3577],{"emptyLinePlaceholder":3576},[3563,10455,10456,10459],{"class":3565,"line":3708},[3563,10457,10458],{"class":3583},"_products_db = [...]              ",[3563,10460,10461],{"class":3569},"# приватні дані, не у __all__\n",[3394,10463,10464,10466],{},[3398,10465,5295],{}," виконує дві функції:",[3505,10468,10469,10475],{},[3508,10470,10471,10474],{},[3406,10472,10473],{},"Документація",": чітко сигналізує, які об'єкти є стабільним публічним API",[3508,10476,10477,10482,10483,10485,10486],{},[3406,10478,10479,10480],{},"Контроль ",[3398,10481,5303],{},": тільки імена з ",[3398,10484,5295],{}," потрапляють у простір імен при ",[3398,10487,4256],{},[3461,10489],{},[3389,10491,10493],{"id":10492},"частина-iii-віртуальні-середовища","Частина III: Віртуальні Середовища",[3468,10495,10497],{"id":10496},"проблема-глобального-python-пекло-залежностей","Проблема глобального Python: «пекло залежностей»",[3394,10499,10500],{},"Уявіть типову ситуацію: у вас на комп'ютері два Python-проекти.",[5138,10502,10503,10515],{},[3508,10504,10505,10508,10509,4481,10512],{},[3406,10506,10507],{},"Проект А"," (2019 рік): використовує ",[3398,10510,10511],{},"Django 2.2",[3398,10513,10514],{},"requests 2.20",[3508,10516,10517,10520,10521,4481,10524],{},[3406,10518,10519],{},"Проект Б"," (2024 рік): потребує ",[3398,10522,10523],{},"Django 4.2",[3398,10525,10526],{},"requests 2.31",[3394,10528,10529,10530,10533,10534,10537,10538,10541],{},"Якщо встановити обидва проекти у ",[3406,10531,10532],{},"глобальний"," Python (без ізоляції), виникає конфлікт: ",[3398,10535,10536],{},"pip install Django==4.2"," замінить ",[3398,10539,10540],{},"Django==2.2"," — і Проект А зламається. Встановити обидві версії одночасно у глобальний Python неможливо.",[3394,10543,10544,10545,3459],{},"Це явище називається ",[3406,10546,10547],{},"«пекло залежностей» (dependency hell)",[4359,10549,10550],{},[3554,10551,10553],{"className":4363,"code":10552,"language":4365,"meta":3559,"style":3559},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #e11d48\n\npackage \"Глобальний Python (❌ БЕЗ venv)\" {\n    object \"site-packages\" as SP #fee2e2 {\n        Django = ???  (2.2 або 4.2?)\n        requests = ???\n    }\n    note right of SP\n      Неможливо встановити\n      дві версії одночасно!\n    end note\n}\n\nobject \"Проект А\\n(Django 2.2)\" as PA #fef3c7\nobject \"Проект Б\\n(Django 4.2)\" as PB #fef3c7\n\nPA --> SP : потребує Django 2.2\nPB --> SP : потребує Django 4.2\n\nnote bottom\n  pip install django==4.2 знищить django==2.2\n  Проект А зламається!\nend note\n@enduml\n",[3398,10554,10555,10559,10563,10567,10572,10576,10581,10586,10591,10596,10600,10605,10610,10615,10619,10623,10627,10632,10637,10641,10646,10651,10655,10660,10665,10670,10674],{"__ignoreMap":3559},[3563,10556,10557],{"class":3565,"line":3566},[3563,10558,4372],{},[3563,10560,10561],{"class":3565,"line":3573},[3563,10562,4377],{},[3563,10564,10565],{"class":3565,"line":3580},[3563,10566,4382],{},[3563,10568,10569],{"class":3565,"line":3594},[3563,10570,10571],{},"skinparam ArrowColor #e11d48\n",[3563,10573,10574],{"class":3565,"line":3599},[3563,10575,3577],{"emptyLinePlaceholder":3576},[3563,10577,10578],{"class":3565,"line":3642},[3563,10579,10580],{},"package \"Глобальний Python (❌ БЕЗ venv)\" {\n",[3563,10582,10583],{"class":3565,"line":3649},[3563,10584,10585],{},"    object \"site-packages\" as SP #fee2e2 {\n",[3563,10587,10588],{"class":3565,"line":3659},[3563,10589,10590],{},"        Django = ???  (2.2 або 4.2?)\n",[3563,10592,10593],{"class":3565,"line":3664},[3563,10594,10595],{},"        requests = ???\n",[3563,10597,10598],{"class":3565,"line":3694},[3563,10599,4426],{},[3563,10601,10602],{"class":3565,"line":3700},[3563,10603,10604],{},"    note right of SP\n",[3563,10606,10607],{"class":3565,"line":3708},[3563,10608,10609],{},"      Неможливо встановити\n",[3563,10611,10612],{"class":3565,"line":3713},[3563,10613,10614],{},"      дві версії одночасно!\n",[3563,10616,10617],{"class":3565,"line":3743},[3563,10618,5446],{},[3563,10620,10621],{"class":3565,"line":3749},[3563,10622,4431],{},[3563,10624,10625],{"class":3565,"line":3757},[3563,10626,3577],{"emptyLinePlaceholder":3576},[3563,10628,10629],{"class":3565,"line":3762},[3563,10630,10631],{},"object \"Проект А\\n(Django 2.2)\" as PA #fef3c7\n",[3563,10633,10634],{"class":3565,"line":3785},[3563,10635,10636],{},"object \"Проект Б\\n(Django 4.2)\" as PB #fef3c7\n",[3563,10638,10639],{"class":3565,"line":3791},[3563,10640,3577],{"emptyLinePlaceholder":3576},[3563,10642,10643],{"class":3565,"line":3802},[3563,10644,10645],{},"PA --> SP : потребує Django 2.2\n",[3563,10647,10648],{"class":3565,"line":3807},[3563,10649,10650],{},"PB --> SP : потребує Django 4.2\n",[3563,10652,10653],{"class":3565,"line":3828},[3563,10654,3577],{"emptyLinePlaceholder":3576},[3563,10656,10657],{"class":3565,"line":3834},[3563,10658,10659],{},"note bottom\n",[3563,10661,10662],{"class":3565,"line":3840},[3563,10663,10664],{},"  pip install django==4.2 знищить django==2.2\n",[3563,10666,10667],{"class":3565,"line":3846},[3563,10668,10669],{},"  Проект А зламається!\n",[3563,10671,10672],{"class":3565,"line":3851},[3563,10673,4465],{},[3563,10675,10676],{"class":3565,"line":5463},[3563,10677,4470],{},[4359,10679,10680],{},[3554,10681,10683],{"className":4363,"code":10682,"language":4365,"meta":3559,"style":3559},"@startuml\nskinparam style plain\nskinparam backgroundColor #ffffff\nskinparam ArrowColor #6366f1\n\npackage \"venv_project_a\u002F\" #d1fae5 {\n    object \"site-packages A\" as SPA #d1fae5 {\n        Django = 2.2.28\n        requests = 2.20.0\n    }\n}\n\npackage \"venv_project_b\u002F\" #dbeafe {\n    object \"site-packages B\" as SPB #dbeafe {\n        Django = 4.2.7\n        requests = 2.31.0\n    }\n}\n\nobject \"Проект А\" as PA #fef3c7\nobject \"Проект Б\" as PB #fef3c7\n\nPA --> SPA : ізольоване середовище ✅\nPB --> SPB : ізольоване середовище ✅\n\nnote bottom\n  Обидва проекти незалежні.\n  Жодних конфліктів!\nend note\n@enduml\n",[3398,10684,10685,10689,10693,10697,10701,10705,10710,10715,10720,10725,10729,10733,10737,10742,10747,10752,10757,10761,10765,10769,10774,10779,10783,10788,10793,10797,10801,10806,10811,10815],{"__ignoreMap":3559},[3563,10686,10687],{"class":3565,"line":3566},[3563,10688,4372],{},[3563,10690,10691],{"class":3565,"line":3573},[3563,10692,4377],{},[3563,10694,10695],{"class":3565,"line":3580},[3563,10696,4382],{},[3563,10698,10699],{"class":3565,"line":3594},[3563,10700,4387],{},[3563,10702,10703],{"class":3565,"line":3599},[3563,10704,3577],{"emptyLinePlaceholder":3576},[3563,10706,10707],{"class":3565,"line":3642},[3563,10708,10709],{},"package \"venv_project_a\u002F\" #d1fae5 {\n",[3563,10711,10712],{"class":3565,"line":3649},[3563,10713,10714],{},"    object \"site-packages A\" as SPA #d1fae5 {\n",[3563,10716,10717],{"class":3565,"line":3659},[3563,10718,10719],{},"        Django = 2.2.28\n",[3563,10721,10722],{"class":3565,"line":3664},[3563,10723,10724],{},"        requests = 2.20.0\n",[3563,10726,10727],{"class":3565,"line":3694},[3563,10728,4426],{},[3563,10730,10731],{"class":3565,"line":3700},[3563,10732,4431],{},[3563,10734,10735],{"class":3565,"line":3708},[3563,10736,3577],{"emptyLinePlaceholder":3576},[3563,10738,10739],{"class":3565,"line":3713},[3563,10740,10741],{},"package \"venv_project_b\u002F\" #dbeafe {\n",[3563,10743,10744],{"class":3565,"line":3743},[3563,10745,10746],{},"    object \"site-packages B\" as SPB #dbeafe {\n",[3563,10748,10749],{"class":3565,"line":3749},[3563,10750,10751],{},"        Django = 4.2.7\n",[3563,10753,10754],{"class":3565,"line":3757},[3563,10755,10756],{},"        requests = 2.31.0\n",[3563,10758,10759],{"class":3565,"line":3762},[3563,10760,4426],{},[3563,10762,10763],{"class":3565,"line":3785},[3563,10764,4431],{},[3563,10766,10767],{"class":3565,"line":3791},[3563,10768,3577],{"emptyLinePlaceholder":3576},[3563,10770,10771],{"class":3565,"line":3802},[3563,10772,10773],{},"object \"Проект А\" as PA #fef3c7\n",[3563,10775,10776],{"class":3565,"line":3807},[3563,10777,10778],{},"object \"Проект Б\" as PB #fef3c7\n",[3563,10780,10781],{"class":3565,"line":3828},[3563,10782,3577],{"emptyLinePlaceholder":3576},[3563,10784,10785],{"class":3565,"line":3834},[3563,10786,10787],{},"PA --> SPA : ізольоване середовище ✅\n",[3563,10789,10790],{"class":3565,"line":3840},[3563,10791,10792],{},"PB --> SPB : ізольоване середовище ✅\n",[3563,10794,10795],{"class":3565,"line":3846},[3563,10796,3577],{"emptyLinePlaceholder":3576},[3563,10798,10799],{"class":3565,"line":3851},[3563,10800,10659],{},[3563,10802,10803],{"class":3565,"line":5463},[3563,10804,10805],{},"  Обидва проекти незалежні.\n",[3563,10807,10808],{"class":3565,"line":5468},[3563,10809,10810],{},"  Жодних конфліктів!\n",[3563,10812,10813],{"class":3565,"line":5474},[3563,10814,4465],{},[3563,10816,10817],{"class":3565,"line":5480},[3563,10818,4470],{},[3468,10820,6107,10822,10825],{"id":10821},"що-таке-venv-ізольований-python-від-стандартної-бібліотеки",[3398,10823,10824],{},"venv",": ізольований Python від стандартної бібліотеки",[3394,10827,10828,10832,10833,10836,10837,3459],{},[3406,10829,10830],{},[3398,10831,10824],{}," — це стандартний модуль Python (доступний без встановлення з Python 3.3+), що створює ",[3406,10834,10835],{},"ізольоване середовище виконання",". Технічно це директорія з окремою копією інтерпретатора Python та власною директорією ",[3398,10838,5997],{},[3394,10840,10841,10842,10845,10846,4481,10848,10850,10851,10853],{},"При ",[3406,10843,10844],{},"активації"," venv оболонка перенаправляє команди ",[3398,10847,3558],{},[3398,10849,6155],{}," на копії у середовищі. Будь-яка встановлена бібліотека потрапляє у ",[3398,10852,5997],{}," цього середовища — повністю ізольовано від глобального Python та інших середовищ.",[4287,10855,10857],{"id":10856},"як-venv-працює-під-капотом","Як venv працює під капотом",[3394,10859,10860],{},"Багато хто вважає, що віртуальне середовище — це повна копія інтерпретатора Python. Насправді це дуже легка структура, яка працює завдяки кільком системним конфігураціям та логіці пошуку шляхів самого Python.",[3394,10862,10863,10864,10866,10867,10872],{},"Ключовим елементом будь-якого ",[3398,10865,10824],{}," є файл ",[3406,10868,10869],{},[3398,10870,10871],{},"pyvenv.cfg",", який лежить у корені папки середовища. Його вміст виглядає приблизно так:",[3554,10874,10878],{"className":10875,"code":10876,"language":10877,"meta":3559,"style":3559},"language-ini shiki shiki-themes light-plus dark-plus dark-plus","home = \u002Fusr\u002Fbin\ninclude-system-site-packages = false\nversion = 3.12.2\nexecutable = \u002Fusr\u002Fbin\u002Fpython3.12\ncommand = \u002Fusr\u002Fbin\u002Fpython3 -m venv \u002Fhome\u002Fuser\u002Fmyproject\u002F.venv\n","ini",[3398,10879,10880,10888,10896,10904,10912],{"__ignoreMap":3559},[3563,10881,10882,10885],{"class":3565,"line":3566},[3563,10883,10884],{"class":3602},"home",[3563,10886,10887],{"class":3583}," = \u002Fusr\u002Fbin\n",[3563,10889,10890,10893],{"class":3565,"line":3573},[3563,10891,10892],{"class":3602},"include-system-site-packages",[3563,10894,10895],{"class":3583}," = false\n",[3563,10897,10898,10901],{"class":3565,"line":3580},[3563,10899,10900],{"class":3602},"version",[3563,10902,10903],{"class":3583}," = 3.12.2\n",[3563,10905,10906,10909],{"class":3565,"line":3594},[3563,10907,10908],{"class":3602},"executable",[3563,10910,10911],{"class":3583}," = \u002Fusr\u002Fbin\u002Fpython3.12\n",[3563,10913,10914,10917],{"class":3565,"line":3599},[3563,10915,10916],{"class":3602},"command",[3563,10918,10919],{"class":3583}," = \u002Fusr\u002Fbin\u002Fpython3 -m venv \u002Fhome\u002Fuser\u002Fmyproject\u002F.venv\n",[3394,10921,10922,10923,10926,10927,10930],{},"Коли ви запускаєте файл ",[3398,10924,10925],{},".venv\u002Fbin\u002Fpython"," (або ",[3398,10928,10929],{},".venv\u002FScripts\u002Fpython.exe"," на Windows), відбувається такий алгоритм:",[3505,10932,10933,10942,10976],{},[3508,10934,10935,10938,10939,10941],{},[3406,10936,10937],{},"Пошук конфігурації",":\nІнтерпретатор шукає файл ",[3398,10940,10871],{}," у своїй директорії або директорії на рівень вище.",[3508,10943,10944,4297,10947],{},[3406,10945,10946],{},"Встановлення префіксів",[5138,10948,10949,10954,10965],{},[3508,10950,7270,10951,10953],{},[3398,10952,10871],{}," знайдено, Python розуміє, що він запущений всередині віртуального середовища.",[3508,10955,10327,10956,10961,10962,10964],{},[3406,10957,10958],{},[3398,10959,10960],{},"sys.base_prefix"," встановлюється на шлях із параметра ",[3398,10963,10884],{}," (це глобальна установка Python, де лежить реальний виконуваний файл і стандартна бібліотека).",[3508,10966,10327,10967,10972,10973,10975],{},[3406,10968,10969],{},[3398,10970,10971],{},"sys.prefix"," встановлюється на директорію, де лежить ",[3398,10974,10871],{}," (тобто на ваше віртуальне середовище).",[3508,10977,10978,10983,10984,10986,10987,10989,10990,10993,10994,3459],{},[3406,10979,10980,10981],{},"Формування ",[3398,10982,3517],{},":\nПри формуванні шляхів пошуку модулів Python використовує значення ",[3398,10985,10971],{},". Завдяки цьому він підключає ",[3398,10988,5997],{}," із папки ",[3398,10991,10992],{},".venv\u002Flib\u002Fpython3.X\u002Fsite-packages\u002F"," замість глобального ",[3398,10995,5997],{},[3394,10997,10998,10999,11002],{},"Скрипт активації (",[3398,11000,11001],{},"source .venv\u002Fbin\u002Factivate",") насправді є дуже простим оболонковим (shell) скриптом, який робить лише дві речі:",[3505,11004,11005,11021],{},[3508,11006,11007,11008,11011,11012,11015,11016,4310,11018,11020],{},"Додає шлях до ",[3398,11009,11010],{},".venv\u002Fbin\u002F"," на самий початок змінної середовища вашої системи ",[3398,11013,11014],{},"PATH",". Завдяки цьому, коли ви вводите ",[3398,11017,3558],{},[3398,11019,6155],{},", викликаються саме файли з вашого середовища, а не глобальні.",[3508,11022,11023,11024,3459],{},"Тимчасово змінює промпт вашого терміналу, додаючи ",[3398,11025,11026],{},"(.venv) ",[11028,11029,11030,11031,11034,11035,3459],"note",{},"Активація через ",[3398,11032,11033],{},"source"," — це зручність для терміналу. Програми та IDE можуть працювати з venv без будь-якої активації — їм просто достатньо запускати інтерпретатор безпосередньо за шляхом ",[3398,11036,10925],{},[3468,11038,11040],{"id":11039},"повний-цикл-роботи-з-venv","Повний цикл роботи з venv",[3394,11042,11043],{},[3406,11044,11045],{},"Крок 1: Створення середовища",[3554,11047,11051],{"className":11048,"code":11049,"language":11050,"meta":3559,"style":3559},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","# python -m venv \u003Cназва_директорії>\n# Конвенція: називати середовище 'venv' або '.venv'\n\npython -m venv venv        # звичайне середовище\npython -m venv .venv       # приховане (починається з крапки)\npython3.12 -m venv .venv   # явна версія Python\n","bash",[3398,11052,11053,11058,11063,11067,11082,11096],{"__ignoreMap":3559},[3563,11054,11055],{"class":3565,"line":3566},[3563,11056,11057],{"class":3569},"# python -m venv \u003Cназва_директорії>\n",[3563,11059,11060],{"class":3565,"line":3573},[3563,11061,11062],{"class":3569},"# Конвенція: називати середовище 'venv' або '.venv'\n",[3563,11064,11065],{"class":3565,"line":3580},[3563,11066,3577],{"emptyLinePlaceholder":3576},[3563,11068,11069,11071,11074,11077,11079],{"class":3565,"line":3594},[3563,11070,3558],{"class":3606},[3563,11072,11073],{"class":3602}," -m",[3563,11075,11076],{"class":3645}," venv",[3563,11078,11076],{"class":3645},[3563,11080,11081],{"class":3569},"        # звичайне середовище\n",[3563,11083,11084,11086,11088,11090,11093],{"class":3565,"line":3599},[3563,11085,3558],{"class":3606},[3563,11087,11073],{"class":3602},[3563,11089,11076],{"class":3645},[3563,11091,11092],{"class":3645}," .venv",[3563,11094,11095],{"class":3569},"       # приховане (починається з крапки)\n",[3563,11097,11098,11101,11103,11105,11107],{"class":3565,"line":3642},[3563,11099,11100],{"class":3606},"python3.12",[3563,11102,11073],{"class":3602},[3563,11104,11076],{"class":3645},[3563,11106,11092],{"class":3645},[3563,11108,11109],{"class":3569},"   # явна версія Python\n",[3394,11111,11112],{},"Після виконання команди Python створює таку структуру:",[3554,11114,11117],{"className":11115,"code":11116,"language":8718},[8716],".venv\u002F\n├── bin\u002F                    # (Linux\u002FmacOS)\n│   ├── python              # символічне посилання на інтерпретатор\n│   ├── python3\n│   ├── pip\n│   └── activate            # скрипт активації!\n├── lib\u002F\n│   └── python3.12\u002F\n│       └── site-packages\u002F  # сюди pip встановлює пакети\n└── pyvenv.cfg              # конфігурація середовища\n",[3398,11118,11116],{"__ignoreMap":3559},[3394,11120,11121],{},[3406,11122,11123],{},"Крок 2: Активація середовища",[3394,11125,11126,11127,3624,11129,11132,11133,4481,11135,11137],{},"Активація — це зміна змінних середовища оболонки (",[3398,11128,11014],{},[3398,11130,11131],{},"VIRTUAL_ENV",") так, щоб команди ",[3398,11134,3558],{},[3398,11136,6155],{}," вели до venv.",[4828,11139,11140,11194,11242],{},[4831,11141,11143],{"label":11142},"macOS \u002F Linux (bash\u002Fzsh)",[3554,11144,11146],{"className":11048,"code":11145,"language":11050,"meta":3559,"style":3559},"source .venv\u002Fbin\u002Factivate\n\n# Підтвердження активації: у промпті з'явиться назва середовища\n# (.venv) user@host:~\u002Fmyproject$\n\nwhich python  # \u002Fhome\u002Fuser\u002Fmyproject\u002F.venv\u002Fbin\u002Fpython\nwhich pip     # \u002Fhome\u002Fuser\u002Fmyproject\u002F.venv\u002Fbin\u002Fpip\n",[3398,11147,11148,11155,11159,11164,11169,11173,11184],{"__ignoreMap":3559},[3563,11149,11150,11152],{"class":3565,"line":3566},[3563,11151,11033],{"class":3606},[3563,11153,11154],{"class":3645}," .venv\u002Fbin\u002Factivate\n",[3563,11156,11157],{"class":3565,"line":3573},[3563,11158,3577],{"emptyLinePlaceholder":3576},[3563,11160,11161],{"class":3565,"line":3580},[3563,11162,11163],{"class":3569},"# Підтвердження активації: у промпті з'явиться назва середовища\n",[3563,11165,11166],{"class":3565,"line":3594},[3563,11167,11168],{"class":3569},"# (.venv) user@host:~\u002Fmyproject$\n",[3563,11170,11171],{"class":3565,"line":3599},[3563,11172,3577],{"emptyLinePlaceholder":3576},[3563,11174,11175,11178,11181],{"class":3565,"line":3642},[3563,11176,11177],{"class":3606},"which",[3563,11179,11180],{"class":3645}," python",[3563,11182,11183],{"class":3569},"  # \u002Fhome\u002Fuser\u002Fmyproject\u002F.venv\u002Fbin\u002Fpython\n",[3563,11185,11186,11188,11191],{"class":3565,"line":3649},[3563,11187,11177],{"class":3606},[3563,11189,11190],{"class":3645}," pip",[3563,11192,11193],{"class":3569},"     # \u002Fhome\u002Fuser\u002Fmyproject\u002F.venv\u002Fbin\u002Fpip\n",[4831,11195,11197],{"label":11196},"Windows (CMD)",[3554,11198,11202],{"className":11199,"code":11200,"language":11201,"meta":3559,"style":3559},"language-bat shiki shiki-themes light-plus dark-plus dark-plus",".venv\\Scripts\\activate.bat\n\n:: Або в PowerShell:\n.venv\\Scripts\\Activate.ps1\n\n:: Підтвердження: (.venv) C:\\myproject>\nwhere python\n:: C:\\myproject\\.venv\\Scripts\\python.exe\n","bat",[3398,11203,11204,11209,11213,11218,11223,11227,11232,11237],{"__ignoreMap":3559},[3563,11205,11206],{"class":3565,"line":3566},[3563,11207,11208],{},".venv\\Scripts\\activate.bat\n",[3563,11210,11211],{"class":3565,"line":3573},[3563,11212,3577],{"emptyLinePlaceholder":3576},[3563,11214,11215],{"class":3565,"line":3580},[3563,11216,11217],{},":: Або в PowerShell:\n",[3563,11219,11220],{"class":3565,"line":3594},[3563,11221,11222],{},".venv\\Scripts\\Activate.ps1\n",[3563,11224,11225],{"class":3565,"line":3599},[3563,11226,3577],{"emptyLinePlaceholder":3576},[3563,11228,11229],{"class":3565,"line":3642},[3563,11230,11231],{},":: Підтвердження: (.venv) C:\\myproject>\n",[3563,11233,11234],{"class":3565,"line":3649},[3563,11235,11236],{},"where python\n",[3563,11238,11239],{"class":3565,"line":3659},[3563,11240,11241],{},":: C:\\myproject\\.venv\\Scripts\\python.exe\n",[4831,11243,11245],{"label":11244},"Fish Shell",[3554,11246,11250],{"className":11247,"code":11248,"language":11249,"meta":3559,"style":3559},"language-fish shiki shiki-themes light-plus dark-plus dark-plus","source .venv\u002Fbin\u002Factivate.fish\n","fish",[3398,11251,11252],{"__ignoreMap":3559},[3563,11253,11254],{"class":3565,"line":3566},[3563,11255,11248],{},[3394,11257,11258],{},[3406,11259,11260],{},"Крок 3: Встановлення пакетів",[3394,11262,11263,11264,11266,11267,4297],{},"Після активації ",[3398,11265,5864],{}," встановлює пакети ізольовано у ",[3398,11268,10992],{},[3554,11270,11272],{"className":11048,"code":11271,"language":11050,"meta":3559,"style":3559},"# Встановлення з PyPI\npip install requests                   # остання версія\npip install requests==2.31.0           # конкретна версія\npip install \"requests>=2.28,\u003C3.0\"      # діапазон версій\npip install django djangorestframework  # кілька одразу\n\n# Список встановлених пакетів\npip list\n\n# Детальна інформація про пакет\npip show requests\n",[3398,11273,11274,11279,11292,11307,11319,11334,11338,11343,11350,11354,11359],{"__ignoreMap":3559},[3563,11275,11276],{"class":3565,"line":3566},[3563,11277,11278],{"class":3569},"# Встановлення з PyPI\n",[3563,11280,11281,11283,11286,11289],{"class":3565,"line":3573},[3563,11282,6155],{"class":3606},[3563,11284,11285],{"class":3645}," install",[3563,11287,11288],{"class":3645}," requests",[3563,11290,11291],{"class":3569},"                   # остання версія\n",[3563,11293,11294,11296,11298,11301,11304],{"class":3565,"line":3580},[3563,11295,6155],{"class":3606},[3563,11297,11285],{"class":3645},[3563,11299,11300],{"class":3645}," requests==",[3563,11302,11303],{"class":3587},"2.31.0",[3563,11305,11306],{"class":3569},"           # конкретна версія\n",[3563,11308,11309,11311,11313,11316],{"class":3565,"line":3594},[3563,11310,6155],{"class":3606},[3563,11312,11285],{"class":3645},[3563,11314,11315],{"class":3645}," \"requests>=2.28,\u003C3.0\"",[3563,11317,11318],{"class":3569},"      # діапазон версій\n",[3563,11320,11321,11323,11325,11328,11331],{"class":3565,"line":3599},[3563,11322,6155],{"class":3606},[3563,11324,11285],{"class":3645},[3563,11326,11327],{"class":3645}," django",[3563,11329,11330],{"class":3645}," djangorestframework",[3563,11332,11333],{"class":3569},"  # кілька одразу\n",[3563,11335,11336],{"class":3565,"line":3642},[3563,11337,3577],{"emptyLinePlaceholder":3576},[3563,11339,11340],{"class":3565,"line":3649},[3563,11341,11342],{"class":3569},"# Список встановлених пакетів\n",[3563,11344,11345,11347],{"class":3565,"line":3659},[3563,11346,6155],{"class":3606},[3563,11348,11349],{"class":3645}," list\n",[3563,11351,11352],{"class":3565,"line":3664},[3563,11353,3577],{"emptyLinePlaceholder":3576},[3563,11355,11356],{"class":3565,"line":3694},[3563,11357,11358],{"class":3569},"# Детальна інформація про пакет\n",[3563,11360,11361,11363,11366],{"class":3565,"line":3700},[3563,11362,6155],{"class":3606},[3563,11364,11365],{"class":3645}," show",[3563,11367,11368],{"class":3645}," requests\n",[4032,11370,11372,11385,11389,11393,11397,11401,11405,11409,11413,11417],{"title":11371},"Процес встановлення пакета у venv",[4036,11373,11375,4044,11379,4044,11382],{"className":11374},[3565],[3563,11376,11378],{"className":11377},[4054],"(.venv)",[3563,11380,4043],{"className":11381},[4042],[3406,11383,11384],{},"pip install requests",[4036,11386,11388],{"className":11387},[3565],"Collecting requests",[4036,11390,11392],{"className":11391},[3565],"  Downloading requests-2.31.0-py3-none-any.whl (62 kB)",[4036,11394,11396],{"className":11395},[3565],"     ━━━━━━━━━━━━━━━━━━━━━━ 62.6\u002F62.6 kB 1.2 MB\u002Fs eta 0:00:00",[4036,11398,11400],{"className":11399},[3565],"Collecting charset-normalizer\u003C4,>=2 (from requests)",[4036,11402,11404],{"className":11403},[3565],"Collecting idna\u003C4,>=2.5 (from requests)",[4036,11406,11408],{"className":11407},[3565],"Collecting urllib3\u003C3,>=1.21.1 (from requests)",[4036,11410,11412],{"className":11411},[3565],"Collecting certifi>=2017.4.17 (from requests)",[4036,11414,11416],{"className":11415},[3565],"Installing collected packages: urllib3, idna, certifi, charset-normalizer, requests",[4036,11418,11420,11421,11425],{"className":11419},[3565],"Successfully installed certifi-2024.2.2 charset-normalizer-3.3.2 idna-3.7 ",[3563,11422,11424],{"className":11423},[4054],"requests-2.31.0"," urllib3-2.2.1",[3394,11427,11428],{},[3406,11429,11430],{},"Крок 4: Деактивація",[3554,11432,11434],{"className":11048,"code":11433,"language":11050,"meta":3559,"style":3559},"deactivate\n\n# Промпт повернувся до нормального вигляду:\n# user@host:~\u002Fmyproject$\n\nwhich python  # \u002Fusr\u002Fbin\u002Fpython3  ← глобальний Python\n",[3398,11435,11436,11441,11445,11450,11455,11459],{"__ignoreMap":3559},[3563,11437,11438],{"class":3565,"line":3566},[3563,11439,11440],{"class":3606},"deactivate\n",[3563,11442,11443],{"class":3565,"line":3573},[3563,11444,3577],{"emptyLinePlaceholder":3576},[3563,11446,11447],{"class":3565,"line":3580},[3563,11448,11449],{"class":3569},"# Промпт повернувся до нормального вигляду:\n",[3563,11451,11452],{"class":3565,"line":3594},[3563,11453,11454],{"class":3569},"# user@host:~\u002Fmyproject$\n",[3563,11456,11457],{"class":3565,"line":3599},[3563,11458,3577],{"emptyLinePlaceholder":3576},[3563,11460,11461,11463,11465],{"class":3565,"line":3642},[3563,11462,11177],{"class":3606},[3563,11464,11180],{"class":3645},[3563,11466,11467],{"class":3569},"  # \u002Fusr\u002Fbin\u002Fpython3  ← глобальний Python\n",[3468,11469,11471,11474],{"id":11470},"requirementstxt-заморожування-залежностей",[3398,11472,11473],{},"requirements.txt",": заморожування залежностей",[3394,11476,10010,11477,11479],{},[3398,11478,11473],{}," — це текстовий маніфест точних версій усіх пакетів, потрібних вашому проекту. Він є стандартом відтворюваності Python-проектів.",[3394,11481,11482],{},[3406,11483,11484,11485,11487],{},"Генерація ",[3398,11486,11473],{}," з активного середовища:",[3554,11489,11491],{"className":11048,"code":11490,"language":11050,"meta":3559,"style":3559},"# pip freeze виводить всі встановлені пакети з точними версіями\npip freeze > requirements.txt\n\ncat requirements.txt\n",[3398,11492,11493,11498,11511,11515],{"__ignoreMap":3559},[3563,11494,11495],{"class":3565,"line":3566},[3563,11496,11497],{"class":3569},"# pip freeze виводить всі встановлені пакети з точними версіями\n",[3563,11499,11500,11502,11505,11508],{"class":3565,"line":3573},[3563,11501,6155],{"class":3606},[3563,11503,11504],{"class":3645}," freeze",[3563,11506,11507],{"class":3583}," > ",[3563,11509,11510],{"class":3645},"requirements.txt\n",[3563,11512,11513],{"class":3565,"line":3580},[3563,11514,3577],{"emptyLinePlaceholder":3576},[3563,11516,11517,11520],{"class":3565,"line":3594},[3563,11518,11519],{"class":3606},"cat",[3563,11521,11522],{"class":3645}," requirements.txt\n",[4032,11524,11526,11538,11547,11551,11555,11559,11566],{"title":11525},"requirements.txt: зафіксовані залежності",[4036,11527,11529,4044,11532,4044,11535],{"className":11528},[3565],[3563,11530,11378],{"className":11531},[4054],[3563,11533,4043],{"className":11534},[4042],[3406,11536,11537],{},"pip freeze > requirements.txt",[4036,11539,11541,4044,11544],{"className":11540},[3565],[3563,11542,4043],{"className":11543},[4042],[3406,11545,11546],{},"cat requirements.txt",[4036,11548,11550],{"className":11549},[3565],"certifi==2024.2.2",[4036,11552,11554],{"className":11553},[3565],"charset-normalizer==3.3.2",[4036,11556,11558],{"className":11557},[3565],"idna==3.7",[4036,11560,11562],{"className":11561},[3565],[3563,11563,11565],{"className":11564},[4071],"requests==2.31.0",[4036,11567,11569],{"className":11568},[3565],"urllib3==2.2.1",[3394,11571,11572],{},[3406,11573,11574,11575,4297],{},"Відтворення середовища з ",[3398,11576,11473],{},[3554,11578,11580],{"className":11048,"code":11579,"language":11050,"meta":3559,"style":3559},"# На іншій машині або у CI\u002FCD:\npython -m venv .venv\nsource .venv\u002Fbin\u002Factivate\n\npip install -r requirements.txt\n# pip встановить точно ті ж версії, що зафіксовані у файлі\n",[3398,11581,11582,11587,11598,11604,11608,11619],{"__ignoreMap":3559},[3563,11583,11584],{"class":3565,"line":3566},[3563,11585,11586],{"class":3569},"# На іншій машині або у CI\u002FCD:\n",[3563,11588,11589,11591,11593,11595],{"class":3565,"line":3573},[3563,11590,3558],{"class":3606},[3563,11592,11073],{"class":3602},[3563,11594,11076],{"class":3645},[3563,11596,11597],{"class":3645}," .venv\n",[3563,11599,11600,11602],{"class":3565,"line":3580},[3563,11601,11033],{"class":3606},[3563,11603,11154],{"class":3645},[3563,11605,11606],{"class":3565,"line":3594},[3563,11607,3577],{"emptyLinePlaceholder":3576},[3563,11609,11610,11612,11614,11617],{"class":3565,"line":3599},[3563,11611,6155],{"class":3606},[3563,11613,11285],{"class":3645},[3563,11615,11616],{"class":3602}," -r",[3563,11618,11522],{"class":3645},[3563,11620,11621],{"class":3565,"line":3642},[3563,11622,11623],{"class":3569},"# pip встановить точно ті ж версії, що зафіксовані у файлі\n",[10286,11625,11626,11629,11630,11633,11634,11636,11637,3624,11640,3624,11643,11646,11647,11649,11650,11652],{},[3406,11627,11628],{},"Сучасна альтернатива:"," Сьогодні у нових проектах часто використовують ",[3398,11631,11632],{},"pyproject.toml"," (стандарт PEP 517\u002F518) замість ",[3398,11635,11473],{},". Менеджери пакетів ",[3398,11638,11639],{},"poetry",[3398,11641,11642],{},"uv",[3398,11644,11645],{},"pdm"," — надають більш потужне управління залежностями. Але ",[3398,11648,11473],{}," + ",[3398,11651,10824],{}," залишаються базовим стандартом, який потрібно знати.",[3461,11654],{},[3389,11656,11658],{"id":11657},"частина-iv-сучасні-менеджери-пакетів","Частина IV: Сучасні менеджери пакетів",[3394,11660,11661,11662,11649,11664,11649,11666,11668],{},"Стандартний тандем ",[3398,11663,10824],{},[3398,11665,6155],{},[3398,11667,11473],{}," надійний і повсюдно підтримуваний. Але у виробничих проектах він має відомі недоліки:",[5138,11670,11671,11681,11688,11695],{},[3508,11672,11673,11676,11677,11680],{},[3398,11674,11675],{},"pip freeze"," включає ",[3406,11678,11679],{},"транзитивні"," залежності (ті, що потрібні вашим залежностям), а не лише прямі — файл стає важким до читання і крихким при оновленні.",[3508,11682,11683,11684,11687],{},"Немає ",[3406,11685,11686],{},"детермінованого lockfile"," зі сумами хешів для кожної платформи окремо.",[3508,11689,11690,11691,11694],{},"Немає вбудованого управління ",[3406,11692,11693],{},"версіями Python"," або запуску команд у ізольованому середовищі.",[3508,11696,11697,11699],{},[3398,11698,6155],{}," не вирішує конфлікти залежностей наперед — він просто встановлює і повідомляє про помилку вже після.",[3394,11701,11702,11703,11707,11708,11713],{},"Два найпопулярніші інструменти, що вирішують ці проблеми: ",[3406,11704,11705],{},[3398,11706,11642],{}," (наступне покоління, швидкість у 10–100 разів вища за pip) та ",[3406,11709,11710],{},[3398,11711,11712],{},"Poetry"," (зрілий, широко розповсюджений у промисловому середовищі).",[3461,11715],{},[3468,11717,11719,11721],{"id":11718},"uv-ультрашвидкий-менеджер-нового-покоління",[3398,11720,11642],{}," — ультрашвидкий менеджер нового покоління",[3394,11723,11724,11728,11729,11732,11733,3624,11735,3624,11738,3624,11741,11744,11745,11747],{},[3406,11725,11726],{},[3398,11727,11642],{}," — це інструмент від компанії Astral (автори лінтера ",[3398,11730,11731],{},"ruff","), написаний на Rust. Він замінює одразу кілька інструментів: ",[3398,11734,6155],{},[3398,11736,11737],{},"pip-tools",[3398,11739,11740],{},"virtualenv",[3398,11742,11743],{},"pyenv"," та частково ",[3398,11746,11639],{}," — з єдиного бінарного файлу.",[3411,11749,11750,11757,11778,11790],{},[3414,11751,11754,11756],{"icon":11752,"title":11753},"i-heroicons-bolt","10–100x швидше за pip",[3398,11755,11642],{}," використовує паралельне завантаження пакетів і оптимізований резолвер залежностей. Встановлення Django з усіма залежностями займає менше секунди проти 10–30 секунд у pip.",[3414,11758,11761,11762,11765,11766,11769,11770,11773,11774,11777],{"icon":11759,"title":11760},"i-heroicons-wrench-screwdriver","Єдиний інструмент","Управляє версіями Python (",[3398,11763,11764],{},"uv python install 3.12","), середовищами (",[3398,11767,11768],{},"uv venv","), залежностями (",[3398,11771,11772],{},"uv add\u002Fremove",") та інструментами CLI (",[3398,11775,11776],{},"uvx ruff","). Один бінарний файл замість п'яти.",[3414,11779,11782,11785,11786,11789],{"icon":11780,"title":11781},"i-heroicons-lock-closed","Детермінований lockfile",[3398,11783,11784],{},"uv.lock"," фіксує точні версії та хеші для всіх платформ. Синхронізація через ",[3398,11787,11788],{},"uv sync"," гарантує ідентичне середовище на будь-якій машині.",[3414,11791,11794,11795,11797,11798,11649,11800,11649,11803,3459],{"icon":11792,"title":11793},"i-heroicons-document-text","pyproject.toml (PEP 621)","Використовує стандарт ",[3398,11796,11632],{}," як єдину точку конфігурації замість ",[3398,11799,11473],{},[3398,11801,11802],{},"setup.py",[3398,11804,11805],{},"setup.cfg",[4287,11807,11809,11810],{"id":11808},"встановлення-uv","Встановлення ",[3398,11811,11642],{},[3554,11813,11815],{"className":11048,"code":11814,"language":11050,"meta":3559,"style":3559},"# macOS \u002F Linux\ncurl -LsSf https:\u002F\u002Fastral.sh\u002Fuv\u002Finstall.sh | sh\n\n# Windows (PowerShell)\npowershell -ExecutionPolicy ByPass -c \"irm https:\u002F\u002Fastral.sh\u002Fuv\u002Finstall.ps1 | iex\"\n\n# Також через pip (якщо вже є Python):\npip install uv\n\n# Перевірка встановлення\nuv --version  # uv 0.5.x (або новіше)\n",[3398,11816,11817,11822,11838,11842,11847,11864,11868,11873,11882,11886,11891],{"__ignoreMap":3559},[3563,11818,11819],{"class":3565,"line":3566},[3563,11820,11821],{"class":3569},"# macOS \u002F Linux\n",[3563,11823,11824,11827,11830,11833,11835],{"class":3565,"line":3573},[3563,11825,11826],{"class":3606},"curl",[3563,11828,11829],{"class":3602}," -LsSf",[3563,11831,11832],{"class":3645}," https:\u002F\u002Fastral.sh\u002Fuv\u002Finstall.sh",[3563,11834,9197],{"class":3583},[3563,11836,11837],{"class":3606},"sh\n",[3563,11839,11840],{"class":3565,"line":3580},[3563,11841,3577],{"emptyLinePlaceholder":3576},[3563,11843,11844],{"class":3565,"line":3594},[3563,11845,11846],{"class":3569},"# Windows (PowerShell)\n",[3563,11848,11849,11852,11855,11858,11861],{"class":3565,"line":3599},[3563,11850,11851],{"class":3606},"powershell",[3563,11853,11854],{"class":3602}," -ExecutionPolicy",[3563,11856,11857],{"class":3645}," ByPass",[3563,11859,11860],{"class":3602}," -c",[3563,11862,11863],{"class":3645}," \"irm https:\u002F\u002Fastral.sh\u002Fuv\u002Finstall.ps1 | iex\"\n",[3563,11865,11866],{"class":3565,"line":3642},[3563,11867,3577],{"emptyLinePlaceholder":3576},[3563,11869,11870],{"class":3565,"line":3649},[3563,11871,11872],{"class":3569},"# Також через pip (якщо вже є Python):\n",[3563,11874,11875,11877,11879],{"class":3565,"line":3659},[3563,11876,6155],{"class":3606},[3563,11878,11285],{"class":3645},[3563,11880,11881],{"class":3645}," uv\n",[3563,11883,11884],{"class":3565,"line":3664},[3563,11885,3577],{"emptyLinePlaceholder":3576},[3563,11887,11888],{"class":3565,"line":3694},[3563,11889,11890],{"class":3569},"# Перевірка встановлення\n",[3563,11892,11893,11895,11898],{"class":3565,"line":3700},[3563,11894,11642],{"class":3606},[3563,11896,11897],{"class":3602}," --version",[3563,11899,11900],{"class":3569},"  # uv 0.5.x (або новіше)\n",[4287,11902,11904],{"id":11903},"створення-нового-проекту-з-нуля","Створення нового проекту з нуля",[3554,11906,11908],{"className":11048,"code":11907,"language":11050,"meta":3559,"style":3559},"# Ініціалізація проекту — створює pyproject.toml і базову структуру\nuv init my-web-api\ncd my-web-api\n\n# Або ініціалізація у поточній директорії\nmkdir my-project && cd my-project\nuv init\n",[3398,11909,11910,11915,11925,11932,11936,11941,11957],{"__ignoreMap":3559},[3563,11911,11912],{"class":3565,"line":3566},[3563,11913,11914],{"class":3569},"# Ініціалізація проекту — створює pyproject.toml і базову структуру\n",[3563,11916,11917,11919,11922],{"class":3565,"line":3573},[3563,11918,11642],{"class":3606},[3563,11920,11921],{"class":3645}," init",[3563,11923,11924],{"class":3645}," my-web-api\n",[3563,11926,11927,11930],{"class":3565,"line":3580},[3563,11928,11929],{"class":3606},"cd",[3563,11931,11924],{"class":3645},[3563,11933,11934],{"class":3565,"line":3594},[3563,11935,3577],{"emptyLinePlaceholder":3576},[3563,11937,11938],{"class":3565,"line":3599},[3563,11939,11940],{"class":3569},"# Або ініціалізація у поточній директорії\n",[3563,11942,11943,11946,11949,11952,11954],{"class":3565,"line":3642},[3563,11944,11945],{"class":3606},"mkdir",[3563,11947,11948],{"class":3645}," my-project",[3563,11950,11951],{"class":3583}," && ",[3563,11953,11929],{"class":3606},[3563,11955,11956],{"class":3645}," my-project\n",[3563,11958,11959,11961],{"class":3565,"line":3649},[3563,11960,11642],{"class":3606},[3563,11962,11963],{"class":3645}," init\n",[4032,11965,11967,11976,11980,11989,11993,12002,12009,12016],{"title":11966},"uv init — структура нового проекту",[4036,11968,11970,4044,11973],{"className":11969},[3565],[3563,11971,4043],{"className":11972},[4042],[3406,11974,11975],{},"uv init my-web-api",[4036,11977,11979],{"className":11978},[3565],"Initialized project `my-web-api` at `\u002FUsers\u002Fuser\u002Fmy-web-api`",[4036,11981,11983,4044,11986],{"className":11982},[3565],[3563,11984,4043],{"className":11985},[4042],[3406,11987,11988],{},"tree my-web-api\u002F",[4036,11990,11992],{"className":11991},[3565],"my-web-api\u002F",[4036,11994,11996,11997,12001],{"className":11995},[3565],"├── ",[3563,11998,12000],{"className":11999},[4071],".python-version","   ← фіксована версія Python",[4036,12003,11996,12005,12008],{"className":12004},[3565],[3563,12006,11632],{"className":12007},[5716],"    ← конфігурація проекту",[4036,12010,11996,12012],{"className":12011},[3565],[3563,12013,12015],{"className":12014},[4054],"README.md",[4036,12017,12019,12020,12024],{"className":12018},[3565],"└── ",[3563,12021,12023],{"className":12022},[4071],"hello.py","          ← точка входу",[3394,12026,12027,12028,12031,12032,4297],{},"Після ",[3398,12029,12030],{},"uv init"," проект вже має ",[3398,12033,11632],{},[3554,12035,12039],{"className":12036,"code":12037,"language":12038,"meta":3559,"style":3559},"language-toml shiki shiki-themes light-plus dark-plus dark-plus","# pyproject.toml (генерується автоматично)\n[project]\nname = \"my-web-api\"\nversion = \"0.1.0\"\ndescription = \"Add your description here\"\nreadme = \"README.md\"\nrequires-python = \">=3.12\"\ndependencies = []\n","toml",[3398,12040,12041,12046,12051,12060,12069,12079,12089,12099],{"__ignoreMap":3559},[3563,12042,12043],{"class":3565,"line":3566},[3563,12044,12045],{"class":3569},"# pyproject.toml (генерується автоматично)\n",[3563,12047,12048],{"class":3565,"line":3573},[3563,12049,12050],{"class":3583},"[project]\n",[3563,12052,12053,12055,12057],{"class":3565,"line":3580},[3563,12054,9494],{"class":3613},[3563,12056,8871],{"class":3583},[3563,12058,12059],{"class":3645},"\"my-web-api\"\n",[3563,12061,12062,12064,12066],{"class":3565,"line":3594},[3563,12063,10900],{"class":3613},[3563,12065,8871],{"class":3583},[3563,12067,12068],{"class":3645},"\"0.1.0\"\n",[3563,12070,12071,12074,12076],{"class":3565,"line":3599},[3563,12072,12073],{"class":3613},"description",[3563,12075,8871],{"class":3583},[3563,12077,12078],{"class":3645},"\"Add your description here\"\n",[3563,12080,12081,12084,12086],{"class":3565,"line":3642},[3563,12082,12083],{"class":3613},"readme",[3563,12085,8871],{"class":3583},[3563,12087,12088],{"class":3645},"\"README.md\"\n",[3563,12090,12091,12094,12096],{"class":3565,"line":3649},[3563,12092,12093],{"class":3613},"requires-python",[3563,12095,8871],{"class":3583},[3563,12097,12098],{"class":3645},"\">=3.12\"\n",[3563,12100,12101,12104],{"class":3565,"line":3659},[3563,12102,12103],{"class":3613},"dependencies",[3563,12105,12106],{"class":3583}," = []\n",[4287,12108,12110],{"id":12109},"управління-залежностями","Управління залежностями",[3554,12112,12114],{"className":11048,"code":12113,"language":11050,"meta":3559,"style":3559},"# Додавання залежності — оновлює pyproject.toml і uv.lock автоматично\nuv add fastapi\nuv add \"sqlalchemy>=2.0\"\nuv add \"pydantic>=2.5,\u003C3.0\"\n\n# Кілька залежностей одразу\nuv add httpx aiohttp redis\n\n# Залежності лише для розробки (не потрапляють у production)\nuv add --dev pytest pytest-asyncio ruff mypy\nuv add --dev black isort\n\n# Видалення залежності\nuv remove redis\n\n# Синхронізація середовища з lockfile (аналог pip install -r requirements.txt)\nuv sync\n\n# Синхронізація без dev-залежностей (для production)\nuv sync --no-dev\n",[3398,12115,12116,12121,12130,12139,12148,12152,12157,12172,12176,12181,12202,12216,12220,12225,12234,12238,12243,12250,12254,12259],{"__ignoreMap":3559},[3563,12117,12118],{"class":3565,"line":3566},[3563,12119,12120],{"class":3569},"# Додавання залежності — оновлює pyproject.toml і uv.lock автоматично\n",[3563,12122,12123,12125,12127],{"class":3565,"line":3573},[3563,12124,11642],{"class":3606},[3563,12126,3607],{"class":3645},[3563,12128,12129],{"class":3645}," fastapi\n",[3563,12131,12132,12134,12136],{"class":3565,"line":3580},[3563,12133,11642],{"class":3606},[3563,12135,3607],{"class":3645},[3563,12137,12138],{"class":3645}," \"sqlalchemy>=2.0\"\n",[3563,12140,12141,12143,12145],{"class":3565,"line":3594},[3563,12142,11642],{"class":3606},[3563,12144,3607],{"class":3645},[3563,12146,12147],{"class":3645}," \"pydantic>=2.5,\u003C3.0\"\n",[3563,12149,12150],{"class":3565,"line":3599},[3563,12151,3577],{"emptyLinePlaceholder":3576},[3563,12153,12154],{"class":3565,"line":3642},[3563,12155,12156],{"class":3569},"# Кілька залежностей одразу\n",[3563,12158,12159,12161,12163,12166,12169],{"class":3565,"line":3649},[3563,12160,11642],{"class":3606},[3563,12162,3607],{"class":3645},[3563,12164,12165],{"class":3645}," httpx",[3563,12167,12168],{"class":3645}," aiohttp",[3563,12170,12171],{"class":3645}," redis\n",[3563,12173,12174],{"class":3565,"line":3659},[3563,12175,3577],{"emptyLinePlaceholder":3576},[3563,12177,12178],{"class":3565,"line":3664},[3563,12179,12180],{"class":3569},"# Залежності лише для розробки (не потрапляють у production)\n",[3563,12182,12183,12185,12187,12190,12193,12196,12199],{"class":3565,"line":3694},[3563,12184,11642],{"class":3606},[3563,12186,3607],{"class":3645},[3563,12188,12189],{"class":3602}," --dev",[3563,12191,12192],{"class":3645}," pytest",[3563,12194,12195],{"class":3645}," pytest-asyncio",[3563,12197,12198],{"class":3645}," ruff",[3563,12200,12201],{"class":3645}," mypy\n",[3563,12203,12204,12206,12208,12210,12213],{"class":3565,"line":3700},[3563,12205,11642],{"class":3606},[3563,12207,3607],{"class":3645},[3563,12209,12189],{"class":3602},[3563,12211,12212],{"class":3645}," black",[3563,12214,12215],{"class":3645}," isort\n",[3563,12217,12218],{"class":3565,"line":3708},[3563,12219,3577],{"emptyLinePlaceholder":3576},[3563,12221,12222],{"class":3565,"line":3713},[3563,12223,12224],{"class":3569},"# Видалення залежності\n",[3563,12226,12227,12229,12232],{"class":3565,"line":3743},[3563,12228,11642],{"class":3606},[3563,12230,12231],{"class":3645}," remove",[3563,12233,12171],{"class":3645},[3563,12235,12236],{"class":3565,"line":3749},[3563,12237,3577],{"emptyLinePlaceholder":3576},[3563,12239,12240],{"class":3565,"line":3757},[3563,12241,12242],{"class":3569},"# Синхронізація середовища з lockfile (аналог pip install -r requirements.txt)\n",[3563,12244,12245,12247],{"class":3565,"line":3762},[3563,12246,11642],{"class":3606},[3563,12248,12249],{"class":3645}," sync\n",[3563,12251,12252],{"class":3565,"line":3785},[3563,12253,3577],{"emptyLinePlaceholder":3576},[3563,12255,12256],{"class":3565,"line":3791},[3563,12257,12258],{"class":3569},"# Синхронізація без dev-залежностей (для production)\n",[3563,12260,12261,12263,12266],{"class":3565,"line":3802},[3563,12262,11642],{"class":3606},[3563,12264,12265],{"class":3645}," sync",[3563,12267,12268],{"class":3602}," --no-dev\n",[4032,12270,12272,12281,12293,12304,12308,12312,12319,12323,12327,12331,12335,12339,12343,12347,12351],{"title":12271},"uv add — швидке додавання залежності",[4036,12273,12275,4044,12278],{"className":12274},[3565],[3563,12276,4043],{"className":12277},[4042],[3406,12279,12280],{},"uv add fastapi uvicorn",[4036,12282,12284,12285,12288,12289],{"className":12283},[3565],"Resolved ",[3563,12286,4055],{"className":12287},[4071]," packages in ",[3563,12290,12292],{"className":12291},[4054],"287ms",[4036,12294,12296,12297,12288,12300],{"className":12295},[3565],"Installed ",[3563,12298,4055],{"className":12299},[4071],[3563,12301,12303],{"className":12302},[4054],"423ms",[4036,12305,12307],{"className":12306},[3565]," + annotated-types==0.7.0",[4036,12309,12311],{"className":12310},[3565]," + anyio==4.7.0",[4036,12313,11649,12315],{"className":12314},[3565],[3563,12316,12318],{"className":12317},[4054],"fastapi==0.115.6",[4036,12320,12322],{"className":12321},[3565]," + h11==0.14.0",[4036,12324,12326],{"className":12325},[3565]," + httpcore==1.0.7",[4036,12328,12330],{"className":12329},[3565]," + idna==3.10",[4036,12332,12334],{"className":12333},[3565]," + pydantic==2.10.3",[4036,12336,12338],{"className":12337},[3565]," + pydantic-core==2.27.1",[4036,12340,12342],{"className":12341},[3565]," + sniffio==1.3.1",[4036,12344,12346],{"className":12345},[3565]," + starlette==0.41.3",[4036,12348,12350],{"className":12349},[3565]," + typing-extensions==4.12.2",[4036,12352,11649,12354],{"className":12353},[3565],[3563,12355,12357],{"className":12356},[4054],"uvicorn==0.32.1",[3394,12359,12360,12361,4044,12364,12366],{},"Після виконання ",[3398,12362,12363],{},"uv add",[3398,12365,11632],{}," оновлюється автоматично:",[3554,12368,12370],{"className":12036,"code":12369,"language":12038,"meta":3559,"style":3559},"[project]\nname = \"my-web-api\"\nversion = \"0.1.0\"\nrequires-python = \">=3.12\"\ndependencies = [\n    \"fastapi>=0.115.6\",\n    \"uvicorn>=0.32.1\",\n]\n\n[dependency-groups]\ndev = [\n    \"pytest>=8.3.4\",\n    \"ruff>=0.8.4\",\n    \"mypy>=1.13.0\",\n]\n",[3398,12371,12372,12376,12384,12392,12400,12407,12415,12422,12426,12430,12435,12442,12449,12456,12463],{"__ignoreMap":3559},[3563,12373,12374],{"class":3565,"line":3566},[3563,12375,12050],{"class":3583},[3563,12377,12378,12380,12382],{"class":3565,"line":3573},[3563,12379,9494],{"class":3613},[3563,12381,8871],{"class":3583},[3563,12383,12059],{"class":3645},[3563,12385,12386,12388,12390],{"class":3565,"line":3580},[3563,12387,10900],{"class":3613},[3563,12389,8871],{"class":3583},[3563,12391,12068],{"class":3645},[3563,12393,12394,12396,12398],{"class":3565,"line":3594},[3563,12395,12093],{"class":3613},[3563,12397,8871],{"class":3583},[3563,12399,12098],{"class":3645},[3563,12401,12402,12404],{"class":3565,"line":3599},[3563,12403,12103],{"class":3613},[3563,12405,12406],{"class":3583}," = [\n",[3563,12408,12409,12412],{"class":3565,"line":3642},[3563,12410,12411],{"class":3645},"    \"fastapi>=0.115.6\"",[3563,12413,12414],{"class":3583},",\n",[3563,12416,12417,12420],{"class":3565,"line":3649},[3563,12418,12419],{"class":3645},"    \"uvicorn>=0.32.1\"",[3563,12421,12414],{"class":3583},[3563,12423,12424],{"class":3565,"line":3659},[3563,12425,6347],{"class":3583},[3563,12427,12428],{"class":3565,"line":3664},[3563,12429,3577],{"emptyLinePlaceholder":3576},[3563,12431,12432],{"class":3565,"line":3694},[3563,12433,12434],{"class":3583},"[dependency-groups]\n",[3563,12436,12437,12440],{"class":3565,"line":3700},[3563,12438,12439],{"class":3613},"dev",[3563,12441,12406],{"class":3583},[3563,12443,12444,12447],{"class":3565,"line":3708},[3563,12445,12446],{"class":3645},"    \"pytest>=8.3.4\"",[3563,12448,12414],{"class":3583},[3563,12450,12451,12454],{"class":3565,"line":3713},[3563,12452,12453],{"class":3645},"    \"ruff>=0.8.4\"",[3563,12455,12414],{"class":3583},[3563,12457,12458,12461],{"class":3565,"line":3743},[3563,12459,12460],{"class":3645},"    \"mypy>=1.13.0\"",[3563,12462,12414],{"class":3583},[3563,12464,12465],{"class":3565,"line":3749},[3563,12466,6347],{"class":3583},[4287,12468,12470],{"id":12469},"запуск-коду-та-команд","Запуск коду та команд",[3394,12472,12473,12476],{},[3398,12474,12475],{},"uv run"," запускає скрипт або команду у керованому середовищі проекту — без потреби вручну активувати середовище:",[3554,12478,12480],{"className":11048,"code":12479,"language":11050,"meta":3559,"style":3559},"# Запуск скрипта\nuv run python main.py\n\n# Запуск застосунку\nuv run uvicorn main:app --reload\n\n# Запуск тестів\nuv run pytest\n\n# Запуск лінтера\nuv run ruff check .\n\n# uv run також може виконувати скрипти без встановлення:\n# навіть якщо pytest не у залежностях — uv встановить тимчасово\nuv run --with pytest pytest tests\u002F\n",[3398,12481,12482,12487,12499,12503,12508,12523,12527,12532,12541,12545,12550,12564,12568,12573,12578],{"__ignoreMap":3559},[3563,12483,12484],{"class":3565,"line":3566},[3563,12485,12486],{"class":3569},"# Запуск скрипта\n",[3563,12488,12489,12491,12494,12496],{"class":3565,"line":3573},[3563,12490,11642],{"class":3606},[3563,12492,12493],{"class":3645}," run",[3563,12495,11180],{"class":3645},[3563,12497,12498],{"class":3645}," main.py\n",[3563,12500,12501],{"class":3565,"line":3580},[3563,12502,3577],{"emptyLinePlaceholder":3576},[3563,12504,12505],{"class":3565,"line":3594},[3563,12506,12507],{"class":3569},"# Запуск застосунку\n",[3563,12509,12510,12512,12514,12517,12520],{"class":3565,"line":3599},[3563,12511,11642],{"class":3606},[3563,12513,12493],{"class":3645},[3563,12515,12516],{"class":3645}," uvicorn",[3563,12518,12519],{"class":3645}," main:app",[3563,12521,12522],{"class":3602}," --reload\n",[3563,12524,12525],{"class":3565,"line":3642},[3563,12526,3577],{"emptyLinePlaceholder":3576},[3563,12528,12529],{"class":3565,"line":3649},[3563,12530,12531],{"class":3569},"# Запуск тестів\n",[3563,12533,12534,12536,12538],{"class":3565,"line":3659},[3563,12535,11642],{"class":3606},[3563,12537,12493],{"class":3645},[3563,12539,12540],{"class":3645}," pytest\n",[3563,12542,12543],{"class":3565,"line":3664},[3563,12544,3577],{"emptyLinePlaceholder":3576},[3563,12546,12547],{"class":3565,"line":3694},[3563,12548,12549],{"class":3569},"# Запуск лінтера\n",[3563,12551,12552,12554,12556,12558,12561],{"class":3565,"line":3700},[3563,12553,11642],{"class":3606},[3563,12555,12493],{"class":3645},[3563,12557,12198],{"class":3645},[3563,12559,12560],{"class":3645}," check",[3563,12562,12563],{"class":3645}," .\n",[3563,12565,12566],{"class":3565,"line":3708},[3563,12567,3577],{"emptyLinePlaceholder":3576},[3563,12569,12570],{"class":3565,"line":3713},[3563,12571,12572],{"class":3569},"# uv run також може виконувати скрипти без встановлення:\n",[3563,12574,12575],{"class":3565,"line":3743},[3563,12576,12577],{"class":3569},"# навіть якщо pytest не у залежностях — uv встановить тимчасово\n",[3563,12579,12580,12582,12584,12587,12589,12591],{"class":3565,"line":3749},[3563,12581,11642],{"class":3606},[3563,12583,12493],{"class":3645},[3563,12585,12586],{"class":3602}," --with",[3563,12588,12192],{"class":3645},[3563,12590,12192],{"class":3645},[3563,12592,12593],{"class":3645}," tests\u002F\n",[12595,12596,12597,12599,12600,12602,12603,4481,12606,3459],"important",{},[3398,12598,12475],{}," автоматично синхронізує середовище перед запуском, якщо ",[3398,12601,11784],{}," та встановлені пакети не відповідають одне одному. Це робить його ідеальним для CI\u002FCD: не потрібні окремі кроки ",[3398,12604,12605],{},"venv create",[3398,12607,5864],{},[4287,12609,12611],{"id":12610},"управління-версіями-python","Управління версіями Python",[3394,12613,12614,12615,12617,12618,10135],{},"Одна з найпотужніших функцій ",[3398,12616,11642],{}," — вбудоване управління версіями Python (аналог ",[3398,12619,11743],{},[3554,12621,12623],{"className":11048,"code":12622,"language":11050,"meta":3559,"style":3559},"# Встановлення конкретної версії Python\nuv python install 3.12\nuv python install 3.11 3.13  # кілька версій одразу\n\n# Перегляд доступних та встановлених версій\nuv python list\n\n# Прив'язка версії Python до проекту\nuv python pin 3.12  # записує у .python-version\n\n# Використання конкретної версії при ініціалізації проекту\nuv init --python 3.11 legacy-service\n",[3398,12624,12625,12630,12641,12658,12662,12667,12675,12679,12684,12699,12703,12708],{"__ignoreMap":3559},[3563,12626,12627],{"class":3565,"line":3566},[3563,12628,12629],{"class":3569},"# Встановлення конкретної версії Python\n",[3563,12631,12632,12634,12636,12638],{"class":3565,"line":3573},[3563,12633,11642],{"class":3606},[3563,12635,11180],{"class":3645},[3563,12637,11285],{"class":3645},[3563,12639,12640],{"class":3587}," 3.12\n",[3563,12642,12643,12645,12647,12649,12652,12655],{"class":3565,"line":3580},[3563,12644,11642],{"class":3606},[3563,12646,11180],{"class":3645},[3563,12648,11285],{"class":3645},[3563,12650,12651],{"class":3587}," 3.11",[3563,12653,12654],{"class":3587}," 3.13",[3563,12656,12657],{"class":3569},"  # кілька версій одразу\n",[3563,12659,12660],{"class":3565,"line":3594},[3563,12661,3577],{"emptyLinePlaceholder":3576},[3563,12663,12664],{"class":3565,"line":3599},[3563,12665,12666],{"class":3569},"# Перегляд доступних та встановлених версій\n",[3563,12668,12669,12671,12673],{"class":3565,"line":3642},[3563,12670,11642],{"class":3606},[3563,12672,11180],{"class":3645},[3563,12674,11349],{"class":3645},[3563,12676,12677],{"class":3565,"line":3649},[3563,12678,3577],{"emptyLinePlaceholder":3576},[3563,12680,12681],{"class":3565,"line":3659},[3563,12682,12683],{"class":3569},"# Прив'язка версії Python до проекту\n",[3563,12685,12686,12688,12690,12693,12696],{"class":3565,"line":3664},[3563,12687,11642],{"class":3606},[3563,12689,11180],{"class":3645},[3563,12691,12692],{"class":3645}," pin",[3563,12694,12695],{"class":3587}," 3.12",[3563,12697,12698],{"class":3569},"  # записує у .python-version\n",[3563,12700,12701],{"class":3565,"line":3694},[3563,12702,3577],{"emptyLinePlaceholder":3576},[3563,12704,12705],{"class":3565,"line":3700},[3563,12706,12707],{"class":3569},"# Використання конкретної версії при ініціалізації проекту\n",[3563,12709,12710,12712,12714,12717,12719],{"class":3565,"line":3708},[3563,12711,11642],{"class":3606},[3563,12713,11921],{"class":3645},[3563,12715,12716],{"class":3602}," --python",[3563,12718,12651],{"class":3587},[3563,12720,12721],{"class":3645}," legacy-service\n",[4032,12723,12725,12734,12742,12754,12762],{"title":12724},"uv python list — огляд версій",[4036,12726,12728,4044,12731],{"className":12727},[3565],[3563,12729,4043],{"className":12730},[4042],[3406,12732,12733],{},"uv python list",[4036,12735,12737,12738],{"className":12736},[3565],"cpython-3.13.1-macos-aarch64-none    ",[3563,12739,12741],{"className":12740},[4071],"\u002FUsers\u002Fuser\u002F.local\u002Fshare\u002Fuv\u002Fpython\u002Fcpython-3.13.1...",[4036,12743,12745,12746,4044,12750],{"className":12744},[3565],"cpython-3.12.8-macos-aarch64-none    ",[3563,12747,12749],{"className":12748},[4071],"\u002FUsers\u002Fuser\u002F.local\u002Fshare\u002Fuv\u002Fpython\u002Fcpython-3.12.8...",[3563,12751,12753],{"className":12752},[4054],"← активна",[4036,12755,12757,12758],{"className":12756},[3565],"cpython-3.11.11-macos-aarch64-none   ",[3563,12759,12761],{"className":12760},[4071],"\u002FUsers\u002Fuser\u002F.local\u002Fshare\u002Fuv\u002Fpython\u002Fcpython-3.11.11...",[4036,12763,12765,12766],{"className":12764},[3565],"cpython-3.10.16-macos-aarch64-none   ",[3563,12767,12769],{"className":12768},[4071],"\u002FUsers\u002Fuser\u002F.local\u002Fshare\u002Fuv\u002Fpython\u002Fcpython-3.10.16...",[4287,12771,12773,12774],{"id":12772},"запуск-cli-інструментів-через-uvx","Запуск CLI-інструментів через ",[3398,12775,12776],{},"uvx",[3394,12778,12779,12781,12782,12785],{},[3398,12780,12776],{}," — це аналог ",[3398,12783,12784],{},"npx"," з Node.js: запускає CLI-інструменти без встановлення у проект, у тимчасовому ізольованому середовищі:",[3554,12787,12789],{"className":11048,"code":12788,"language":11050,"meta":3559,"style":3559},"# Запуск без встановлення (uvx = uv tool run)\nuvx ruff check .          # запускає ruff для перевірки поточної директорії\nuvx black myfile.py        # форматує файл\nuvx httpie GET httpbin.org\u002Fget  # HTTP-клієнт для тестування API\n\n# Встановлення інструментів глобально (available everywhere)\nuv tool install ruff\nuv tool install black\nuv tool list               # список встановлених інструментів\n",[3398,12790,12791,12796,12810,12822,12838,12842,12847,12859,12870],{"__ignoreMap":3559},[3563,12792,12793],{"class":3565,"line":3566},[3563,12794,12795],{"class":3569},"# Запуск без встановлення (uvx = uv tool run)\n",[3563,12797,12798,12800,12802,12804,12807],{"class":3565,"line":3573},[3563,12799,12776],{"class":3606},[3563,12801,12198],{"class":3645},[3563,12803,12560],{"class":3645},[3563,12805,12806],{"class":3645}," .",[3563,12808,12809],{"class":3569},"          # запускає ruff для перевірки поточної директорії\n",[3563,12811,12812,12814,12816,12819],{"class":3565,"line":3580},[3563,12813,12776],{"class":3606},[3563,12815,12212],{"class":3645},[3563,12817,12818],{"class":3645}," myfile.py",[3563,12820,12821],{"class":3569},"        # форматує файл\n",[3563,12823,12824,12826,12829,12832,12835],{"class":3565,"line":3594},[3563,12825,12776],{"class":3606},[3563,12827,12828],{"class":3645}," httpie",[3563,12830,12831],{"class":3645}," GET",[3563,12833,12834],{"class":3645}," httpbin.org\u002Fget",[3563,12836,12837],{"class":3569},"  # HTTP-клієнт для тестування API\n",[3563,12839,12840],{"class":3565,"line":3599},[3563,12841,3577],{"emptyLinePlaceholder":3576},[3563,12843,12844],{"class":3565,"line":3642},[3563,12845,12846],{"class":3569},"# Встановлення інструментів глобально (available everywhere)\n",[3563,12848,12849,12851,12854,12856],{"class":3565,"line":3649},[3563,12850,11642],{"class":3606},[3563,12852,12853],{"class":3645}," tool",[3563,12855,11285],{"class":3645},[3563,12857,12858],{"class":3645}," ruff\n",[3563,12860,12861,12863,12865,12867],{"class":3565,"line":3659},[3563,12862,11642],{"class":3606},[3563,12864,12853],{"class":3645},[3563,12866,11285],{"class":3645},[3563,12868,12869],{"class":3645}," black\n",[3563,12871,12872,12874,12876,12878],{"class":3565,"line":3664},[3563,12873,11642],{"class":3606},[3563,12875,12853],{"class":3645},[3563,12877,9167],{"class":3645},[3563,12879,12880],{"class":3569},"               # список встановлених інструментів\n",[10286,12882,12883,12885,12886,10066,12889,3459],{},[3398,12884,12776],{}," особливо зручний у CI\u002FCD та скриптах, де не хочеться «забруднювати» залежності проекту інструментами розробки. ",[3398,12887,12888],{},"uvx ruff check .",[3398,12890,12891],{},"pip install ruff && ruff check .",[4287,12893,12895,12897,12898,12900],{"id":12894},"uv-як-замінник-pip-у-існуючих-проектах",[3398,12896,11642],{}," як замінник ",[3398,12899,6155],{}," у існуючих проектах",[3394,12902,12903,12904,3624,12906,12908,12909,4297],{},"Якщо у вас вже є проект з ",[3398,12905,11473],{},[3398,12907,11642],{}," можна підключити без переходу на ",[3398,12910,11632],{},[3554,12912,12914],{"className":11048,"code":12913,"language":11050,"meta":3559,"style":3559},"# uv як прямий замінник pip (набагато швидший)\nuv pip install requests\nuv pip install -r requirements.txt\nuv pip freeze > requirements.txt\n\n# Створення venv через uv\nuv venv .venv\nsource .venv\u002Fbin\u002Factivate\n\n# Компіляція requirements (аналог pip-tools)\nuv pip compile requirements.in -o requirements.txt\n",[3398,12915,12916,12921,12931,12943,12955,12959,12964,12972,12978,12982,12987],{"__ignoreMap":3559},[3563,12917,12918],{"class":3565,"line":3566},[3563,12919,12920],{"class":3569},"# uv як прямий замінник pip (набагато швидший)\n",[3563,12922,12923,12925,12927,12929],{"class":3565,"line":3573},[3563,12924,11642],{"class":3606},[3563,12926,11190],{"class":3645},[3563,12928,11285],{"class":3645},[3563,12930,11368],{"class":3645},[3563,12932,12933,12935,12937,12939,12941],{"class":3565,"line":3580},[3563,12934,11642],{"class":3606},[3563,12936,11190],{"class":3645},[3563,12938,11285],{"class":3645},[3563,12940,11616],{"class":3602},[3563,12942,11522],{"class":3645},[3563,12944,12945,12947,12949,12951,12953],{"class":3565,"line":3594},[3563,12946,11642],{"class":3606},[3563,12948,11190],{"class":3645},[3563,12950,11504],{"class":3645},[3563,12952,11507],{"class":3583},[3563,12954,11510],{"class":3645},[3563,12956,12957],{"class":3565,"line":3599},[3563,12958,3577],{"emptyLinePlaceholder":3576},[3563,12960,12961],{"class":3565,"line":3642},[3563,12962,12963],{"class":3569},"# Створення venv через uv\n",[3563,12965,12966,12968,12970],{"class":3565,"line":3649},[3563,12967,11642],{"class":3606},[3563,12969,11076],{"class":3645},[3563,12971,11597],{"class":3645},[3563,12973,12974,12976],{"class":3565,"line":3659},[3563,12975,11033],{"class":3606},[3563,12977,11154],{"class":3645},[3563,12979,12980],{"class":3565,"line":3664},[3563,12981,3577],{"emptyLinePlaceholder":3576},[3563,12983,12984],{"class":3565,"line":3694},[3563,12985,12986],{"class":3569},"# Компіляція requirements (аналог pip-tools)\n",[3563,12988,12989,12991,12993,12996,12999,13002],{"class":3565,"line":3700},[3563,12990,11642],{"class":3606},[3563,12992,11190],{"class":3645},[3563,12994,12995],{"class":3645}," compile",[3563,12997,12998],{"class":3645}," requirements.in",[3563,13000,13001],{"class":3602}," -o",[3563,13003,11522],{"class":3645},[4032,13005,13007,13016,13020,13027,13030,13039,13043,13051],{"title":13006},"Порівняння швидкості: pip vs uv",[4036,13008,13010,4044,13013],{"className":13009},[3565],[3563,13011,4043],{"className":13012},[4042],[3406,13014,13015],{},"time pip install django djangorestframework psycopg2-binary",[4036,13017,13019],{"className":13018},[3565],"Successfully installed django-5.1.4 djangorestframework-3.15.2 ...",[4036,13021,13023],{"className":13022},[3565],[3563,13024,13026],{"className":13025},[6748],"real  0m28.3s",[4036,13028],{"className":13029},[3565],[4036,13031,13033,4044,13036],{"className":13032},[3565],[3563,13034,4043],{"className":13035},[4042],[3406,13037,13038],{},"time uv pip install django djangorestframework psycopg2-binary",[4036,13040,13042],{"className":13041},[3565],"Resolved 8 packages in 143ms",[4036,13044,13046,13047],{"className":13045},[3565],"Installed 8 packages in ",[3563,13048,13050],{"className":13049},[4054],"614ms",[4036,13052,13054,5726,13058],{"className":13053},[3565],[3563,13055,13057],{"className":13056},[4054],"real  0m0.8s",[3563,13059,13061],{"className":13060},[4042],"← у 35 разів швидше!",[4287,13063,13065,13066],{"id":13064},"довідник-команд-uv","Довідник команд ",[3398,13067,11642],{},[5790,13069,13070,13123,13205,13256,13326,13392,13475,13570],{},[5793,13071,13073,13082],{"name":12030,"type":13072},"Ініціалізація проекту",[3394,13074,13075,13076,3624,13078,4481,13080,3459],{},"Створює новий проект у поточній директорії або у вказаній папці. Генерує ",[3398,13077,11632],{},[3398,13079,12015],{},[3398,13081,12000],{},[3554,13083,13085],{"className":11048,"code":13084,"language":11050,"meta":3559,"style":3559},"uv init                        # у поточній папці\nuv init my-project             # у новій папці my-project\u002F\nuv init --python 3.11 api      # з фіксованою версією Python\n",[3398,13086,13087,13096,13107],{"__ignoreMap":3559},[3563,13088,13089,13091,13093],{"class":3565,"line":3566},[3563,13090,11642],{"class":3606},[3563,13092,11921],{"class":3645},[3563,13094,13095],{"class":3569},"                        # у поточній папці\n",[3563,13097,13098,13100,13102,13104],{"class":3565,"line":3573},[3563,13099,11642],{"class":3606},[3563,13101,11921],{"class":3645},[3563,13103,11948],{"class":3645},[3563,13105,13106],{"class":3569},"             # у новій папці my-project\u002F\n",[3563,13108,13109,13111,13113,13115,13117,13120],{"class":3565,"line":3580},[3563,13110,11642],{"class":3606},[3563,13112,11921],{"class":3645},[3563,13114,12716],{"class":3602},[3563,13116,12651],{"class":3587},[3563,13118,13119],{"class":3645}," api",[3563,13121,13122],{"class":3569},"      # з фіксованою версією Python\n",[5793,13124,13126,13134],{"name":13125,"type":12110},"uv add \u002F uv remove",[3394,13127,13128,13129,4481,13131,13133],{},"Додає або видаляє залежності. Автоматично оновлює ",[3398,13130,11632],{},[3398,13132,11784],{},". Підтримує версійні обмеження, extras та групи.",[3554,13135,13137],{"className":11048,"code":13136,"language":11050,"meta":3559,"style":3559},"uv add fastapi                       # остання версія\nuv add \"sqlalchemy>=2.0,\u003C3\"         # з обмеженнями версій\nuv add uvicorn[standard]             # з extras\nuv add --dev pytest ruff mypy        # dev-залежності\nuv remove redis                      # видалення\n",[3398,13138,13139,13151,13163,13175,13193],{"__ignoreMap":3559},[3563,13140,13141,13143,13145,13148],{"class":3565,"line":3566},[3563,13142,11642],{"class":3606},[3563,13144,3607],{"class":3645},[3563,13146,13147],{"class":3645}," fastapi",[3563,13149,13150],{"class":3569},"                       # остання версія\n",[3563,13152,13153,13155,13157,13160],{"class":3565,"line":3573},[3563,13154,11642],{"class":3606},[3563,13156,3607],{"class":3645},[3563,13158,13159],{"class":3645}," \"sqlalchemy>=2.0,\u003C3\"",[3563,13161,13162],{"class":3569},"         # з обмеженнями версій\n",[3563,13164,13165,13167,13169,13172],{"class":3565,"line":3580},[3563,13166,11642],{"class":3606},[3563,13168,3607],{"class":3645},[3563,13170,13171],{"class":3645}," uvicorn[standard]",[3563,13173,13174],{"class":3569},"             # з extras\n",[3563,13176,13177,13179,13181,13183,13185,13187,13190],{"class":3565,"line":3594},[3563,13178,11642],{"class":3606},[3563,13180,3607],{"class":3645},[3563,13182,12189],{"class":3602},[3563,13184,12192],{"class":3645},[3563,13186,12198],{"class":3645},[3563,13188,13189],{"class":3645}," mypy",[3563,13191,13192],{"class":3569},"        # dev-залежності\n",[3563,13194,13195,13197,13199,13202],{"class":3565,"line":3599},[3563,13196,11642],{"class":3606},[3563,13198,12231],{"class":3645},[3563,13200,13201],{"class":3645}," redis",[3563,13203,13204],{"class":3569},"                      # видалення\n",[5793,13206,13208,13218],{"name":11788,"type":13207},"Синхронізація середовища",[3394,13209,13210,13211,13213,13214,13217],{},"Встановлює\u002Fоновлює пакети у середовищі відповідно до ",[3398,13212,11784],{},". Аналог ",[3398,13215,13216],{},"pip install -r requirements.txt",", але точний і детермінований.",[3554,13219,13221],{"className":11048,"code":13220,"language":11050,"meta":3559,"style":3559},"uv sync                  # встановити всі залежності\nuv sync --no-dev         # тільки production (без dev-групи)\nuv sync --frozen         # не оновлювати lockfile, лише встановити\n",[3398,13222,13223,13232,13244],{"__ignoreMap":3559},[3563,13224,13225,13227,13229],{"class":3565,"line":3566},[3563,13226,11642],{"class":3606},[3563,13228,12265],{"class":3645},[3563,13230,13231],{"class":3569},"                  # встановити всі залежності\n",[3563,13233,13234,13236,13238,13241],{"class":3565,"line":3573},[3563,13235,11642],{"class":3606},[3563,13237,12265],{"class":3645},[3563,13239,13240],{"class":3602}," --no-dev",[3563,13242,13243],{"class":3569},"         # тільки production (без dev-групи)\n",[3563,13245,13246,13248,13250,13253],{"class":3565,"line":3580},[3563,13247,11642],{"class":3606},[3563,13249,12265],{"class":3645},[3563,13251,13252],{"class":3602}," --frozen",[3563,13254,13255],{"class":3569},"         # не оновлювати lockfile, лише встановити\n",[5793,13257,13259,13262],{"name":12475,"type":13258},"Запуск команд у середовищі",[3394,13260,13261],{},"Виконує скрипт або команду у середовищі проекту без ручної активації venv. Перед запуском автоматично синхронізує середовище.",[3554,13263,13265],{"className":11048,"code":13264,"language":11050,"meta":3559,"style":3559},"uv run python main.py              # запуск скрипта\nuv run uvicorn app:app --reload    # запуск застосунку\nuv run pytest                      # тести\nuv run --with httpx python -c \"import httpx; print(httpx.__version__)\"\n",[3398,13266,13267,13281,13298,13309],{"__ignoreMap":3559},[3563,13268,13269,13271,13273,13275,13278],{"class":3565,"line":3566},[3563,13270,11642],{"class":3606},[3563,13272,12493],{"class":3645},[3563,13274,11180],{"class":3645},[3563,13276,13277],{"class":3645}," main.py",[3563,13279,13280],{"class":3569},"              # запуск скрипта\n",[3563,13282,13283,13285,13287,13289,13292,13295],{"class":3565,"line":3573},[3563,13284,11642],{"class":3606},[3563,13286,12493],{"class":3645},[3563,13288,12516],{"class":3645},[3563,13290,13291],{"class":3645}," app:app",[3563,13293,13294],{"class":3602}," --reload",[3563,13296,13297],{"class":3569},"    # запуск застосунку\n",[3563,13299,13300,13302,13304,13306],{"class":3565,"line":3580},[3563,13301,11642],{"class":3606},[3563,13303,12493],{"class":3645},[3563,13305,12192],{"class":3645},[3563,13307,13308],{"class":3569},"                      # тести\n",[3563,13310,13311,13313,13315,13317,13319,13321,13323],{"class":3565,"line":3594},[3563,13312,11642],{"class":3606},[3563,13314,12493],{"class":3645},[3563,13316,12586],{"class":3602},[3563,13318,12165],{"class":3645},[3563,13320,11180],{"class":3645},[3563,13322,11860],{"class":3602},[3563,13324,13325],{"class":3645}," \"import httpx; print(httpx.__version__)\"\n",[5793,13327,13329,13335],{"name":13328,"type":12611},"uv python",[3394,13330,13331,13332,13334],{},"Встановлює, перелічує та прив'язує версії Python до проекту. Замінює ",[3398,13333,11743],{}," для більшості сценаріїв.",[3554,13336,13338],{"className":11048,"code":13337,"language":11050,"meta":3559,"style":3559},"uv python install 3.12          # завантажити та встановити\nuv python install 3.11 3.13     # кілька версій одразу\nuv python list                  # переглянути всі доступні\nuv python pin 3.12              # зафіксувати у .python-version\n",[3398,13339,13340,13353,13368,13379],{"__ignoreMap":3559},[3563,13341,13342,13344,13346,13348,13350],{"class":3565,"line":3566},[3563,13343,11642],{"class":3606},[3563,13345,11180],{"class":3645},[3563,13347,11285],{"class":3645},[3563,13349,12695],{"class":3587},[3563,13351,13352],{"class":3569},"          # завантажити та встановити\n",[3563,13354,13355,13357,13359,13361,13363,13365],{"class":3565,"line":3573},[3563,13356,11642],{"class":3606},[3563,13358,11180],{"class":3645},[3563,13360,11285],{"class":3645},[3563,13362,12651],{"class":3587},[3563,13364,12654],{"class":3587},[3563,13366,13367],{"class":3569},"     # кілька версій одразу\n",[3563,13369,13370,13372,13374,13376],{"class":3565,"line":3580},[3563,13371,11642],{"class":3606},[3563,13373,11180],{"class":3645},[3563,13375,9167],{"class":3645},[3563,13377,13378],{"class":3569},"                  # переглянути всі доступні\n",[3563,13380,13381,13383,13385,13387,13389],{"class":3565,"line":3594},[3563,13382,11642],{"class":3606},[3563,13384,11180],{"class":3645},[3563,13386,12692],{"class":3645},[3563,13388,12695],{"class":3587},[3563,13390,13391],{"class":3569},"              # зафіксувати у .python-version\n",[5793,13393,13396,13404],{"name":13394,"type":13395},"uv pip","pip-сумісний режим",[3394,13397,13398,13399,13401,13402,3459],{},"Підмножина команд ",[3398,13400,6155],{}," з тим самим синтаксисом, але у рази швидша. Для інтеграції з існуючими проектами без переходу на ",[3398,13403,11632],{},[3554,13405,13407],{"className":11048,"code":13406,"language":11050,"meta":3559,"style":3559},"uv pip install requests             # встановлення пакета\nuv pip install -r requirements.txt  # з файлу\nuv pip freeze > requirements.txt    # збереження списку\nuv pip list                         # перелік встановлених\nuv venv .venv                       # створення середовища\n",[3398,13408,13409,13422,13438,13453,13464],{"__ignoreMap":3559},[3563,13410,13411,13413,13415,13417,13419],{"class":3565,"line":3566},[3563,13412,11642],{"class":3606},[3563,13414,11190],{"class":3645},[3563,13416,11285],{"class":3645},[3563,13418,11288],{"class":3645},[3563,13420,13421],{"class":3569},"             # встановлення пакета\n",[3563,13423,13424,13426,13428,13430,13432,13435],{"class":3565,"line":3573},[3563,13425,11642],{"class":3606},[3563,13427,11190],{"class":3645},[3563,13429,11285],{"class":3645},[3563,13431,11616],{"class":3602},[3563,13433,13434],{"class":3645}," requirements.txt",[3563,13436,13437],{"class":3569},"  # з файлу\n",[3563,13439,13440,13442,13444,13446,13448,13450],{"class":3565,"line":3580},[3563,13441,11642],{"class":3606},[3563,13443,11190],{"class":3645},[3563,13445,11504],{"class":3645},[3563,13447,11507],{"class":3583},[3563,13449,11473],{"class":3645},[3563,13451,13452],{"class":3569},"    # збереження списку\n",[3563,13454,13455,13457,13459,13461],{"class":3565,"line":3594},[3563,13456,11642],{"class":3606},[3563,13458,11190],{"class":3645},[3563,13460,9167],{"class":3645},[3563,13462,13463],{"class":3569},"                         # перелік встановлених\n",[3563,13465,13466,13468,13470,13472],{"class":3565,"line":3599},[3563,13467,11642],{"class":3606},[3563,13469,11076],{"class":3645},[3563,13471,11092],{"class":3645},[3563,13473,13474],{"class":3569},"                       # створення середовища\n",[5793,13476,13479,13488],{"name":13477,"type":13478},"uvx \u002F uv tool","Глобальні CLI-інструменти",[3394,13480,13481,13483,13484,13487],{},[3398,13482,12776],{}," запускає CLI-інструменти без встановлення у проект (у тимчасовому ізольованому середовищі). ",[3398,13485,13486],{},"uv tool install"," — встановлює глобально.",[3554,13489,13491],{"className":11048,"code":13490,"language":11050,"meta":3559,"style":3559},"uvx ruff check .               # запуск без встановлення\nuvx black myfile.py\nuvx --from httpie http GET httpbin.org\u002Fget\nuv tool install ruff            # встановити глобально\nuv tool list                    # список глобальних інструментів\nuv tool uninstall ruff          # видалити\n",[3398,13492,13493,13506,13515,13532,13545,13556],{"__ignoreMap":3559},[3563,13494,13495,13497,13499,13501,13503],{"class":3565,"line":3566},[3563,13496,12776],{"class":3606},[3563,13498,12198],{"class":3645},[3563,13500,12560],{"class":3645},[3563,13502,12806],{"class":3645},[3563,13504,13505],{"class":3569},"               # запуск без встановлення\n",[3563,13507,13508,13510,13512],{"class":3565,"line":3573},[3563,13509,12776],{"class":3606},[3563,13511,12212],{"class":3645},[3563,13513,13514],{"class":3645}," myfile.py\n",[3563,13516,13517,13519,13522,13524,13527,13529],{"class":3565,"line":3580},[3563,13518,12776],{"class":3606},[3563,13520,13521],{"class":3602}," --from",[3563,13523,12828],{"class":3645},[3563,13525,13526],{"class":3645}," http",[3563,13528,12831],{"class":3645},[3563,13530,13531],{"class":3645}," httpbin.org\u002Fget\n",[3563,13533,13534,13536,13538,13540,13542],{"class":3565,"line":3594},[3563,13535,11642],{"class":3606},[3563,13537,12853],{"class":3645},[3563,13539,11285],{"class":3645},[3563,13541,12198],{"class":3645},[3563,13543,13544],{"class":3569},"            # встановити глобально\n",[3563,13546,13547,13549,13551,13553],{"class":3565,"line":3599},[3563,13548,11642],{"class":3606},[3563,13550,12853],{"class":3645},[3563,13552,9167],{"class":3645},[3563,13554,13555],{"class":3569},"                    # список глобальних інструментів\n",[3563,13557,13558,13560,13562,13565,13567],{"class":3565,"line":3642},[3563,13559,11642],{"class":3606},[3563,13561,12853],{"class":3645},[3563,13563,13564],{"class":3645}," uninstall",[3563,13566,12198],{"class":3645},[3563,13568,13569],{"class":3569},"          # видалити\n",[5793,13571,13574,13585],{"name":13572,"type":13573},"uv lock \u002F uv export","Lockfile та сумісність",[3394,13575,13576,13577,13579,13580,13582,13583,3459],{},"Генерує або оновлює ",[3398,13578,11784],{},". Може експортувати залежності у формат ",[3398,13581,11473],{}," для інструментів, що не підтримують ",[3398,13584,11784],{},[3554,13586,13588],{"className":11048,"code":13587,"language":11050,"meta":3559,"style":3559},"uv lock                                          # оновити lockfile\nuv export -f requirements-txt > requirements.txt # експорт у pip-формат\nuv export --no-dev -f requirements-txt > req-prod.txt\n",[3398,13589,13590,13600,13620],{"__ignoreMap":3559},[3563,13591,13592,13594,13597],{"class":3565,"line":3566},[3563,13593,11642],{"class":3606},[3563,13595,13596],{"class":3645}," lock",[3563,13598,13599],{"class":3569},"                                          # оновити lockfile\n",[3563,13601,13602,13604,13607,13610,13613,13615,13617],{"class":3565,"line":3573},[3563,13603,11642],{"class":3606},[3563,13605,13606],{"class":3645}," export",[3563,13608,13609],{"class":3602}," -f",[3563,13611,13612],{"class":3645}," requirements-txt",[3563,13614,11507],{"class":3583},[3563,13616,11473],{"class":3645},[3563,13618,13619],{"class":3569}," # експорт у pip-формат\n",[3563,13621,13622,13624,13626,13628,13630,13632,13634],{"class":3565,"line":3580},[3563,13623,11642],{"class":3606},[3563,13625,13606],{"class":3645},[3563,13627,13240],{"class":3602},[3563,13629,13609],{"class":3602},[3563,13631,13612],{"class":3645},[3563,13633,11507],{"class":3583},[3563,13635,13636],{"class":3645},"req-prod.txt\n",[3461,13638],{},[3468,13640,13642,13644],{"id":13641},"poetry-зрілий-менеджер-для-складних-проектів",[3398,13643,11712],{}," — зрілий менеджер для складних проектів",[3394,13646,13647,13649,13650,13652,13653,13656,13657,13660],{},[3406,13648,11712],{}," — це інструмент, що вийшов у 2018 році і зараз широко використовується у виробничих проектах. Він вирішує ту саму проблему, що і ",[3398,13651,11642],{},", але з акцентом на управління ",[3406,13654,13655],{},"залежностями з групами"," і ",[3406,13658,13659],{},"публікацію пакетів"," на PyPI.",[3411,13662,13663,13675,13683,13691],{},[3414,13664,13667,13668,13671,13672,3459],{"icon":13665,"title":13666},"i-heroicons-cube","Автоматичне управління середовищем","Poetry автоматично створює та активує venv. Не потрібно ",[3398,13669,13670],{},"python -m venv .venv && source .venv\u002Fbin\u002Factivate"," — достатньо ",[3398,13673,13674],{},"poetry install",[3414,13676,13679,13680,13682],{"icon":13677,"title":13678},"i-heroicons-document-duplicate","poetry.lock — точне відтворення","Lockfile фіксує точні версії і хеші пакетів. ",[3398,13681,13674],{}," завжди відтворює ідентичне середовище на будь-якій машині або у CI.",[3414,13684,13687,13688,3459],{"icon":13685,"title":13686},"i-heroicons-tag","Групи залежностей","Окремі групи для dev, test, docs — залежності розробника не потрапляють у production-image при встановленні через ",[3398,13689,13690],{},"poetry install --without dev",[3414,13692,13695,13698,13699,3624,13702,13705,13706,3459],{"icon":13693,"title":13694},"i-heroicons-cloud-arrow-up","Публікація на PyPI",[3398,13696,13697],{},"poetry publish"," — єдина команда для збірки та публікації пакету. Замінює ",[3398,13700,13701],{},"setuptools",[3398,13703,13704],{},"twine"," і ручне редагування ",[3398,13707,11802],{},[4287,13709,13711],{"id":13710},"встановлення-poetry","Встановлення Poetry",[3554,13713,13715],{"className":11048,"code":13714,"language":11050,"meta":3559,"style":3559},"# Рекомендований спосіб (isolated installer)\ncurl -sSL https:\u002F\u002Finstall.python-poetry.org | python3 -\n\n# macOS через Homebrew\nbrew install poetry\n\n# Перевірка встановлення\npoetry --version  # Poetry (version 1.8.x)\n\n# Важливе налаштування: зберігати venv всередині проекту\n# (замість ~\u002F.cache\u002Fpypoetry\u002Fvirtualenvs\u002F)\npoetry config virtualenvs.in-project true\n",[3398,13716,13717,13722,13740,13744,13749,13759,13763,13767,13776,13780,13785,13790],{"__ignoreMap":3559},[3563,13718,13719],{"class":3565,"line":3566},[3563,13720,13721],{"class":3569},"# Рекомендований спосіб (isolated installer)\n",[3563,13723,13724,13726,13729,13732,13734,13737],{"class":3565,"line":3573},[3563,13725,11826],{"class":3606},[3563,13727,13728],{"class":3602}," -sSL",[3563,13730,13731],{"class":3645}," https:\u002F\u002Finstall.python-poetry.org",[3563,13733,9197],{"class":3583},[3563,13735,13736],{"class":3606},"python3",[3563,13738,13739],{"class":3645}," -\n",[3563,13741,13742],{"class":3565,"line":3580},[3563,13743,3577],{"emptyLinePlaceholder":3576},[3563,13745,13746],{"class":3565,"line":3594},[3563,13747,13748],{"class":3569},"# macOS через Homebrew\n",[3563,13750,13751,13754,13756],{"class":3565,"line":3599},[3563,13752,13753],{"class":3606},"brew",[3563,13755,11285],{"class":3645},[3563,13757,13758],{"class":3645}," poetry\n",[3563,13760,13761],{"class":3565,"line":3642},[3563,13762,3577],{"emptyLinePlaceholder":3576},[3563,13764,13765],{"class":3565,"line":3649},[3563,13766,11890],{"class":3569},[3563,13768,13769,13771,13773],{"class":3565,"line":3659},[3563,13770,11639],{"class":3606},[3563,13772,11897],{"class":3602},[3563,13774,13775],{"class":3569},"  # Poetry (version 1.8.x)\n",[3563,13777,13778],{"class":3565,"line":3664},[3563,13779,3577],{"emptyLinePlaceholder":3576},[3563,13781,13782],{"class":3565,"line":3694},[3563,13783,13784],{"class":3569},"# Важливе налаштування: зберігати venv всередині проекту\n",[3563,13786,13787],{"class":3565,"line":3700},[3563,13788,13789],{"class":3569},"# (замість ~\u002F.cache\u002Fpypoetry\u002Fvirtualenvs\u002F)\n",[3563,13791,13792,13794,13797,13800],{"class":3565,"line":3708},[3563,13793,11639],{"class":3606},[3563,13795,13796],{"class":3645}," config",[3563,13798,13799],{"class":3645}," virtualenvs.in-project",[3563,13801,13802],{"class":3602}," true\n",[10286,13804,13805,13808,13809,13812],{},[3398,13806,13807],{},"poetry config virtualenvs.in-project true"," — рекомендоване налаштування для більшості розробників. Середовище буде у ",[3398,13810,13811],{},".venv\u002F"," всередині вашого проекту, що зручно для IDE та Docker.",[4287,13814,13816],{"id":13815},"створення-нового-проекту","Створення нового проекту",[3554,13818,13820],{"className":11048,"code":13819,"language":11050,"meta":3559,"style":3559},"# Новий проект з повною структурою\npoetry new my-service\n\n# Або ініціалізація інтерактивно у поточній папці\nmkdir existing-project && cd existing-project\npoetry init\n",[3398,13821,13822,13827,13837,13841,13846,13860],{"__ignoreMap":3559},[3563,13823,13824],{"class":3565,"line":3566},[3563,13825,13826],{"class":3569},"# Новий проект з повною структурою\n",[3563,13828,13829,13831,13834],{"class":3565,"line":3573},[3563,13830,11639],{"class":3606},[3563,13832,13833],{"class":3645}," new",[3563,13835,13836],{"class":3645}," my-service\n",[3563,13838,13839],{"class":3565,"line":3580},[3563,13840,3577],{"emptyLinePlaceholder":3576},[3563,13842,13843],{"class":3565,"line":3594},[3563,13844,13845],{"class":3569},"# Або ініціалізація інтерактивно у поточній папці\n",[3563,13847,13848,13850,13853,13855,13857],{"class":3565,"line":3599},[3563,13849,11945],{"class":3606},[3563,13851,13852],{"class":3645}," existing-project",[3563,13854,11951],{"class":3583},[3563,13856,11929],{"class":3606},[3563,13858,13859],{"class":3645}," existing-project\n",[3563,13861,13862,13864],{"class":3565,"line":3642},[3563,13863,11639],{"class":3606},[3563,13865,11963],{"class":3645},[4032,13867,13869,13878,13887,13896,13900,13908,13915,13922,13928,13935],{"title":13868},"poetry new — структура нового проекту",[4036,13870,13872,4044,13875],{"className":13871},[3565],[3563,13873,4043],{"className":13874},[4042],[3406,13876,13877],{},"poetry new my-service",[4036,13879,13881,13882,13886],{"className":13880},[3565],"Created package ",[3563,13883,13885],{"className":13884},[4054],"my-service"," at `my-service`",[4036,13888,13890,4044,13893],{"className":13889},[3565],[3563,13891,4043],{"className":13892},[4042],[3406,13894,13895],{},"tree my-service\u002F",[4036,13897,13899],{"className":13898},[3565],"my-service\u002F",[4036,13901,11996,13903,13907],{"className":13902},[3565],[3563,13904,13906],{"className":13905},[4071],"my_service\u002F","         ← пакет Python",[4036,13909,13911,13912],{"className":13910},[3565],"│   └── ",[3563,13913,8808],{"className":13914},[4071],[4036,13916,11996,13918],{"className":13917},[3565],[3563,13919,13921],{"className":13920},[4071],"tests\u002F",[4036,13923,13911,13925],{"className":13924},[3565],[3563,13926,8808],{"className":13927},[4071],[4036,13929,11996,13931,13934],{"className":13930},[3565],[3563,13932,11632],{"className":13933},[5716],"      ← вся конфігурація тут",[4036,13936,12019,13938],{"className":13937},[3565],[3563,13939,12015],{"className":13940},[4054],[4287,13942,13944,13946],{"id":13943},"pyprojecttoml-у-poetry",[3398,13945,11632],{}," у Poetry",[3394,13948,13949,13950,13952,13953,4297],{},"Poetry використовує ",[3398,13951,11632],{}," — але зі своїми секціями ",[3398,13954,13955],{},"[tool.poetry.*]",[3554,13957,13959],{"className":12036,"code":13958,"language":12038,"meta":3559,"style":3559},"[tool.poetry]\nname = \"my-service\"\nversion = \"0.1.0\"\ndescription = \"Production-ready REST API\"\nauthors = [\"Developer \u003Cdev@example.com>\"]\nreadme = \"README.md\"\npackages = [{include = \"my_service\"}]\n\n[tool.poetry.dependencies]\npython = \"^3.12\"           # версія Python — обов'язкова\nfastapi = \">=0.115.0\"      # прямі залежності проекту\nsqlalchemy = \"^2.0\"\npydantic = \"^2.5\"\nuvicorn = {extras = [\"standard\"], version = \"^0.32\"}\n\n[tool.poetry.group.dev.dependencies]  # група dev — не у production\npytest = \"^8.0\"\npytest-asyncio = \"^0.24\"\nruff = \"^0.8\"\nmypy = \"^1.13\"\nblack = \"^24.0\"\n\n[tool.poetry.group.test.dependencies]  # окрема група для тестів\nhttpx = \"^0.28\"            # HTTP-клієнт для тестування FastAPI\nfactory-boy = \"^3.3\"\n\n[build-system]\nrequires = [\"poetry-core\"]\nbuild-backend = \"poetry.core.masonry.api\"\n",[3398,13960,13961,13966,13975,13983,13992,14004,14012,14031,14035,14040,14052,14065,14075,14085,14113,14117,14125,14135,14145,14154,14164,14174,14178,14186,14199,14209,14213,14218,14230],{"__ignoreMap":3559},[3563,13962,13963],{"class":3565,"line":3566},[3563,13964,13965],{"class":3583},"[tool.poetry]\n",[3563,13967,13968,13970,13972],{"class":3565,"line":3573},[3563,13969,9494],{"class":3613},[3563,13971,8871],{"class":3583},[3563,13973,13974],{"class":3645},"\"my-service\"\n",[3563,13976,13977,13979,13981],{"class":3565,"line":3580},[3563,13978,10900],{"class":3613},[3563,13980,8871],{"class":3583},[3563,13982,12068],{"class":3645},[3563,13984,13985,13987,13989],{"class":3565,"line":3594},[3563,13986,12073],{"class":3613},[3563,13988,8871],{"class":3583},[3563,13990,13991],{"class":3645},"\"Production-ready REST API\"\n",[3563,13993,13994,13997,13999,14002],{"class":3565,"line":3599},[3563,13995,13996],{"class":3613},"authors",[3563,13998,8890],{"class":3583},[3563,14000,14001],{"class":3645},"\"Developer \u003Cdev@example.com>\"",[3563,14003,6347],{"class":3583},[3563,14005,14006,14008,14010],{"class":3565,"line":3642},[3563,14007,12083],{"class":3613},[3563,14009,8871],{"class":3583},[3563,14011,12088],{"class":3645},[3563,14013,14014,14017,14020,14023,14025,14028],{"class":3565,"line":3649},[3563,14015,14016],{"class":3613},"packages",[3563,14018,14019],{"class":3583}," = [{",[3563,14021,14022],{"class":3613},"include",[3563,14024,8871],{"class":3583},[3563,14026,14027],{"class":3645},"\"my_service\"",[3563,14029,14030],{"class":3583},"}]\n",[3563,14032,14033],{"class":3565,"line":3659},[3563,14034,3577],{"emptyLinePlaceholder":3576},[3563,14036,14037],{"class":3565,"line":3664},[3563,14038,14039],{"class":3583},"[tool.poetry.dependencies]\n",[3563,14041,14042,14044,14046,14049],{"class":3565,"line":3694},[3563,14043,3558],{"class":3613},[3563,14045,8871],{"class":3583},[3563,14047,14048],{"class":3645},"\"^3.12\"",[3563,14050,14051],{"class":3569},"           # версія Python — обов'язкова\n",[3563,14053,14054,14057,14059,14062],{"class":3565,"line":3700},[3563,14055,14056],{"class":3613},"fastapi",[3563,14058,8871],{"class":3583},[3563,14060,14061],{"class":3645},"\">=0.115.0\"",[3563,14063,14064],{"class":3569},"      # прямі залежності проекту\n",[3563,14066,14067,14070,14072],{"class":3565,"line":3708},[3563,14068,14069],{"class":3613},"sqlalchemy",[3563,14071,8871],{"class":3583},[3563,14073,14074],{"class":3645},"\"^2.0\"\n",[3563,14076,14077,14080,14082],{"class":3565,"line":3713},[3563,14078,14079],{"class":3613},"pydantic",[3563,14081,8871],{"class":3583},[3563,14083,14084],{"class":3645},"\"^2.5\"\n",[3563,14086,14087,14090,14093,14096,14098,14101,14104,14106,14108,14111],{"class":3565,"line":3743},[3563,14088,14089],{"class":3613},"uvicorn",[3563,14091,14092],{"class":3583}," = {",[3563,14094,14095],{"class":3613},"extras",[3563,14097,8890],{"class":3583},[3563,14099,14100],{"class":3645},"\"standard\"",[3563,14102,14103],{"class":3583},"], ",[3563,14105,10900],{"class":3613},[3563,14107,8871],{"class":3583},[3563,14109,14110],{"class":3645},"\"^0.32\"",[3563,14112,4431],{"class":3583},[3563,14114,14115],{"class":3565,"line":3749},[3563,14116,3577],{"emptyLinePlaceholder":3576},[3563,14118,14119,14122],{"class":3565,"line":3757},[3563,14120,14121],{"class":3583},"[tool.poetry.group.dev.dependencies]  ",[3563,14123,14124],{"class":3569},"# група dev — не у production\n",[3563,14126,14127,14130,14132],{"class":3565,"line":3762},[3563,14128,14129],{"class":3613},"pytest",[3563,14131,8871],{"class":3583},[3563,14133,14134],{"class":3645},"\"^8.0\"\n",[3563,14136,14137,14140,14142],{"class":3565,"line":3785},[3563,14138,14139],{"class":3613},"pytest-asyncio",[3563,14141,8871],{"class":3583},[3563,14143,14144],{"class":3645},"\"^0.24\"\n",[3563,14146,14147,14149,14151],{"class":3565,"line":3791},[3563,14148,11731],{"class":3613},[3563,14150,8871],{"class":3583},[3563,14152,14153],{"class":3645},"\"^0.8\"\n",[3563,14155,14156,14159,14161],{"class":3565,"line":3802},[3563,14157,14158],{"class":3613},"mypy",[3563,14160,8871],{"class":3583},[3563,14162,14163],{"class":3645},"\"^1.13\"\n",[3563,14165,14166,14169,14171],{"class":3565,"line":3807},[3563,14167,14168],{"class":3613},"black",[3563,14170,8871],{"class":3583},[3563,14172,14173],{"class":3645},"\"^24.0\"\n",[3563,14175,14176],{"class":3565,"line":3828},[3563,14177,3577],{"emptyLinePlaceholder":3576},[3563,14179,14180,14183],{"class":3565,"line":3834},[3563,14181,14182],{"class":3583},"[tool.poetry.group.test.dependencies]  ",[3563,14184,14185],{"class":3569},"# окрема група для тестів\n",[3563,14187,14188,14191,14193,14196],{"class":3565,"line":3840},[3563,14189,14190],{"class":3613},"httpx",[3563,14192,8871],{"class":3583},[3563,14194,14195],{"class":3645},"\"^0.28\"",[3563,14197,14198],{"class":3569},"            # HTTP-клієнт для тестування FastAPI\n",[3563,14200,14201,14204,14206],{"class":3565,"line":3846},[3563,14202,14203],{"class":3613},"factory-boy",[3563,14205,8871],{"class":3583},[3563,14207,14208],{"class":3645},"\"^3.3\"\n",[3563,14210,14211],{"class":3565,"line":3851},[3563,14212,3577],{"emptyLinePlaceholder":3576},[3563,14214,14215],{"class":3565,"line":5463},[3563,14216,14217],{"class":3583},"[build-system]\n",[3563,14219,14220,14223,14225,14228],{"class":3565,"line":5468},[3563,14221,14222],{"class":3613},"requires",[3563,14224,8890],{"class":3583},[3563,14226,14227],{"class":3645},"\"poetry-core\"",[3563,14229,6347],{"class":3583},[3563,14231,14232,14235,14237],{"class":3565,"line":5474},[3563,14233,14234],{"class":3613},"build-backend",[3563,14236,8871],{"class":3583},[3563,14238,14239],{"class":3645},"\"poetry.core.masonry.api\"\n",[4287,14241,12110],{"id":14242},"управління-залежностями-1",[3554,14244,14246],{"className":11048,"code":14245,"language":11050,"meta":3559,"style":3559},"# Встановлення залежностей з pyproject.toml (також синхронізує lock)\npoetry install\n\n# Встановлення без dev-залежностей (для production)\npoetry install --without dev\n\n# Додавання нової залежності (оновлює pyproject.toml і lock автоматично)\npoetry add fastapi\npoetry add \"sqlalchemy>=2.0,\u003C3.0\"\npoetry add uvicorn[standard]          # з extras\n\n# Додавання dev-залежності\npoetry add --group dev pytest\npoetry add --group dev ruff black mypy\n\n# Видалення залежності\npoetry remove redis\n\n# Оновлення всіх залежностей (в межах версійних обмежень)\npoetry update\n\n# Оновлення конкретного пакету\npoetry update fastapi\n",[3398,14247,14248,14253,14260,14264,14269,14281,14285,14290,14298,14307,14318,14322,14327,14341,14357,14361,14365,14373,14377,14382,14389,14393,14398],{"__ignoreMap":3559},[3563,14249,14250],{"class":3565,"line":3566},[3563,14251,14252],{"class":3569},"# Встановлення залежностей з pyproject.toml (також синхронізує lock)\n",[3563,14254,14255,14257],{"class":3565,"line":3573},[3563,14256,11639],{"class":3606},[3563,14258,14259],{"class":3645}," install\n",[3563,14261,14262],{"class":3565,"line":3580},[3563,14263,3577],{"emptyLinePlaceholder":3576},[3563,14265,14266],{"class":3565,"line":3594},[3563,14267,14268],{"class":3569},"# Встановлення без dev-залежностей (для production)\n",[3563,14270,14271,14273,14275,14278],{"class":3565,"line":3599},[3563,14272,11639],{"class":3606},[3563,14274,11285],{"class":3645},[3563,14276,14277],{"class":3602}," --without",[3563,14279,14280],{"class":3645}," dev\n",[3563,14282,14283],{"class":3565,"line":3642},[3563,14284,3577],{"emptyLinePlaceholder":3576},[3563,14286,14287],{"class":3565,"line":3649},[3563,14288,14289],{"class":3569},"# Додавання нової залежності (оновлює pyproject.toml і lock автоматично)\n",[3563,14291,14292,14294,14296],{"class":3565,"line":3659},[3563,14293,11639],{"class":3606},[3563,14295,3607],{"class":3645},[3563,14297,12129],{"class":3645},[3563,14299,14300,14302,14304],{"class":3565,"line":3664},[3563,14301,11639],{"class":3606},[3563,14303,3607],{"class":3645},[3563,14305,14306],{"class":3645}," \"sqlalchemy>=2.0,\u003C3.0\"\n",[3563,14308,14309,14311,14313,14315],{"class":3565,"line":3694},[3563,14310,11639],{"class":3606},[3563,14312,3607],{"class":3645},[3563,14314,13171],{"class":3645},[3563,14316,14317],{"class":3569},"          # з extras\n",[3563,14319,14320],{"class":3565,"line":3700},[3563,14321,3577],{"emptyLinePlaceholder":3576},[3563,14323,14324],{"class":3565,"line":3708},[3563,14325,14326],{"class":3569},"# Додавання dev-залежності\n",[3563,14328,14329,14331,14333,14336,14339],{"class":3565,"line":3713},[3563,14330,11639],{"class":3606},[3563,14332,3607],{"class":3645},[3563,14334,14335],{"class":3602}," --group",[3563,14337,14338],{"class":3645}," dev",[3563,14340,12540],{"class":3645},[3563,14342,14343,14345,14347,14349,14351,14353,14355],{"class":3565,"line":3743},[3563,14344,11639],{"class":3606},[3563,14346,3607],{"class":3645},[3563,14348,14335],{"class":3602},[3563,14350,14338],{"class":3645},[3563,14352,12198],{"class":3645},[3563,14354,12212],{"class":3645},[3563,14356,12201],{"class":3645},[3563,14358,14359],{"class":3565,"line":3749},[3563,14360,3577],{"emptyLinePlaceholder":3576},[3563,14362,14363],{"class":3565,"line":3757},[3563,14364,12224],{"class":3569},[3563,14366,14367,14369,14371],{"class":3565,"line":3762},[3563,14368,11639],{"class":3606},[3563,14370,12231],{"class":3645},[3563,14372,12171],{"class":3645},[3563,14374,14375],{"class":3565,"line":3785},[3563,14376,3577],{"emptyLinePlaceholder":3576},[3563,14378,14379],{"class":3565,"line":3791},[3563,14380,14381],{"class":3569},"# Оновлення всіх залежностей (в межах версійних обмежень)\n",[3563,14383,14384,14386],{"class":3565,"line":3802},[3563,14385,11639],{"class":3606},[3563,14387,14388],{"class":3645}," update\n",[3563,14390,14391],{"class":3565,"line":3807},[3563,14392,3577],{"emptyLinePlaceholder":3576},[3563,14394,14395],{"class":3565,"line":3828},[3563,14396,14397],{"class":3569},"# Оновлення конкретного пакету\n",[3563,14399,14400,14402,14405],{"class":3565,"line":3834},[3563,14401,11639],{"class":3606},[3563,14403,14404],{"class":3645}," update",[3563,14406,12129],{"class":3645},[4032,14408,14410,14418,14422,14425,14442,14446,14450,14458,14462,14466,14473,14481,14488,14491],{"title":14409},"poetry install — встановлення та вирішення залежностей",[4036,14411,14413,4044,14416],{"className":14412},[3565],[3563,14414,4043],{"className":14415},[4042],[3406,14417,13674],{},[4036,14419,14421],{"className":14420},[3565],"Installing dependencies from lock file",[4036,14423],{"className":14424},[3565],[4036,14426,14428,14429,14433,14434,14437,14438,14441],{"className":14427},[3565],"Package operations: ",[3563,14430,14432],{"className":14431},[4071],"22"," installs, ",[3563,14435,5922],{"className":14436},[5716]," updates, ",[3563,14439,5922],{"className":14440},[6748]," removals",[4036,14443,14445],{"className":14444},[3565],"  • Installing annotated-types (0.7.0)",[4036,14447,14449],{"className":14448},[3565],"  • Installing anyio (4.7.0)",[4036,14451,14453,14454],{"className":14452},[3565],"  • ",[3563,14455,14457],{"className":14456},[4054],"Installing fastapi (0.115.6)",[4036,14459,14461],{"className":14460},[3565],"  • Installing pydantic (2.10.3)",[4036,14463,14465],{"className":14464},[3565],"  • Installing starlette (0.41.3)",[4036,14467,14453,14469],{"className":14468},[3565],[3563,14470,14472],{"className":14471},[4054],"Installing uvicorn (0.32.1)",[4036,14474,14476,14477],{"className":14475},[3565],"  • Installing pytest (8.3.4) ",[3563,14478,14480],{"className":14479},[4042],"(dev)",[4036,14482,14484,14485],{"className":14483},[3565],"  • Installing ruff (0.8.4) ",[3563,14486,14480],{"className":14487},[4042],[4036,14489],{"className":14490},[3565],[4036,14492,14494,14495],{"className":14493},[3565],"Installing the current project: ",[3563,14496,14498],{"className":14497},[4054],"my-service (0.1.0)",[4287,14500,14502],{"id":14501},"запуск-коду-у-середовищі-poetry","Запуск коду у середовищі Poetry",[3394,14504,14505,14506,4297],{},"Poetry не вимагає ручної активації середовища — використовуйте ",[3398,14507,14508],{},"poetry run",[3554,14510,14512],{"className":11048,"code":14511,"language":11050,"meta":3559,"style":3559},"# Запуск скрипта у середовищі проекту\npoetry run python main.py\n\n# Запуск застосунку\npoetry run uvicorn my_service.main:app --reload\n\n# Запуск тестів\npoetry run pytest\n\n# Запуск лінтера\npoetry run ruff check .\npoetry run mypy my_service\u002F\n\n# Або активувати середовище вручну (як у venv)\npoetry shell   # відкриває нову оболонку з активованим середовищем\nexit           # повернутись\n",[3398,14513,14514,14519,14529,14533,14537,14550,14554,14558,14566,14570,14574,14586,14597,14601,14606,14616],{"__ignoreMap":3559},[3563,14515,14516],{"class":3565,"line":3566},[3563,14517,14518],{"class":3569},"# Запуск скрипта у середовищі проекту\n",[3563,14520,14521,14523,14525,14527],{"class":3565,"line":3573},[3563,14522,11639],{"class":3606},[3563,14524,12493],{"class":3645},[3563,14526,11180],{"class":3645},[3563,14528,12498],{"class":3645},[3563,14530,14531],{"class":3565,"line":3580},[3563,14532,3577],{"emptyLinePlaceholder":3576},[3563,14534,14535],{"class":3565,"line":3594},[3563,14536,12507],{"class":3569},[3563,14538,14539,14541,14543,14545,14548],{"class":3565,"line":3599},[3563,14540,11639],{"class":3606},[3563,14542,12493],{"class":3645},[3563,14544,12516],{"class":3645},[3563,14546,14547],{"class":3645}," my_service.main:app",[3563,14549,12522],{"class":3602},[3563,14551,14552],{"class":3565,"line":3642},[3563,14553,3577],{"emptyLinePlaceholder":3576},[3563,14555,14556],{"class":3565,"line":3649},[3563,14557,12531],{"class":3569},[3563,14559,14560,14562,14564],{"class":3565,"line":3659},[3563,14561,11639],{"class":3606},[3563,14563,12493],{"class":3645},[3563,14565,12540],{"class":3645},[3563,14567,14568],{"class":3565,"line":3664},[3563,14569,3577],{"emptyLinePlaceholder":3576},[3563,14571,14572],{"class":3565,"line":3694},[3563,14573,12549],{"class":3569},[3563,14575,14576,14578,14580,14582,14584],{"class":3565,"line":3700},[3563,14577,11639],{"class":3606},[3563,14579,12493],{"class":3645},[3563,14581,12198],{"class":3645},[3563,14583,12560],{"class":3645},[3563,14585,12563],{"class":3645},[3563,14587,14588,14590,14592,14594],{"class":3565,"line":3708},[3563,14589,11639],{"class":3606},[3563,14591,12493],{"class":3645},[3563,14593,13189],{"class":3645},[3563,14595,14596],{"class":3645}," my_service\u002F\n",[3563,14598,14599],{"class":3565,"line":3713},[3563,14600,3577],{"emptyLinePlaceholder":3576},[3563,14602,14603],{"class":3565,"line":3743},[3563,14604,14605],{"class":3569},"# Або активувати середовище вручну (як у venv)\n",[3563,14607,14608,14610,14613],{"class":3565,"line":3749},[3563,14609,11639],{"class":3606},[3563,14611,14612],{"class":3645}," shell",[3563,14614,14615],{"class":3569},"   # відкриває нову оболонку з активованим середовищем\n",[3563,14617,14618,14621],{"class":3565,"line":3757},[3563,14619,14620],{"class":3606},"exit",[3563,14622,14623],{"class":3569},"           # повернутись\n",[4287,14625,13065,14627],{"id":14626},"довідник-команд-poetry",[3398,14628,11639],{},[5790,14630,14631,14673,14762,14823,14896,14945,15001,15064,15114],{},[5793,14632,14634,14647],{"name":14633,"type":13072},"poetry new \u002F poetry init",[3394,14635,14636,14639,14640,14643,14644,14646],{},[3398,14637,14638],{},"poetry new"," створює проект з готовою структурою папок. ",[3398,14641,14642],{},"poetry init"," — інтерактивно додає ",[3398,14645,11632],{}," до існуючої директорії.",[3554,14648,14650],{"className":11048,"code":14649,"language":11050,"meta":3559,"style":3559},"poetry new my-service         # новий проект зі структурою\npoetry init                   # додати poetry до існуючого проекту\n",[3398,14651,14652,14664],{"__ignoreMap":3559},[3563,14653,14654,14656,14658,14661],{"class":3565,"line":3566},[3563,14655,11639],{"class":3606},[3563,14657,13833],{"class":3645},[3563,14659,14660],{"class":3645}," my-service",[3563,14662,14663],{"class":3569},"         # новий проект зі структурою\n",[3563,14665,14666,14668,14670],{"class":3565,"line":3573},[3563,14667,11639],{"class":3606},[3563,14669,11921],{"class":3645},[3563,14671,14672],{"class":3569},"                   # додати poetry до існуючого проекту\n",[5793,14674,14676,14684],{"name":14675,"type":12110},"poetry add \u002F poetry remove",[3394,14677,13128,14678,4481,14680,14683],{},[3398,14679,11632],{},[3398,14681,14682],{},"poetry.lock",". Підтримує групи, extras та версійні обмеження.",[3554,14685,14687],{"className":11048,"code":14686,"language":11050,"meta":3559,"style":3559},"poetry add fastapi                       # остання версія\npoetry add \"sqlalchemy>=2.0,\u003C3\"         # з обмеженнями версій\npoetry add uvicorn[standard]             # з extras\npoetry add --group dev pytest ruff       # dev-група\npoetry add --group test httpx            # test-група\npoetry remove redis                      # видалення\n",[3398,14688,14689,14699,14709,14719,14736,14752],{"__ignoreMap":3559},[3563,14690,14691,14693,14695,14697],{"class":3565,"line":3566},[3563,14692,11639],{"class":3606},[3563,14694,3607],{"class":3645},[3563,14696,13147],{"class":3645},[3563,14698,13150],{"class":3569},[3563,14700,14701,14703,14705,14707],{"class":3565,"line":3573},[3563,14702,11639],{"class":3606},[3563,14704,3607],{"class":3645},[3563,14706,13159],{"class":3645},[3563,14708,13162],{"class":3569},[3563,14710,14711,14713,14715,14717],{"class":3565,"line":3580},[3563,14712,11639],{"class":3606},[3563,14714,3607],{"class":3645},[3563,14716,13171],{"class":3645},[3563,14718,13174],{"class":3569},[3563,14720,14721,14723,14725,14727,14729,14731,14733],{"class":3565,"line":3594},[3563,14722,11639],{"class":3606},[3563,14724,3607],{"class":3645},[3563,14726,14335],{"class":3602},[3563,14728,14338],{"class":3645},[3563,14730,12192],{"class":3645},[3563,14732,12198],{"class":3645},[3563,14734,14735],{"class":3569},"       # dev-група\n",[3563,14737,14738,14740,14742,14744,14747,14749],{"class":3565,"line":3599},[3563,14739,11639],{"class":3606},[3563,14741,3607],{"class":3645},[3563,14743,14335],{"class":3602},[3563,14745,14746],{"class":3645}," test",[3563,14748,12165],{"class":3645},[3563,14750,14751],{"class":3569},"            # test-група\n",[3563,14753,14754,14756,14758,14760],{"class":3565,"line":3642},[3563,14755,11639],{"class":3606},[3563,14757,12231],{"class":3645},[3563,14759,13201],{"class":3645},[3563,14761,13204],{"class":3569},[5793,14763,14765,14771],{"name":13674,"type":14764},"Встановлення залежностей",[3394,14766,14767,14768,14770],{},"Встановлює всі залежності з ",[3398,14769,14682],{},". Якщо lockfile відсутній — вирішує залежності і створює його.",[3554,14772,14774],{"className":11048,"code":14773,"language":11050,"meta":3559,"style":3559},"poetry install                  # встановити всі залежності\npoetry install --without dev    # тільки production\npoetry install --only test      # тільки вказана група\npoetry install --no-root        # без встановлення самого проекту\n",[3398,14775,14776,14784,14797,14811],{"__ignoreMap":3559},[3563,14777,14778,14780,14782],{"class":3565,"line":3566},[3563,14779,11639],{"class":3606},[3563,14781,11285],{"class":3645},[3563,14783,13231],{"class":3569},[3563,14785,14786,14788,14790,14792,14794],{"class":3565,"line":3573},[3563,14787,11639],{"class":3606},[3563,14789,11285],{"class":3645},[3563,14791,14277],{"class":3602},[3563,14793,14338],{"class":3645},[3563,14795,14796],{"class":3569},"    # тільки production\n",[3563,14798,14799,14801,14803,14806,14808],{"class":3565,"line":3580},[3563,14800,11639],{"class":3606},[3563,14802,11285],{"class":3645},[3563,14804,14805],{"class":3602}," --only",[3563,14807,14746],{"class":3645},[3563,14809,14810],{"class":3569},"      # тільки вказана група\n",[3563,14812,14813,14815,14817,14820],{"class":3565,"line":3594},[3563,14814,11639],{"class":3606},[3563,14816,11285],{"class":3645},[3563,14818,14819],{"class":3602}," --no-root",[3563,14821,14822],{"class":3569},"        # без встановлення самого проекту\n",[5793,14824,14825,14831],{"name":14508,"type":13258},[3394,14826,14827,14828,3459],{},"Виконує команду у середовищі проекту без ручної активації. Або відкрийте оболонку через ",[3398,14829,14830],{},"poetry shell",[3554,14832,14834],{"className":11048,"code":14833,"language":11050,"meta":3559,"style":3559},"poetry run python main.py              # запуск скрипта\npoetry run uvicorn app:app --reload    # запуск застосунку\npoetry run pytest                      # тести\npoetry run ruff check .                # лінтер\npoetry shell                           # активувати оболонку\n",[3398,14835,14836,14848,14862,14872,14887],{"__ignoreMap":3559},[3563,14837,14838,14840,14842,14844,14846],{"class":3565,"line":3566},[3563,14839,11639],{"class":3606},[3563,14841,12493],{"class":3645},[3563,14843,11180],{"class":3645},[3563,14845,13277],{"class":3645},[3563,14847,13280],{"class":3569},[3563,14849,14850,14852,14854,14856,14858,14860],{"class":3565,"line":3573},[3563,14851,11639],{"class":3606},[3563,14853,12493],{"class":3645},[3563,14855,12516],{"class":3645},[3563,14857,13291],{"class":3645},[3563,14859,13294],{"class":3602},[3563,14861,13297],{"class":3569},[3563,14863,14864,14866,14868,14870],{"class":3565,"line":3580},[3563,14865,11639],{"class":3606},[3563,14867,12493],{"class":3645},[3563,14869,12192],{"class":3645},[3563,14871,13308],{"class":3569},[3563,14873,14874,14876,14878,14880,14882,14884],{"class":3565,"line":3594},[3563,14875,11639],{"class":3606},[3563,14877,12493],{"class":3645},[3563,14879,12198],{"class":3645},[3563,14881,12560],{"class":3645},[3563,14883,12806],{"class":3645},[3563,14885,14886],{"class":3569},"                # лінтер\n",[3563,14888,14889,14891,14893],{"class":3565,"line":3599},[3563,14890,11639],{"class":3606},[3563,14892,14612],{"class":3645},[3563,14894,14895],{"class":3569},"                           # активувати оболонку\n",[5793,14897,14900,14908],{"name":14898,"type":14899},"poetry update","Оновлення залежностей",[3394,14901,14902,14903,14905,14906,3459],{},"Оновлює залежності до найновіших версій у межах обмежень з ",[3398,14904,11632],{},". Оновлює ",[3398,14907,14682],{},[3554,14909,14911],{"className":11048,"code":14910,"language":11050,"meta":3559,"style":3559},"poetry update              # оновити всі пакети\npoetry update fastapi      # оновити конкретний пакет\npoetry update --dry-run    # показати що зміниться (без застосування)\n",[3398,14912,14913,14922,14933],{"__ignoreMap":3559},[3563,14914,14915,14917,14919],{"class":3565,"line":3566},[3563,14916,11639],{"class":3606},[3563,14918,14404],{"class":3645},[3563,14920,14921],{"class":3569},"              # оновити всі пакети\n",[3563,14923,14924,14926,14928,14930],{"class":3565,"line":3573},[3563,14925,11639],{"class":3606},[3563,14927,14404],{"class":3645},[3563,14929,13147],{"class":3645},[3563,14931,14932],{"class":3569},"      # оновити конкретний пакет\n",[3563,14934,14935,14937,14939,14942],{"class":3565,"line":3580},[3563,14936,11639],{"class":3606},[3563,14938,14404],{"class":3645},[3563,14940,14941],{"class":3602}," --dry-run",[3563,14943,14944],{"class":3569},"    # показати що зміниться (без застосування)\n",[5793,14946,14949,14952],{"name":14947,"type":14948},"poetry show","Перегляд залежностей",[3394,14950,14951],{},"Відображає список встановлених пакетів або дерево залежностей з транзитивними пакетами.",[3554,14953,14955],{"className":11048,"code":14954,"language":11050,"meta":3559,"style":3559},"poetry show                # список всіх встановлених\npoetry show --tree         # дерево залежностей\npoetry show fastapi        # деталі конкретного пакету\npoetry show --outdated     # застарілі пакети\n",[3398,14956,14957,14966,14978,14989],{"__ignoreMap":3559},[3563,14958,14959,14961,14963],{"class":3565,"line":3566},[3563,14960,11639],{"class":3606},[3563,14962,11365],{"class":3645},[3563,14964,14965],{"class":3569},"                # список всіх встановлених\n",[3563,14967,14968,14970,14972,14975],{"class":3565,"line":3573},[3563,14969,11639],{"class":3606},[3563,14971,11365],{"class":3645},[3563,14973,14974],{"class":3602}," --tree",[3563,14976,14977],{"class":3569},"         # дерево залежностей\n",[3563,14979,14980,14982,14984,14986],{"class":3565,"line":3580},[3563,14981,11639],{"class":3606},[3563,14983,11365],{"class":3645},[3563,14985,13147],{"class":3645},[3563,14987,14988],{"class":3569},"        # деталі конкретного пакету\n",[3563,14990,14991,14993,14995,14998],{"class":3565,"line":3594},[3563,14992,11639],{"class":3606},[3563,14994,11365],{"class":3645},[3563,14996,14997],{"class":3602}," --outdated",[3563,14999,15000],{"class":3569},"     # застарілі пакети\n",[5793,15002,15005,15008],{"name":15003,"type":15004},"poetry env","Управління середовищем",[3394,15006,15007],{},"Переглядає та управляє віртуальними середовищами Poetry.",[3554,15009,15011],{"className":11048,"code":15010,"language":11050,"meta":3559,"style":3559},"poetry env info             # поточне середовище та Python\npoetry env list             # всі середовища проекту\npoetry env remove 3.12      # видалити середовище\npoetry env use 3.11         # перемкнути на іншу версію Python\n",[3398,15012,15013,15026,15037,15050],{"__ignoreMap":3559},[3563,15014,15015,15017,15020,15023],{"class":3565,"line":3566},[3563,15016,11639],{"class":3606},[3563,15018,15019],{"class":3645}," env",[3563,15021,15022],{"class":3645}," info",[3563,15024,15025],{"class":3569},"             # поточне середовище та Python\n",[3563,15027,15028,15030,15032,15034],{"class":3565,"line":3573},[3563,15029,11639],{"class":3606},[3563,15031,15019],{"class":3645},[3563,15033,9167],{"class":3645},[3563,15035,15036],{"class":3569},"             # всі середовища проекту\n",[3563,15038,15039,15041,15043,15045,15047],{"class":3565,"line":3580},[3563,15040,11639],{"class":3606},[3563,15042,15019],{"class":3645},[3563,15044,12231],{"class":3645},[3563,15046,12695],{"class":3587},[3563,15048,15049],{"class":3569},"      # видалити середовище\n",[3563,15051,15052,15054,15056,15059,15061],{"class":3565,"line":3594},[3563,15053,11639],{"class":3606},[3563,15055,15019],{"class":3645},[3563,15057,15058],{"class":3645}," use",[3563,15060,12651],{"class":3587},[3563,15062,15063],{"class":3569},"         # перемкнути на іншу версію Python\n",[5793,15065,15068,15075],{"name":15066,"type":15067},"poetry export","Сумісність з pip",[3394,15069,15070,15071,13582,15073,3459],{},"Експортує залежності у ",[3398,15072,11473],{},[3398,15074,11632],{},[3554,15076,15078],{"className":11048,"code":15077,"language":11050,"meta":3559,"style":3559},"poetry export -f requirements.txt --output requirements.txt\npoetry export -f requirements.txt --without dev --output req-prod.txt\n",[3398,15079,15080,15095],{"__ignoreMap":3559},[3563,15081,15082,15084,15086,15088,15090,15093],{"class":3565,"line":3566},[3563,15083,11639],{"class":3606},[3563,15085,13606],{"class":3645},[3563,15087,13609],{"class":3602},[3563,15089,13434],{"class":3645},[3563,15091,15092],{"class":3602}," --output",[3563,15094,11522],{"class":3645},[3563,15096,15097,15099,15101,15103,15105,15107,15109,15111],{"class":3565,"line":3573},[3563,15098,11639],{"class":3606},[3563,15100,13606],{"class":3645},[3563,15102,13609],{"class":3602},[3563,15104,13434],{"class":3645},[3563,15106,14277],{"class":3602},[3563,15108,14338],{"class":3645},[3563,15110,15092],{"class":3602},[3563,15112,15113],{"class":3645}," req-prod.txt\n",[5793,15115,15118,15128],{"name":15116,"type":15117},"poetry build \u002F poetry publish","Публікація пакету",[3394,15119,15120,15121,3624,15123,15125,15126,3459],{},"Збирає дистрибутив (wheel + sdist) та публікує на PyPI. Замінює ",[3398,15122,13701],{},[3398,15124,13704],{}," та ручне редагування ",[3398,15127,11802],{},[3554,15129,15131],{"className":11048,"code":15130,"language":11050,"meta":3559,"style":3559},"poetry build                  # зібрати dist\u002F (wheel + tar.gz)\npoetry publish                # опублікувати на PyPI\npoetry publish --build        # зібрати і опублікувати одразу\npoetry publish --repository testpypi  # на тестовий PyPI\n",[3398,15132,15133,15143,15153,15165],{"__ignoreMap":3559},[3563,15134,15135,15137,15140],{"class":3565,"line":3566},[3563,15136,11639],{"class":3606},[3563,15138,15139],{"class":3645}," build",[3563,15141,15142],{"class":3569},"                  # зібрати dist\u002F (wheel + tar.gz)\n",[3563,15144,15145,15147,15150],{"class":3565,"line":3573},[3563,15146,11639],{"class":3606},[3563,15148,15149],{"class":3645}," publish",[3563,15151,15152],{"class":3569},"                # опублікувати на PyPI\n",[3563,15154,15155,15157,15159,15162],{"class":3565,"line":3580},[3563,15156,11639],{"class":3606},[3563,15158,15149],{"class":3645},[3563,15160,15161],{"class":3602}," --build",[3563,15163,15164],{"class":3569},"        # зібрати і опублікувати одразу\n",[3563,15166,15167,15169,15171,15174,15177],{"class":3565,"line":3594},[3563,15168,11639],{"class":3606},[3563,15170,15149],{"class":3645},[3563,15172,15173],{"class":3602}," --repository",[3563,15175,15176],{"class":3645}," testpypi",[3563,15178,15179],{"class":3569},"  # на тестовий PyPI\n",[3461,15181],{},[3468,15183,15185,15186,15189,15190,5787],{"id":15184},"робота-з-git-що-робити-після-git-clone","Робота з ",[3398,15187,15188],{},"git",": що робити після ",[3398,15191,15192],{},"git clone",[3394,15194,15195,15196,15199],{},"Один із найпоширеніших питань початківців: ",[4093,15197,15198],{},"«Я склонував репозиторій. Що далі?»",". Відповідь залежить від того, яким менеджером пакетів користується проект.",[4287,15201,15203],{"id":15202},"як-розпізнати-менеджер-пакетів-проекту","Як розпізнати менеджер пакетів проекту",[3394,15205,15206],{},"Першим ділом — подивіться на файли у корені репозиторію:",[5790,15208,15209,15227,15245],{},[5793,15210,15213,15221],{"name":15211,"type":15212},"uv.lock + pyproject.toml","Проект на uv",[3394,15214,15215,15216,15218,15219,3459],{},"Є обидва файли — це ",[3398,15217,11642],{},"-проект. Команда для старту: ",[3398,15220,11788],{},[3554,15222,15225],{"className":15223,"code":15224,"language":8718},[8716],"my-project\u002F\n├── pyproject.toml   ← залежності та метадані\n├── uv.lock          ← детермінований lockfile\n├── .python-version  ← зафіксована версія Python\n└── src\u002F\n",[3398,15226,15224],{"__ignoreMap":3559},[5793,15228,15231,15239],{"name":15229,"type":15230},"poetry.lock + pyproject.toml","Проект на Poetry",[3394,15232,15233,15234,15236,15237,3459],{},"Є ",[3398,15235,14682],{}," — це Poetry-проект. Команда для старту: ",[3398,15238,13674],{},[3554,15240,15243],{"className":15241,"code":15242,"language":8718},[8716],"my-project\u002F\n├── pyproject.toml   ← залежності та метадані\n├── poetry.lock      ← детермінований lockfile\n└── src\u002F\n",[3398,15244,15242],{"__ignoreMap":3559},[5793,15246,15248,15256],{"name":11473,"type":15247},"Класичний pip-проект",[3394,15249,15250,15251,15253,15254,3459],{},"Тільки ",[3398,15252,11473],{}," — класичний підхід. Команда для старту: ",[3398,15255,13216],{},[3554,15257,15260],{"className":15258,"code":15259,"language":8718},[8716],"my-project\u002F\n├── requirements.txt ← список залежностей\n└── app.py\n",[3398,15261,15259],{"__ignoreMap":3559},[4287,15263,15265,15266,15268,15269,15271],{"id":15264},"флоу-після-git-clone-uv-проект","Флоу після ",[3398,15267,15192],{}," — ",[3398,15270,11642],{},"-проект",[4299,15273,15274,15278,15299,15303,15314,15340,15344,15355,15366,15425,15429],{},[3468,15275,15277],{"id":15276},"клонувати-та-перейти-у-директорію","Клонувати та перейти у директорію",[3554,15279,15281],{"className":11048,"code":15280,"language":11050,"meta":3559,"style":3559},"git clone https:\u002F\u002Fgithub.com\u002Forg\u002Fmy-project.git\ncd my-project\n",[3398,15282,15283,15293],{"__ignoreMap":3559},[3563,15284,15285,15287,15290],{"class":3565,"line":3566},[3563,15286,15188],{"class":3606},[3563,15288,15289],{"class":3645}," clone",[3563,15291,15292],{"class":3645}," https:\u002F\u002Fgithub.com\u002Forg\u002Fmy-project.git\n",[3563,15294,15295,15297],{"class":3565,"line":3573},[3563,15296,11929],{"class":3606},[3563,15298,11956],{"class":3645},[3468,15300,15302],{"id":15301},"перевірити-версію-python-опційно","Перевірити версію Python (опційно)",[3394,15304,15305,15307,15308,15310,15311,15313],{},[3398,15306,11642],{}," прочитає ",[3398,15309,12000],{}," автоматично. Якщо потрібна версія відсутня — ",[3398,15312,11642],{}," завантажить її сам:",[3554,15315,15317],{"className":11048,"code":15316,"language":11050,"meta":3559,"style":3559},"cat .python-version  # наприклад: 3.12\nuv python list       # перевірити що встановлено\n",[3398,15318,15319,15329],{"__ignoreMap":3559},[3563,15320,15321,15323,15326],{"class":3565,"line":3566},[3563,15322,11519],{"class":3606},[3563,15324,15325],{"class":3645}," .python-version",[3563,15327,15328],{"class":3569},"  # наприклад: 3.12\n",[3563,15330,15331,15333,15335,15337],{"class":3565,"line":3573},[3563,15332,11642],{"class":3606},[3563,15334,11180],{"class":3645},[3563,15336,9167],{"class":3645},[3563,15338,15339],{"class":3569},"       # перевірити що встановлено\n",[3468,15341,15343],{"id":15342},"синхронізувати-середовище","Синхронізувати середовище",[3394,15345,15346,15347,15349,15350,15352,15353,4297],{},"Одна команда — і все готово. ",[3398,15348,11642],{}," сам створить ",[3398,15351,13811],{}," і встановить точні версії з ",[3398,15354,11784],{},[3554,15356,15358],{"className":11048,"code":15357,"language":11050,"meta":3559,"style":3559},"uv sync\n",[3398,15359,15360],{"__ignoreMap":3559},[3563,15361,15362,15364],{"class":3565,"line":3566},[3563,15363,11642],{"class":3606},[3563,15365,12249],{"class":3645},[4032,15367,15369,15377,15381,15385,15396,15406,15410,15414,15418],{"title":15368},"uv sync після git clone",[4036,15370,15372,4044,15375],{"className":15371},[3565],[3563,15373,4043],{"className":15374},[4042],[3406,15376,11788],{},[4036,15378,15380],{"className":15379},[3565],"Using CPython 3.12.8 interpreter at: \u002FUsers\u002Fuser\u002F.local\u002Fshare\u002Fuv\u002Fpython\u002F...",[4036,15382,15384],{"className":15383},[3565],"Creating virtual environment at: .venv",[4036,15386,12284,15388,12288,15392],{"className":15387},[3565],[3563,15389,15391],{"className":15390},[4071],"42",[3563,15393,15395],{"className":15394},[4054],"183ms",[4036,15397,12296,15399,12288,15402],{"className":15398},[3565],[3563,15400,15391],{"className":15401},[4071],[3563,15403,15405],{"className":15404},[4054],"1.2s",[4036,15407,15409],{"className":15408},[3565]," + fastapi==0.115.6",[4036,15411,15413],{"className":15412},[3565]," + sqlalchemy==2.0.36",[4036,15415,15417],{"className":15416},[3565]," + ... та інші",[4036,15419,15421],{"className":15420},[3565],[3563,15422,15424],{"className":15423},[4054],"All dependencies are satisfied.",[3468,15426,15428],{"id":15427},"запустити-проект","Запустити проект",[3554,15430,15432],{"className":11048,"code":15431,"language":11050,"meta":3559,"style":3559},"uv run python main.py          # скрипт\nuv run uvicorn app:app --reload  # FastAPI\nuv run pytest                  # тести\n",[3398,15433,15434,15447,15462],{"__ignoreMap":3559},[3563,15435,15436,15438,15440,15442,15444],{"class":3565,"line":3566},[3563,15437,11642],{"class":3606},[3563,15439,12493],{"class":3645},[3563,15441,11180],{"class":3645},[3563,15443,13277],{"class":3645},[3563,15445,15446],{"class":3569},"          # скрипт\n",[3563,15448,15449,15451,15453,15455,15457,15459],{"class":3565,"line":3573},[3563,15450,11642],{"class":3606},[3563,15452,12493],{"class":3645},[3563,15454,12516],{"class":3645},[3563,15456,13291],{"class":3645},[3563,15458,13294],{"class":3602},[3563,15460,15461],{"class":3569},"  # FastAPI\n",[3563,15463,15464,15466,15468,15470],{"class":3565,"line":3580},[3563,15465,11642],{"class":3606},[3563,15467,12493],{"class":3645},[3563,15469,12192],{"class":3645},[3563,15471,15472],{"class":3569},"                  # тести\n",[11028,15474,15475,15476,15268,15478,15480,15481,3459],{},"Ніякого ",[3398,15477,11001],{},[3398,15479,12475],{}," все робить сам. Але якщо хочете активувати середовище явно для IDE або оболонки: ",[3398,15482,11001],{},[4287,15484,15265,15486,15488],{"id":15485},"флоу-після-git-clone-poetry-проект",[3398,15487,15192],{}," — Poetry-проект",[4299,15490,15491,15494,15512,15516,15536,15540,15546,15557,15617,15620],{},[3468,15492,15277],{"id":15493},"клонувати-та-перейти-у-директорію-1",[3554,15495,15496],{"className":11048,"code":15280,"language":11050,"meta":3559,"style":3559},[3398,15497,15498,15506],{"__ignoreMap":3559},[3563,15499,15500,15502,15504],{"class":3565,"line":3566},[3563,15501,15188],{"class":3606},[3563,15503,15289],{"class":3645},[3563,15505,15292],{"class":3645},[3563,15507,15508,15510],{"class":3565,"line":3573},[3563,15509,11929],{"class":3606},[3563,15511,11956],{"class":3645},[3468,15513,15515],{"id":15514},"перевірити-налаштування-poetry-один-раз","Перевірити налаштування Poetry (один раз)",[3554,15517,15519],{"className":11048,"code":15518,"language":11050,"meta":3559,"style":3559},"# Рекомендовано: зберігати venv всередині проекту\npoetry config virtualenvs.in-project true\n",[3398,15520,15521,15526],{"__ignoreMap":3559},[3563,15522,15523],{"class":3565,"line":3566},[3563,15524,15525],{"class":3569},"# Рекомендовано: зберігати venv всередині проекту\n",[3563,15527,15528,15530,15532,15534],{"class":3565,"line":3573},[3563,15529,11639],{"class":3606},[3563,15531,13796],{"class":3645},[3563,15533,13799],{"class":3645},[3563,15535,13802],{"class":3602},[3468,15537,15539],{"id":15538},"встановити-залежності","Встановити залежності",[3394,15541,15542,15543,15545],{},"Poetry прочитає ",[3398,15544,14682],{}," і встановить точні версії:",[3554,15547,15549],{"className":11048,"code":15548,"language":11050,"meta":3559,"style":3559},"poetry install\n",[3398,15550,15551],{"__ignoreMap":3559},[3563,15552,15553,15555],{"class":3565,"line":3566},[3563,15554,11639],{"class":3606},[3563,15556,14259],{"class":3645},[4032,15558,15560,15568,15571,15574,15587,15590,15596,15599,15603,15607,15610],{"title":15559},"poetry install після git clone",[4036,15561,15563,4044,15566],{"className":15562},[3565],[3563,15564,4043],{"className":15565},[4042],[3406,15567,13674],{},[4036,15569,14421],{"className":15570},[3565],[4036,15572],{"className":15573},[3565],[4036,15575,14428,15577,14433,15581,14437,15584,14441],{"className":15576},[3565],[3563,15578,15580],{"className":15579},[4071],"38",[3563,15582,5922],{"className":15583},[5716],[3563,15585,5922],{"className":15586},[6748],[4036,15588,14445],{"className":15589},[3565],[4036,15591,14453,15593],{"className":15592},[3565],[3563,15594,14457],{"className":15595},[4054],[4036,15597,14461],{"className":15598},[3565],[4036,15600,15602],{"className":15601},[3565],"  • Installing sqlalchemy (2.0.36)",[4036,15604,15606],{"className":15605},[3565],"  • ...",[4036,15608],{"className":15609},[3565],[4036,15611,14494,15613],{"className":15612},[3565],[3563,15614,15616],{"className":15615},[4054],"my-project (0.1.0)",[3468,15618,15428],{"id":15619},"запустити-проект-1",[3554,15621,15623],{"className":11048,"code":15622,"language":11050,"meta":3559,"style":3559},"poetry run python main.py\npoetry run uvicorn app:app --reload\npoetry run pytest\n",[3398,15624,15625,15635,15647],{"__ignoreMap":3559},[3563,15626,15627,15629,15631,15633],{"class":3565,"line":3566},[3563,15628,11639],{"class":3606},[3563,15630,12493],{"class":3645},[3563,15632,11180],{"class":3645},[3563,15634,12498],{"class":3645},[3563,15636,15637,15639,15641,15643,15645],{"class":3565,"line":3573},[3563,15638,11639],{"class":3606},[3563,15640,12493],{"class":3645},[3563,15642,12516],{"class":3645},[3563,15644,13291],{"class":3645},[3563,15646,12522],{"class":3602},[3563,15648,15649,15651,15653],{"class":3565,"line":3580},[3563,15650,11639],{"class":3606},[3563,15652,12493],{"class":3645},[3563,15654,12540],{"class":3645},[4287,15656,15658,15659,15661],{"id":15657},"що-комітити-у-git-таблиця","Що комітити у ",[3398,15660,15188],{},"? Таблиця",[3394,15663,15664,15665,3624,15668,15268,15671,3459],{},"Правило просте: ",[3406,15666,15667],{},"lockfile завжди комітити",[3398,15669,15670],{},".venv",[3406,15672,15673],{},"ніколи",[8132,15675,15676,15689],{},[8135,15677,15678],{},[8138,15679,15680,15683,15686],{},[8141,15681,15682],{},"Файл",[8141,15684,15685],{},"Комітити?",[8141,15687,15688],{},"Причина",[8152,15690,15691,15703,15714,15724,15735,15746,15761,15775,15789],{},[8138,15692,15693,15697,15700],{},[8157,15694,15695],{},[3398,15696,11632],{},[8157,15698,15699],{},"✅ Так",[8157,15701,15702],{},"Метадані та прямі залежності проекту",[8138,15704,15705,15709,15711],{},[8157,15706,15707],{},[3398,15708,11784],{},[8157,15710,15699],{},[8157,15712,15713],{},"Детермінований lockfile для відтворення",[8138,15715,15716,15720,15722],{},[8157,15717,15718],{},[3398,15719,14682],{},[8157,15721,15699],{},[8157,15723,15713],{},[8138,15725,15726,15730,15732],{},[8157,15727,15728],{},[3398,15729,11473],{},[8157,15731,15699],{},[8157,15733,15734],{},"Якщо проект класичний pip",[8138,15736,15737,15741,15743],{},[8157,15738,15739],{},[3398,15740,12000],{},[8157,15742,15699],{},[8157,15744,15745],{},"Фіксує версію Python для команди",[8138,15747,15748,15752,15755],{},[8157,15749,15750],{},[3398,15751,13811],{},[8157,15753,15754],{},"❌ Ні",[8157,15756,15757,15758],{},"Велика, специфічна для ОС — у ",[3398,15759,15760],{},".gitignore",[8138,15762,15763,15768,15770],{},[8157,15764,15765],{},[3398,15766,15767],{},"__pycache__\u002F",[8157,15769,15754],{},[8157,15771,15772,15773],{},"Кеш байткоду — у ",[3398,15774,15760],{},[8138,15776,15777,15782,15784],{},[8157,15778,15779],{},[3398,15780,15781],{},"*.pyc",[8157,15783,15754],{},[8157,15785,15786,15787],{},"Компільований байткод — у ",[3398,15788,15760],{},[8138,15790,15791,15796,15798],{},[8157,15792,15793],{},[3398,15794,15795],{},".env",[8157,15797,15754],{},[8157,15799,15800,15801],{},"Секрети та конфіги — у ",[3398,15802,15760],{},[4287,15804,15806,15807,15809],{"id":15805},"стандартний-gitignore-для-python-проекту","Стандартний ",[3398,15808,15760],{}," для Python-проекту",[3554,15811,15815],{"className":15812,"code":15813,"language":15814,"meta":3559,"style":3559},"language-gitignore shiki shiki-themes light-plus dark-plus dark-plus","# Віртуальні середовища\n.venv\u002F\nvenv\u002F\nenv\u002F\n\n# Байткод та кеш\n__pycache__\u002F\n*.py[cod]\n*$py.class\n*.pyo\n\n# Артефакти збірки\ndist\u002F\nbuild\u002F\n*.egg-info\u002F\n*.egg\n\n# Тести та покриття\n.pytest_cache\u002F\n.coverage\nhtmlcov\u002F\n\n# Типи та лінтери\n.mypy_cache\u002F\n.ruff_cache\u002F\n\n# Середовище та секрети\n.env\n.env.local\n*.env\n\n# IDE\n.idea\u002F\n.vscode\u002F\n*.swp\n","gitignore",[3398,15816,15817,15822,15827,15832,15837,15841,15846,15851,15856,15861,15866,15870,15875,15880,15885,15890,15895,15899,15904,15909,15914,15919,15923,15928,15933,15938,15942,15947,15952,15957,15962,15966,15971,15976,15981],{"__ignoreMap":3559},[3563,15818,15819],{"class":3565,"line":3566},[3563,15820,15821],{},"# Віртуальні середовища\n",[3563,15823,15824],{"class":3565,"line":3573},[3563,15825,15826],{},".venv\u002F\n",[3563,15828,15829],{"class":3565,"line":3580},[3563,15830,15831],{},"venv\u002F\n",[3563,15833,15834],{"class":3565,"line":3594},[3563,15835,15836],{},"env\u002F\n",[3563,15838,15839],{"class":3565,"line":3599},[3563,15840,3577],{"emptyLinePlaceholder":3576},[3563,15842,15843],{"class":3565,"line":3642},[3563,15844,15845],{},"# Байткод та кеш\n",[3563,15847,15848],{"class":3565,"line":3649},[3563,15849,15850],{},"__pycache__\u002F\n",[3563,15852,15853],{"class":3565,"line":3659},[3563,15854,15855],{},"*.py[cod]\n",[3563,15857,15858],{"class":3565,"line":3664},[3563,15859,15860],{},"*$py.class\n",[3563,15862,15863],{"class":3565,"line":3694},[3563,15864,15865],{},"*.pyo\n",[3563,15867,15868],{"class":3565,"line":3700},[3563,15869,3577],{"emptyLinePlaceholder":3576},[3563,15871,15872],{"class":3565,"line":3708},[3563,15873,15874],{},"# Артефакти збірки\n",[3563,15876,15877],{"class":3565,"line":3713},[3563,15878,15879],{},"dist\u002F\n",[3563,15881,15882],{"class":3565,"line":3743},[3563,15883,15884],{},"build\u002F\n",[3563,15886,15887],{"class":3565,"line":3749},[3563,15888,15889],{},"*.egg-info\u002F\n",[3563,15891,15892],{"class":3565,"line":3757},[3563,15893,15894],{},"*.egg\n",[3563,15896,15897],{"class":3565,"line":3762},[3563,15898,3577],{"emptyLinePlaceholder":3576},[3563,15900,15901],{"class":3565,"line":3785},[3563,15902,15903],{},"# Тести та покриття\n",[3563,15905,15906],{"class":3565,"line":3791},[3563,15907,15908],{},".pytest_cache\u002F\n",[3563,15910,15911],{"class":3565,"line":3802},[3563,15912,15913],{},".coverage\n",[3563,15915,15916],{"class":3565,"line":3807},[3563,15917,15918],{},"htmlcov\u002F\n",[3563,15920,15921],{"class":3565,"line":3828},[3563,15922,3577],{"emptyLinePlaceholder":3576},[3563,15924,15925],{"class":3565,"line":3834},[3563,15926,15927],{},"# Типи та лінтери\n",[3563,15929,15930],{"class":3565,"line":3840},[3563,15931,15932],{},".mypy_cache\u002F\n",[3563,15934,15935],{"class":3565,"line":3846},[3563,15936,15937],{},".ruff_cache\u002F\n",[3563,15939,15940],{"class":3565,"line":3851},[3563,15941,3577],{"emptyLinePlaceholder":3576},[3563,15943,15944],{"class":3565,"line":5463},[3563,15945,15946],{},"# Середовище та секрети\n",[3563,15948,15949],{"class":3565,"line":5468},[3563,15950,15951],{},".env\n",[3563,15953,15954],{"class":3565,"line":5474},[3563,15955,15956],{},".env.local\n",[3563,15958,15959],{"class":3565,"line":5480},[3563,15960,15961],{},"*.env\n",[3563,15963,15964],{"class":3565,"line":5486},[3563,15965,3577],{"emptyLinePlaceholder":3576},[3563,15967,15968],{"class":3565,"line":5492},[3563,15969,15970],{},"# IDE\n",[3563,15972,15973],{"class":3565,"line":5498},[3563,15974,15975],{},".idea\u002F\n",[3563,15977,15978],{"class":3565,"line":5504},[3563,15979,15980],{},".vscode\u002F\n",[3563,15982,15983],{"class":3565,"line":5509},[3563,15984,15985],{},"*.swp\n",[3461,15987],{},[3468,15989,15991,15992,4481,15994],{"id":15990},"статичний-аналіз-типів-mypy-та-pyright","Статичний аналіз типів: ",[3398,15993,14158],{},[3398,15995,15996],{},"Pyright",[3394,15998,15999,16000,16003,16004,7274,16007,16010,16011,16014,16015,16018],{},"Python — мова з ",[3406,16001,16002],{},"динамічною"," типізацією: типи перевіряються під час виконання. Але з Python 3.5+ з'явилися ",[3406,16005,16006],{},"анотації типів",[3398,16008,16009],{},"def foo(x: int) -> str:","), і на цій основі побудовані ",[3406,16012,16013],{},"статичні аналізатори"," — інструменти, що знаходять помилки типів ",[4093,16016,16017],{},"до"," запуску програми.",[3411,16020,16021,16025],{},[3414,16022,16024],{"icon":16023,"title":14158},"i-heroicons-check-badge","Офіційний статичний аналізатор від команди Python. Написаний на Python. Стандарт для більшості проектів, широко підтримується в CI\u002FCD та IDE.",[3414,16026,16027,16028,3459],{"icon":11752,"title":15996},"Написаний на TypeScript (!) від Microsoft. Значно швидший за mypy. Є основою для type-checking у Pylance (VSCode). Також доступний як CLI — ",[3398,16029,16030],{},"pyright",[4287,16032,16034],{"id":16033},"навіщо-потрібен-статичний-аналіз-типів","Навіщо потрібен статичний аналіз типів?",[3554,16036,16038],{"className":3556,"code":16037,"language":3558,"meta":3559,"style":3559},"# Без анотацій — помилка знайдеться лише під час виконання\ndef get_user_age(user):\n    return user[\"age\"] + 1  # KeyError? TypeError? Дізнаємось пізно\n\n# З анотаціями — mypy\u002FPyright знаходять помилки відразу\nfrom typing import TypedDict\n\nclass User(TypedDict):\n    name: str\n    age: int\n\ndef get_user_age(user: User) -> int:\n    return user[\"age\"] + 1  # mypy: OK\n    # return user[\"nme\"] + 1  # mypy: ERROR — key \"nme\" не існує у User\n",[3398,16039,16040,16045,16059,16077,16081,16086,16098,16102,16117,16125,16133,16137,16154,16169],{"__ignoreMap":3559},[3563,16041,16042],{"class":3565,"line":3566},[3563,16043,16044],{"class":3569},"# Без анотацій — помилка знайдеться лише під час виконання\n",[3563,16046,16047,16049,16052,16054,16057],{"class":3565,"line":3573},[3563,16048,3603],{"class":3602},[3563,16050,16051],{"class":3606}," get_user_age",[3563,16053,3610],{"class":3583},[3563,16055,16056],{"class":3613},"user",[3563,16058,7337],{"class":3583},[3563,16060,16061,16063,16066,16069,16072,16074],{"class":3565,"line":3580},[3563,16062,3653],{"class":3652},[3563,16064,16065],{"class":3583}," user[",[3563,16067,16068],{"class":3645},"\"age\"",[3563,16070,16071],{"class":3583},"] + ",[3563,16073,5061],{"class":3587},[3563,16075,16076],{"class":3569},"  # KeyError? TypeError? Дізнаємось пізно\n",[3563,16078,16079],{"class":3565,"line":3594},[3563,16080,3577],{"emptyLinePlaceholder":3576},[3563,16082,16083],{"class":3565,"line":3599},[3563,16084,16085],{"class":3569},"# З анотаціями — mypy\u002FPyright знаходять помилки відразу\n",[3563,16087,16088,16090,16093,16095],{"class":3565,"line":3642},[3563,16089,4907],{"class":3652},[3563,16091,16092],{"class":3583}," typing ",[3563,16094,3905],{"class":3652},[3563,16096,16097],{"class":3583}," TypedDict\n",[3563,16099,16100],{"class":3565,"line":3649},[3563,16101,3577],{"emptyLinePlaceholder":3576},[3563,16103,16104,16107,16110,16112,16115],{"class":3565,"line":3659},[3563,16105,16106],{"class":3602},"class",[3563,16108,16109],{"class":3620}," User",[3563,16111,3610],{"class":3583},[3563,16113,16114],{"class":3620},"TypedDict",[3563,16116,7337],{"class":3583},[3563,16118,16119,16122],{"class":3565,"line":3664},[3563,16120,16121],{"class":3583},"    name: ",[3563,16123,16124],{"class":3620},"str\n",[3563,16126,16127,16130],{"class":3565,"line":3694},[3563,16128,16129],{"class":3583},"    age: ",[3563,16131,16132],{"class":3620},"int\n",[3563,16134,16135],{"class":3565,"line":3700},[3563,16136,3577],{"emptyLinePlaceholder":3576},[3563,16138,16139,16141,16143,16145,16147,16150,16152],{"class":3565,"line":3708},[3563,16140,3603],{"class":3602},[3563,16142,16051],{"class":3606},[3563,16144,3610],{"class":3583},[3563,16146,16056],{"class":3613},[3563,16148,16149],{"class":3583},": User) -> ",[3563,16151,3867],{"class":3620},[3563,16153,3639],{"class":3583},[3563,16155,16156,16158,16160,16162,16164,16166],{"class":3565,"line":3713},[3563,16157,3653],{"class":3652},[3563,16159,16065],{"class":3583},[3563,16161,16068],{"class":3645},[3563,16163,16071],{"class":3583},[3563,16165,5061],{"class":3587},[3563,16167,16168],{"class":3569},"  # mypy: OK\n",[3563,16170,16171],{"class":3565,"line":3743},[3563,16172,16173],{"class":3569},"    # return user[\"nme\"] + 1  # mypy: ERROR — key \"nme\" не існує у User\n",[4287,16175,16177,16179],{"id":16176},"mypy-встановлення-та-базове-використання",[3398,16178,14158],{}," — встановлення та базове використання",[3554,16181,16183],{"className":11048,"code":16182,"language":11050,"meta":3559,"style":3559},"# Встановлення\nuv add --dev mypy\n# або\npip install mypy\n\n# Запуск для файлу\nmypy main.py\n\n# Запуск для всього проекту\nmypy .\n\n# Перевірка конкретного пакету\nmypy my_package\u002F\n",[3398,16184,16185,16190,16200,16205,16213,16217,16222,16228,16232,16237,16243,16247,16252],{"__ignoreMap":3559},[3563,16186,16187],{"class":3565,"line":3566},[3563,16188,16189],{"class":3569},"# Встановлення\n",[3563,16191,16192,16194,16196,16198],{"class":3565,"line":3573},[3563,16193,11642],{"class":3606},[3563,16195,3607],{"class":3645},[3563,16197,12189],{"class":3602},[3563,16199,12201],{"class":3645},[3563,16201,16202],{"class":3565,"line":3580},[3563,16203,16204],{"class":3569},"# або\n",[3563,16206,16207,16209,16211],{"class":3565,"line":3594},[3563,16208,6155],{"class":3606},[3563,16210,11285],{"class":3645},[3563,16212,12201],{"class":3645},[3563,16214,16215],{"class":3565,"line":3599},[3563,16216,3577],{"emptyLinePlaceholder":3576},[3563,16218,16219],{"class":3565,"line":3642},[3563,16220,16221],{"class":3569},"# Запуск для файлу\n",[3563,16223,16224,16226],{"class":3565,"line":3649},[3563,16225,14158],{"class":3606},[3563,16227,12498],{"class":3645},[3563,16229,16230],{"class":3565,"line":3659},[3563,16231,3577],{"emptyLinePlaceholder":3576},[3563,16233,16234],{"class":3565,"line":3664},[3563,16235,16236],{"class":3569},"# Запуск для всього проекту\n",[3563,16238,16239,16241],{"class":3565,"line":3694},[3563,16240,14158],{"class":3606},[3563,16242,12563],{"class":3645},[3563,16244,16245],{"class":3565,"line":3700},[3563,16246,3577],{"emptyLinePlaceholder":3576},[3563,16248,16249],{"class":3565,"line":3708},[3563,16250,16251],{"class":3569},"# Перевірка конкретного пакету\n",[3563,16253,16254,16256],{"class":3565,"line":3713},[3563,16255,14158],{"class":3606},[3563,16257,16258],{"class":3645}," my_package\u002F\n",[4032,16260,16262,16271,16290,16303,16319],{"title":16261},"mypy — знаходження помилок типів",[4036,16263,16265,4044,16268],{"className":16264},[3565],[3563,16266,4043],{"className":16267},[4042],[3406,16269,16270],{},"mypy main.py",[4036,16272,16274,16275,16279,16280,16284,16285,16289],{"className":16273},[3565],"main.py:",[3563,16276,16278],{"className":16277},[5716],"12",": error: Argument 1 to \"add\" has incompatible type ",[3563,16281,16283],{"className":16282},[6748],"\"str\"","; expected ",[3563,16286,16288],{"className":16287},[4054],"\"int\"","  [arg-type]",[4036,16291,16274,16293,16297,16298,16302],{"className":16292},[3565],[3563,16294,16296],{"className":16295},[5716],"18",": error: Item ",[3563,16299,16301],{"className":16300},[6748],"\"None\""," of \"Optional[str]\" has no attribute \"upper\"  [union-attr]",[4036,16304,16274,16306,16310,16311,16314,16315,16318],{"className":16305},[3565],[3563,16307,16309],{"className":16308},[5716],"25",": error: Return type declared as ",[3563,16312,16288],{"className":16313},[4054],", actual return type ",[3563,16316,16283],{"className":16317},[6748],"  [return-value]",[4036,16320,16322,16323,16327],{"className":16321},[3565],"Found ",[3563,16324,16326],{"className":16325},[6748],"3 errors"," in 1 file (checked 1 source file)",[4287,16329,16331,16332,8445,16334],{"id":16330},"конфігурація-mypy-у-pyprojecttoml","Конфігурація ",[3398,16333,14158],{},[3398,16335,11632],{},[3554,16337,16339],{"className":12036,"code":16338,"language":12038,"meta":3559,"style":3559},"[tool.mypy]\npython_version = \"3.12\"\nstrict = true              # найсуворіший режим — рекомендовано для нових проектів\n\n# Що перевіряти\ncheck_untyped_defs = true  # перевіряти навіть нетиповані функції\ndisallow_untyped_defs = true  # вимагати анотацій для всіх функцій\ndisallow_any_generics = true  # заборонити голі Generic (list замість list[str])\nwarn_return_any = true     # попереджати про return Any\n\n# Що ігнорувати\nignore_missing_imports = true  # якщо бібліотека не має стабів\n\n# Виключення конкретних модулів\n[[tool.mypy.overrides]]\nmodule = [\"tests.*\"]\ndisallow_untyped_defs = false  # у тестах дозволяємо без анотацій\n",[3398,16340,16341,16346,16356,16369,16373,16378,16390,16402,16414,16426,16430,16435,16447,16451,16456,16461,16472],{"__ignoreMap":3559},[3563,16342,16343],{"class":3565,"line":3566},[3563,16344,16345],{"class":3583},"[tool.mypy]\n",[3563,16347,16348,16351,16353],{"class":3565,"line":3573},[3563,16349,16350],{"class":3613},"python_version",[3563,16352,8871],{"class":3583},[3563,16354,16355],{"class":3645},"\"3.12\"\n",[3563,16357,16358,16361,16363,16366],{"class":3565,"line":3580},[3563,16359,16360],{"class":3613},"strict",[3563,16362,8871],{"class":3583},[3563,16364,16365],{"class":3602},"true",[3563,16367,16368],{"class":3569},"              # найсуворіший режим — рекомендовано для нових проектів\n",[3563,16370,16371],{"class":3565,"line":3594},[3563,16372,3577],{"emptyLinePlaceholder":3576},[3563,16374,16375],{"class":3565,"line":3599},[3563,16376,16377],{"class":3569},"# Що перевіряти\n",[3563,16379,16380,16383,16385,16387],{"class":3565,"line":3642},[3563,16381,16382],{"class":3613},"check_untyped_defs",[3563,16384,8871],{"class":3583},[3563,16386,16365],{"class":3602},[3563,16388,16389],{"class":3569},"  # перевіряти навіть нетиповані функції\n",[3563,16391,16392,16395,16397,16399],{"class":3565,"line":3649},[3563,16393,16394],{"class":3613},"disallow_untyped_defs",[3563,16396,8871],{"class":3583},[3563,16398,16365],{"class":3602},[3563,16400,16401],{"class":3569},"  # вимагати анотацій для всіх функцій\n",[3563,16403,16404,16407,16409,16411],{"class":3565,"line":3659},[3563,16405,16406],{"class":3613},"disallow_any_generics",[3563,16408,8871],{"class":3583},[3563,16410,16365],{"class":3602},[3563,16412,16413],{"class":3569},"  # заборонити голі Generic (list замість list[str])\n",[3563,16415,16416,16419,16421,16423],{"class":3565,"line":3664},[3563,16417,16418],{"class":3613},"warn_return_any",[3563,16420,8871],{"class":3583},[3563,16422,16365],{"class":3602},[3563,16424,16425],{"class":3569},"     # попереджати про return Any\n",[3563,16427,16428],{"class":3565,"line":3694},[3563,16429,3577],{"emptyLinePlaceholder":3576},[3563,16431,16432],{"class":3565,"line":3700},[3563,16433,16434],{"class":3569},"# Що ігнорувати\n",[3563,16436,16437,16440,16442,16444],{"class":3565,"line":3708},[3563,16438,16439],{"class":3613},"ignore_missing_imports",[3563,16441,8871],{"class":3583},[3563,16443,16365],{"class":3602},[3563,16445,16446],{"class":3569},"  # якщо бібліотека не має стабів\n",[3563,16448,16449],{"class":3565,"line":3713},[3563,16450,3577],{"emptyLinePlaceholder":3576},[3563,16452,16453],{"class":3565,"line":3743},[3563,16454,16455],{"class":3569},"# Виключення конкретних модулів\n",[3563,16457,16458],{"class":3565,"line":3749},[3563,16459,16460],{"class":3583},"[[tool.mypy.overrides]]\n",[3563,16462,16463,16465,16467,16470],{"class":3565,"line":3757},[3563,16464,3530],{"class":3613},[3563,16466,8890],{"class":3583},[3563,16468,16469],{"class":3645},"\"tests.*\"",[3563,16471,6347],{"class":3583},[3563,16473,16474,16476,16478,16481],{"class":3565,"line":3762},[3563,16475,16394],{"class":3613},[3563,16477,8871],{"class":3583},[3563,16479,16480],{"class":3602},"false",[3563,16482,16483],{"class":3569},"  # у тестах дозволяємо без анотацій\n",[4287,16485,16487],{"id":16486},"практичний-приклад-типовані-структури-даних","Практичний приклад: типовані структури даних",[3554,16489,16491],{"className":3556,"code":16490,"language":3558,"meta":3559,"style":3559},"from typing import Optional, Union\nfrom collections.abc import Sequence\n\n# TypedDict — словник зі строгою структурою\nfrom typing import TypedDict\n\nclass Address(TypedDict):\n    street: str\n    city: str\n    postal_code: str\n\nclass UserProfile(TypedDict, total=False):  # total=False — всі поля необов'язкові\n    bio: str\n    avatar_url: str\n\nclass User(TypedDict):\n    id: int\n    name: str\n    email: str\n    address: Address\n    profile: UserProfile  # вкладений TypedDict\n\n# Функція з повними анотаціями\ndef find_users_by_city(\n    users: Sequence[User],\n    city: str,\n    limit: Optional[int] = None,\n) -> list[User]:\n    \"\"\"Знаходить користувачів із зазначеного міста.\"\"\"\n    result = [u for u in users if u[\"address\"][\"city\"] == city]\n    if limit is not None:\n        result = result[:limit]\n    return result\n\n# mypy перевірить:\n# - що users є Sequence[User]\n# - що city є str\n# - що limit є Optional[int] (може бути None)\n# - що функція повертає list[User]\n",[3398,16492,16493,16504,16516,16520,16525,16535,16539,16552,16559,16566,16573,16577,16603,16610,16617,16621,16633,16642,16648,16655,16660,16668,16672,16677,16687,16695,16706,16723,16728,16733,16765,16781,16786,16793,16797,16802,16807,16812,16817],{"__ignoreMap":3559},[3563,16494,16495,16497,16499,16501],{"class":3565,"line":3566},[3563,16496,4907],{"class":3652},[3563,16498,16092],{"class":3583},[3563,16500,3905],{"class":3652},[3563,16502,16503],{"class":3583}," Optional, Union\n",[3563,16505,16506,16508,16511,16513],{"class":3565,"line":3573},[3563,16507,4907],{"class":3652},[3563,16509,16510],{"class":3583}," collections.abc ",[3563,16512,3905],{"class":3652},[3563,16514,16515],{"class":3583}," Sequence\n",[3563,16517,16518],{"class":3565,"line":3580},[3563,16519,3577],{"emptyLinePlaceholder":3576},[3563,16521,16522],{"class":3565,"line":3594},[3563,16523,16524],{"class":3569},"# TypedDict — словник зі строгою структурою\n",[3563,16526,16527,16529,16531,16533],{"class":3565,"line":3599},[3563,16528,4907],{"class":3652},[3563,16530,16092],{"class":3583},[3563,16532,3905],{"class":3652},[3563,16534,16097],{"class":3583},[3563,16536,16537],{"class":3565,"line":3642},[3563,16538,3577],{"emptyLinePlaceholder":3576},[3563,16540,16541,16543,16546,16548,16550],{"class":3565,"line":3649},[3563,16542,16106],{"class":3602},[3563,16544,16545],{"class":3620}," Address",[3563,16547,3610],{"class":3583},[3563,16549,16114],{"class":3620},[3563,16551,7337],{"class":3583},[3563,16553,16554,16557],{"class":3565,"line":3659},[3563,16555,16556],{"class":3583},"    street: ",[3563,16558,16124],{"class":3620},[3563,16560,16561,16564],{"class":3565,"line":3664},[3563,16562,16563],{"class":3583},"    city: ",[3563,16565,16124],{"class":3620},[3563,16567,16568,16571],{"class":3565,"line":3694},[3563,16569,16570],{"class":3583},"    postal_code: ",[3563,16572,16124],{"class":3620},[3563,16574,16575],{"class":3565,"line":3700},[3563,16576,3577],{"emptyLinePlaceholder":3576},[3563,16578,16579,16581,16584,16586,16588,16590,16593,16595,16597,16600],{"class":3565,"line":3708},[3563,16580,16106],{"class":3602},[3563,16582,16583],{"class":3620}," UserProfile",[3563,16585,3610],{"class":3583},[3563,16587,16114],{"class":3620},[3563,16589,3624],{"class":3583},[3563,16591,16592],{"class":3613},"total",[3563,16594,7810],{"class":3583},[3563,16596,6749],{"class":3602},[3563,16598,16599],{"class":3583},"):  ",[3563,16601,16602],{"class":3569},"# total=False — всі поля необов'язкові\n",[3563,16604,16605,16608],{"class":3565,"line":3713},[3563,16606,16607],{"class":3583},"    bio: ",[3563,16609,16124],{"class":3620},[3563,16611,16612,16615],{"class":3565,"line":3743},[3563,16613,16614],{"class":3583},"    avatar_url: ",[3563,16616,16124],{"class":3620},[3563,16618,16619],{"class":3565,"line":3749},[3563,16620,3577],{"emptyLinePlaceholder":3576},[3563,16622,16623,16625,16627,16629,16631],{"class":3565,"line":3757},[3563,16624,16106],{"class":3602},[3563,16626,16109],{"class":3620},[3563,16628,3610],{"class":3583},[3563,16630,16114],{"class":3620},[3563,16632,7337],{"class":3583},[3563,16634,16635,16638,16640],{"class":3565,"line":3762},[3563,16636,16637],{"class":3606},"    id",[3563,16639,3617],{"class":3583},[3563,16641,16132],{"class":3620},[3563,16643,16644,16646],{"class":3565,"line":3785},[3563,16645,16121],{"class":3583},[3563,16647,16124],{"class":3620},[3563,16649,16650,16653],{"class":3565,"line":3791},[3563,16651,16652],{"class":3583},"    email: ",[3563,16654,16124],{"class":3620},[3563,16656,16657],{"class":3565,"line":3802},[3563,16658,16659],{"class":3583},"    address: Address\n",[3563,16661,16662,16665],{"class":3565,"line":3807},[3563,16663,16664],{"class":3583},"    profile: UserProfile  ",[3563,16666,16667],{"class":3569},"# вкладений TypedDict\n",[3563,16669,16670],{"class":3565,"line":3828},[3563,16671,3577],{"emptyLinePlaceholder":3576},[3563,16673,16674],{"class":3565,"line":3834},[3563,16675,16676],{"class":3569},"# Функція з повними анотаціями\n",[3563,16678,16679,16681,16684],{"class":3565,"line":3840},[3563,16680,3603],{"class":3602},[3563,16682,16683],{"class":3606}," find_users_by_city",[3563,16685,16686],{"class":3583},"(\n",[3563,16688,16689,16692],{"class":3565,"line":3846},[3563,16690,16691],{"class":3613},"    users",[3563,16693,16694],{"class":3583},": Sequence[User],\n",[3563,16696,16697,16700,16702,16704],{"class":3565,"line":3851},[3563,16698,16699],{"class":3613},"    city",[3563,16701,3617],{"class":3583},[3563,16703,4145],{"class":3620},[3563,16705,12414],{"class":3583},[3563,16707,16708,16711,16714,16716,16719,16721],{"class":3565,"line":5463},[3563,16709,16710],{"class":3613},"    limit",[3563,16712,16713],{"class":3583},": Optional[",[3563,16715,3867],{"class":3620},[3563,16717,16718],{"class":3583},"] = ",[3563,16720,6862],{"class":3602},[3563,16722,12414],{"class":3583},[3563,16724,16725],{"class":3565,"line":5468},[3563,16726,16727],{"class":3583},") -> list[User]:\n",[3563,16729,16730],{"class":3565,"line":5474},[3563,16731,16732],{"class":3645},"    \"\"\"Знаходить користувачів із зазначеного міста.\"\"\"\n",[3563,16734,16735,16738,16740,16743,16745,16748,16750,16753,16756,16759,16762],{"class":3565,"line":5480},[3563,16736,16737],{"class":3583},"    result = [u ",[3563,16739,3877],{"class":3652},[3563,16741,16742],{"class":3583}," u ",[3563,16744,3883],{"class":3652},[3563,16746,16747],{"class":3583}," users ",[3563,16749,7464],{"class":3652},[3563,16751,16752],{"class":3583}," u[",[3563,16754,16755],{"class":3645},"\"address\"",[3563,16757,16758],{"class":3583},"][",[3563,16760,16761],{"class":3645},"\"city\"",[3563,16763,16764],{"class":3583},"] == city]\n",[3563,16766,16767,16769,16772,16774,16777,16779],{"class":3565,"line":5486},[3563,16768,7854],{"class":3652},[3563,16770,16771],{"class":3583}," limit ",[3563,16773,6366],{"class":3602},[3563,16775,16776],{"class":3602}," not",[3563,16778,9307],{"class":3602},[3563,16780,3639],{"class":3583},[3563,16782,16783],{"class":3565,"line":5492},[3563,16784,16785],{"class":3583},"        result = result[:limit]\n",[3563,16787,16788,16790],{"class":3565,"line":5498},[3563,16789,3653],{"class":3652},[3563,16791,16792],{"class":3583}," result\n",[3563,16794,16795],{"class":3565,"line":5504},[3563,16796,3577],{"emptyLinePlaceholder":3576},[3563,16798,16799],{"class":3565,"line":5509},[3563,16800,16801],{"class":3569},"# mypy перевірить:\n",[3563,16803,16804],{"class":3565,"line":5514},[3563,16805,16806],{"class":3569},"# - що users є Sequence[User]\n",[3563,16808,16809],{"class":3565,"line":5520},[3563,16810,16811],{"class":3569},"# - що city є str\n",[3563,16813,16814],{"class":3565,"line":5526},[3563,16815,16816],{"class":3569},"# - що limit є Optional[int] (може бути None)\n",[3563,16818,16819],{"class":3565,"line":5532},[3563,16820,16821],{"class":3569},"# - що функція повертає list[User]\n",[4287,16823,16825,16827],{"id":16824},"pyright-швидший-альтернативний-аналізатор",[3398,16826,15996],{}," — швидший альтернативний аналізатор",[3554,16829,16831],{"className":11048,"code":16830,"language":11050,"meta":3559,"style":3559},"# Встановлення через uv\nuv add --dev pyright\n# або глобально\nuvx pyright --version\n\n# Запуск\npyright .\npyright main.py --pythonversion 3.12\n",[3398,16832,16833,16838,16849,16854,16864,16868,16873,16879],{"__ignoreMap":3559},[3563,16834,16835],{"class":3565,"line":3566},[3563,16836,16837],{"class":3569},"# Встановлення через uv\n",[3563,16839,16840,16842,16844,16846],{"class":3565,"line":3573},[3563,16841,11642],{"class":3606},[3563,16843,3607],{"class":3645},[3563,16845,12189],{"class":3602},[3563,16847,16848],{"class":3645}," pyright\n",[3563,16850,16851],{"class":3565,"line":3580},[3563,16852,16853],{"class":3569},"# або глобально\n",[3563,16855,16856,16858,16861],{"class":3565,"line":3594},[3563,16857,12776],{"class":3606},[3563,16859,16860],{"class":3645}," pyright",[3563,16862,16863],{"class":3602}," --version\n",[3563,16865,16866],{"class":3565,"line":3599},[3563,16867,3577],{"emptyLinePlaceholder":3576},[3563,16869,16870],{"class":3565,"line":3642},[3563,16871,16872],{"class":3569},"# Запуск\n",[3563,16874,16875,16877],{"class":3565,"line":3649},[3563,16876,16030],{"class":3606},[3563,16878,12563],{"class":3645},[3563,16880,16881,16883,16885,16888],{"class":3565,"line":3659},[3563,16882,16030],{"class":3606},[3563,16884,13277],{"class":3645},[3563,16886,16887],{"class":3602}," --pythonversion",[3563,16889,12640],{"class":3587},[4032,16891,16893,16902,16906,16910,16913,16921,16946,16973,16976,16984],{"title":16892},"pyright — аналіз типів",[4036,16894,16896,4044,16899],{"className":16895},[3565],[3563,16897,4043],{"className":16898},[4042],[3406,16900,16901],{},"pyright .",[4036,16903,16905],{"className":16904},[3565],"Loading configuration file at \u002FUsers\u002Fuser\u002Fmy-project\u002Fpyrightconfig.json",[4036,16907,16909],{"className":16908},[3565],"pyright 1.1.391",[4036,16911],{"className":16912},[3565],[4036,16914,16916,16917],{"className":16915},[3565],"\u002F",[3563,16918,16920],{"className":16919},[4071],"my_project\u002Fservice.py",[4036,16922,16924,16925,4297,16928,4297,16932,16936,16937,16941,16942,16945],{"className":16923},[3565],"  \u002F",[3563,16926,16920],{"className":16927},[4071],[3563,16929,16931],{"className":16930},[5716],"34",[3563,16933,16935],{"className":16934},[5716],"16"," - error: Expression of type ",[3563,16938,16940],{"className":16939},[6748],"\"str | None\""," cannot be assigned to declared type ",[3563,16943,16283],{"className":16944},[4054]," (reportAssignmentType)",[4036,16947,16924,16949,4297,16952,4297,16956,16960,16961,16964,16965,16968,16969,16972],{"className":16948},[3565],[3563,16950,16920],{"className":16951},[4071],[3563,16953,16955],{"className":16954},[5716],"51",[3563,16957,16959],{"className":16958},[5716],"9"," - error: Argument of type ",[3563,16962,16288],{"className":16963},[6748]," cannot be assigned to parameter ",[3563,16966,8985],{"className":16967},[4054]," of type ",[3563,16970,16283],{"className":16971},[6748]," (reportArgumentType)",[4036,16974],{"className":16975},[3565],[4036,16977,16979,16983],{"className":16978},[3565],[3563,16980,16982],{"className":16981},[4071],"2 errors",", 0 warnings, 0 informations",[4036,16985,16987,16988],{"className":16986},[3565],"Completed in ",[3563,16989,16991],{"className":16990},[4054],"0.43s",[4287,16993,16995,16996],{"id":16994},"конфігурація-pyright-pyrightconfigjson","Конфігурація Pyright — ",[3398,16997,16998],{},"pyrightconfig.json",[3554,17000,17003],{"className":17001,"code":17002,"language":5851,"meta":3559,"style":3559},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\n    \"pythonVersion\": \"3.12\",\n    \"venvPath\": \".\",\n    \"venv\": \".venv\",\n    \"typeCheckingMode\": \"strict\",\n    \"include\": [\"src\", \"tests\"],\n    \"exclude\": [\"**\u002F__pycache__\"],\n    \"reportMissingImports\": true,\n    \"reportMissingTypeStubs\": false,\n    \"reportUnknownVariableType\": false\n}\n",[3398,17004,17005,17010,17023,17035,17047,17059,17078,17090,17101,17112,17122],{"__ignoreMap":3559},[3563,17006,17007],{"class":3565,"line":3566},[3563,17008,17009],{"class":3583},"{\n",[3563,17011,17012,17016,17018,17021],{"class":3565,"line":3573},[3563,17013,17015],{"class":17014},"sLwNe","    \"pythonVersion\"",[3563,17017,3617],{"class":3583},[3563,17019,17020],{"class":3645},"\"3.12\"",[3563,17022,12414],{"class":3583},[3563,17024,17025,17028,17030,17033],{"class":3565,"line":3580},[3563,17026,17027],{"class":17014},"    \"venvPath\"",[3563,17029,3617],{"class":3583},[3563,17031,17032],{"class":3645},"\".\"",[3563,17034,12414],{"class":3583},[3563,17036,17037,17040,17042,17045],{"class":3565,"line":3594},[3563,17038,17039],{"class":17014},"    \"venv\"",[3563,17041,3617],{"class":3583},[3563,17043,17044],{"class":3645},"\".venv\"",[3563,17046,12414],{"class":3583},[3563,17048,17049,17052,17054,17057],{"class":3565,"line":3599},[3563,17050,17051],{"class":17014},"    \"typeCheckingMode\"",[3563,17053,3617],{"class":3583},[3563,17055,17056],{"class":3645},"\"strict\"",[3563,17058,12414],{"class":3583},[3563,17060,17061,17064,17067,17070,17072,17075],{"class":3565,"line":3642},[3563,17062,17063],{"class":17014},"    \"include\"",[3563,17065,17066],{"class":3583},": [",[3563,17068,17069],{"class":3645},"\"src\"",[3563,17071,3624],{"class":3583},[3563,17073,17074],{"class":3645},"\"tests\"",[3563,17076,17077],{"class":3583},"],\n",[3563,17079,17080,17083,17085,17088],{"class":3565,"line":3649},[3563,17081,17082],{"class":17014},"    \"exclude\"",[3563,17084,17066],{"class":3583},[3563,17086,17087],{"class":3645},"\"**\u002F__pycache__\"",[3563,17089,17077],{"class":3583},[3563,17091,17092,17095,17097,17099],{"class":3565,"line":3659},[3563,17093,17094],{"class":17014},"    \"reportMissingImports\"",[3563,17096,3617],{"class":3583},[3563,17098,16365],{"class":3602},[3563,17100,12414],{"class":3583},[3563,17102,17103,17106,17108,17110],{"class":3565,"line":3664},[3563,17104,17105],{"class":17014},"    \"reportMissingTypeStubs\"",[3563,17107,3617],{"class":3583},[3563,17109,16480],{"class":3602},[3563,17111,12414],{"class":3583},[3563,17113,17114,17117,17119],{"class":3565,"line":3694},[3563,17115,17116],{"class":17014},"    \"reportUnknownVariableType\"",[3563,17118,3617],{"class":3583},[3563,17120,17121],{"class":3602},"false\n",[3563,17123,17124],{"class":3565,"line":3700},[3563,17125,4431],{"class":3583},[3394,17127,17128,17129,4297],{},"Або у ",[3398,17130,11632],{},[3554,17132,17134],{"className":12036,"code":17133,"language":12038,"meta":3559,"style":3559},"[tool.pyright]\npythonVersion = \"3.12\"\nvenvPath = \".\"\nvenv = \".venv\"\ntypeCheckingMode = \"strict\"\ninclude = [\"src\"]\nexclude = [\"**\u002F__pycache__\"]\n",[3398,17135,17136,17141,17150,17160,17169,17179,17189],{"__ignoreMap":3559},[3563,17137,17138],{"class":3565,"line":3566},[3563,17139,17140],{"class":3583},"[tool.pyright]\n",[3563,17142,17143,17146,17148],{"class":3565,"line":3573},[3563,17144,17145],{"class":3613},"pythonVersion",[3563,17147,8871],{"class":3583},[3563,17149,16355],{"class":3645},[3563,17151,17152,17155,17157],{"class":3565,"line":3580},[3563,17153,17154],{"class":3613},"venvPath",[3563,17156,8871],{"class":3583},[3563,17158,17159],{"class":3645},"\".\"\n",[3563,17161,17162,17164,17166],{"class":3565,"line":3594},[3563,17163,10824],{"class":3613},[3563,17165,8871],{"class":3583},[3563,17167,17168],{"class":3645},"\".venv\"\n",[3563,17170,17171,17174,17176],{"class":3565,"line":3599},[3563,17172,17173],{"class":3613},"typeCheckingMode",[3563,17175,8871],{"class":3583},[3563,17177,17178],{"class":3645},"\"strict\"\n",[3563,17180,17181,17183,17185,17187],{"class":3565,"line":3642},[3563,17182,14022],{"class":3613},[3563,17184,8890],{"class":3583},[3563,17186,17069],{"class":3645},[3563,17188,6347],{"class":3583},[3563,17190,17191,17194,17196,17198],{"class":3565,"line":3649},[3563,17192,17193],{"class":3613},"exclude",[3563,17195,8890],{"class":3583},[3563,17197,17087],{"class":3645},[3563,17199,6347],{"class":3583},[4287,17201,17203],{"id":17202},"порівняння-mypy-vs-pyright","Порівняння mypy vs Pyright",[8132,17205,17206,17217],{},[8135,17207,17208],{},[8138,17209,17210,17213,17215],{},[8141,17211,17212],{},"Характеристика",[8141,17214,14158],{},[8141,17216,15996],{},[8152,17218,17219,17230,17243,17255,17268,17280,17293,17306],{},[8138,17220,17221,17226,17228],{},[8157,17222,17223],{},[3406,17224,17225],{},"Мова реалізації",[8157,17227,2548],{},[8157,17229,2325],{},[8138,17231,17232,17237,17240],{},[8157,17233,17234],{},[3406,17235,17236],{},"Швидкість",[8157,17238,17239],{},"⚠️ Повільніший на великих проектах",[8157,17241,17242],{},"⚡ Значно швидший, інкрементальний",[8138,17244,17245,17250,17253],{},[8157,17246,17247],{},[3406,17248,17249],{},"Строгість",[8157,17251,17252],{},"✅ Налаштовувана",[8157,17254,17252],{},[8138,17256,17257,17262,17265],{},[8157,17258,17259],{},[3406,17260,17261],{},"IDE-інтеграція",[8157,17263,17264],{},"PyCharm, VSCode (mypy extension)",[8157,17266,17267],{},"VSCode (Pylance базується на Pyright)",[8138,17269,17270,17275,17278],{},[8157,17271,17272],{},[3406,17273,17274],{},"Підтримка стандартів",[8157,17276,17277],{},"✅ PEP 484, 526, 544...",[8157,17279,17277],{},[8138,17281,17282,17287,17290],{},[8157,17283,17284],{},[3406,17285,17286],{},"Plugins",[8157,17288,17289],{},"✅ Є (Django, SQLAlchemy)",[8157,17291,17292],{},"⚠️ Менше plugins",[8138,17294,17295,17300,17303],{},[8157,17296,17297],{},[3406,17298,17299],{},"CI\u002FCD",[8157,17301,17302],{},"✅ Стандарт де-факто",[8157,17304,17305],{},"✅ Зростає",[8138,17307,17308,17313,17316],{},[8157,17309,17310],{},[3406,17311,17312],{},"Рекомендація",[8157,17314,17315],{},"Зрілі проекти, Django, MLops",[8157,17317,17318],{},"FastAPI, нові проекти, VSCode-workflow",[10286,17320,17321,17323,17324,17326,17327,3624,17330,4354],{},[3406,17322,2609],{}," офіційно рекомендує Pyright (через Pylance у VSCode). ",[3406,17325,5879],{}," та більшість MLops-інструментів — mypy з відповідними plugin-ами (",[3398,17328,17329],{},"django-stubs",[3398,17331,17332],{},"sqlalchemy-stubs",[4287,17334,17336,17337],{"id":17335},"інтеграція-у-workflow-з-uv","Інтеграція у workflow з ",[3398,17338,11642],{},[3554,17340,17342],{"className":11048,"code":17341,"language":11050,"meta":3559,"style":3559},"# Додавання аналізаторів у dev-залежності\nuv add --dev mypy pyright\n\n# Запуск у CI\u002FCD або pre-commit\nuv run mypy .\nuv run pyright .\n\n# Часто використовують разом з ruff (лінтер)\nuv add --dev ruff\nuv run ruff check .\nuv run ruff format .\n",[3398,17343,17344,17349,17361,17365,17370,17380,17390,17394,17399,17409,17421],{"__ignoreMap":3559},[3563,17345,17346],{"class":3565,"line":3566},[3563,17347,17348],{"class":3569},"# Додавання аналізаторів у dev-залежності\n",[3563,17350,17351,17353,17355,17357,17359],{"class":3565,"line":3573},[3563,17352,11642],{"class":3606},[3563,17354,3607],{"class":3645},[3563,17356,12189],{"class":3602},[3563,17358,13189],{"class":3645},[3563,17360,16848],{"class":3645},[3563,17362,17363],{"class":3565,"line":3580},[3563,17364,3577],{"emptyLinePlaceholder":3576},[3563,17366,17367],{"class":3565,"line":3594},[3563,17368,17369],{"class":3569},"# Запуск у CI\u002FCD або pre-commit\n",[3563,17371,17372,17374,17376,17378],{"class":3565,"line":3599},[3563,17373,11642],{"class":3606},[3563,17375,12493],{"class":3645},[3563,17377,13189],{"class":3645},[3563,17379,12563],{"class":3645},[3563,17381,17382,17384,17386,17388],{"class":3565,"line":3642},[3563,17383,11642],{"class":3606},[3563,17385,12493],{"class":3645},[3563,17387,16860],{"class":3645},[3563,17389,12563],{"class":3645},[3563,17391,17392],{"class":3565,"line":3649},[3563,17393,3577],{"emptyLinePlaceholder":3576},[3563,17395,17396],{"class":3565,"line":3659},[3563,17397,17398],{"class":3569},"# Часто використовують разом з ruff (лінтер)\n",[3563,17400,17401,17403,17405,17407],{"class":3565,"line":3664},[3563,17402,11642],{"class":3606},[3563,17404,3607],{"class":3645},[3563,17406,12189],{"class":3602},[3563,17408,12858],{"class":3645},[3563,17410,17411,17413,17415,17417,17419],{"class":3565,"line":3694},[3563,17412,11642],{"class":3606},[3563,17414,12493],{"class":3645},[3563,17416,12198],{"class":3645},[3563,17418,12560],{"class":3645},[3563,17420,12563],{"class":3645},[3563,17422,17423,17425,17427,17429,17432],{"class":3565,"line":3700},[3563,17424,11642],{"class":3606},[3563,17426,12493],{"class":3645},[3563,17428,12198],{"class":3645},[3563,17430,17431],{"class":3645}," format",[3563,17433,12563],{"class":3645},[4287,17435,17437,17439],{"id":17436},"pyprojecttoml-повна-конфігурація-типового-проекту",[3398,17438,11632],{}," — повна конфігурація типового проекту",[3554,17441,17443],{"className":12036,"code":17442,"language":12038,"meta":3559,"style":3559},"[project]\nname = \"my-service\"\nversion = \"0.1.0\"\nrequires-python = \">=3.12\"\ndependencies = [\"fastapi>=0.115\", \"sqlalchemy>=2.0\"]\n\n[dependency-groups]\ndev = [\"mypy>=1.13\", \"pyright>=1.1\", \"ruff>=0.8\", \"pytest>=8.0\"]\n\n[tool.mypy]\npython_version = \"3.12\"\nstrict = true\nignore_missing_imports = true\n\n[tool.pyright]\npythonVersion = \"3.12\"\ntypeCheckingMode = \"basic\"\nvenvPath = \".\"\nvenv = \".venv\"\n\n[tool.ruff]\nline-length = 88\ntarget-version = \"py312\"\n\n[tool.ruff.lint]\nselect = [\"E\", \"F\", \"I\", \"UP\"]\n",[3398,17444,17445,17449,17457,17465,17473,17489,17493,17497,17523,17527,17531,17539,17548,17556,17560,17564,17572,17581,17589,17597,17601,17606,17616,17626,17630,17635],{"__ignoreMap":3559},[3563,17446,17447],{"class":3565,"line":3566},[3563,17448,12050],{"class":3583},[3563,17450,17451,17453,17455],{"class":3565,"line":3573},[3563,17452,9494],{"class":3613},[3563,17454,8871],{"class":3583},[3563,17456,13974],{"class":3645},[3563,17458,17459,17461,17463],{"class":3565,"line":3580},[3563,17460,10900],{"class":3613},[3563,17462,8871],{"class":3583},[3563,17464,12068],{"class":3645},[3563,17466,17467,17469,17471],{"class":3565,"line":3594},[3563,17468,12093],{"class":3613},[3563,17470,8871],{"class":3583},[3563,17472,12098],{"class":3645},[3563,17474,17475,17477,17479,17482,17484,17487],{"class":3565,"line":3599},[3563,17476,12103],{"class":3613},[3563,17478,8890],{"class":3583},[3563,17480,17481],{"class":3645},"\"fastapi>=0.115\"",[3563,17483,3624],{"class":3583},[3563,17485,17486],{"class":3645},"\"sqlalchemy>=2.0\"",[3563,17488,6347],{"class":3583},[3563,17490,17491],{"class":3565,"line":3642},[3563,17492,3577],{"emptyLinePlaceholder":3576},[3563,17494,17495],{"class":3565,"line":3649},[3563,17496,12434],{"class":3583},[3563,17498,17499,17501,17503,17506,17508,17511,17513,17516,17518,17521],{"class":3565,"line":3659},[3563,17500,12439],{"class":3613},[3563,17502,8890],{"class":3583},[3563,17504,17505],{"class":3645},"\"mypy>=1.13\"",[3563,17507,3624],{"class":3583},[3563,17509,17510],{"class":3645},"\"pyright>=1.1\"",[3563,17512,3624],{"class":3583},[3563,17514,17515],{"class":3645},"\"ruff>=0.8\"",[3563,17517,3624],{"class":3583},[3563,17519,17520],{"class":3645},"\"pytest>=8.0\"",[3563,17522,6347],{"class":3583},[3563,17524,17525],{"class":3565,"line":3664},[3563,17526,3577],{"emptyLinePlaceholder":3576},[3563,17528,17529],{"class":3565,"line":3694},[3563,17530,16345],{"class":3583},[3563,17532,17533,17535,17537],{"class":3565,"line":3700},[3563,17534,16350],{"class":3613},[3563,17536,8871],{"class":3583},[3563,17538,16355],{"class":3645},[3563,17540,17541,17543,17545],{"class":3565,"line":3708},[3563,17542,16360],{"class":3613},[3563,17544,8871],{"class":3583},[3563,17546,17547],{"class":3602},"true\n",[3563,17549,17550,17552,17554],{"class":3565,"line":3713},[3563,17551,16439],{"class":3613},[3563,17553,8871],{"class":3583},[3563,17555,17547],{"class":3602},[3563,17557,17558],{"class":3565,"line":3743},[3563,17559,3577],{"emptyLinePlaceholder":3576},[3563,17561,17562],{"class":3565,"line":3749},[3563,17563,17140],{"class":3583},[3563,17565,17566,17568,17570],{"class":3565,"line":3757},[3563,17567,17145],{"class":3613},[3563,17569,8871],{"class":3583},[3563,17571,16355],{"class":3645},[3563,17573,17574,17576,17578],{"class":3565,"line":3762},[3563,17575,17173],{"class":3613},[3563,17577,8871],{"class":3583},[3563,17579,17580],{"class":3645},"\"basic\"\n",[3563,17582,17583,17585,17587],{"class":3565,"line":3785},[3563,17584,17154],{"class":3613},[3563,17586,8871],{"class":3583},[3563,17588,17159],{"class":3645},[3563,17590,17591,17593,17595],{"class":3565,"line":3791},[3563,17592,10824],{"class":3613},[3563,17594,8871],{"class":3583},[3563,17596,17168],{"class":3645},[3563,17598,17599],{"class":3565,"line":3802},[3563,17600,3577],{"emptyLinePlaceholder":3576},[3563,17602,17603],{"class":3565,"line":3807},[3563,17604,17605],{"class":3583},"[tool.ruff]\n",[3563,17607,17608,17611,17613],{"class":3565,"line":3828},[3563,17609,17610],{"class":3613},"line-length",[3563,17612,8871],{"class":3583},[3563,17614,17615],{"class":3587},"88\n",[3563,17617,17618,17621,17623],{"class":3565,"line":3834},[3563,17619,17620],{"class":3613},"target-version",[3563,17622,8871],{"class":3583},[3563,17624,17625],{"class":3645},"\"py312\"\n",[3563,17627,17628],{"class":3565,"line":3840},[3563,17629,3577],{"emptyLinePlaceholder":3576},[3563,17631,17632],{"class":3565,"line":3846},[3563,17633,17634],{"class":3583},"[tool.ruff.lint]\n",[3563,17636,17637,17640,17642,17645,17647,17650,17652,17655,17657,17660],{"class":3565,"line":3851},[3563,17638,17639],{"class":3613},"select",[3563,17641,8890],{"class":3583},[3563,17643,17644],{"class":3645},"\"E\"",[3563,17646,3624],{"class":3583},[3563,17648,17649],{"class":3645},"\"F\"",[3563,17651,3624],{"class":3583},[3563,17653,17654],{"class":3645},"\"I\"",[3563,17656,3624],{"class":3583},[3563,17658,17659],{"class":3645},"\"UP\"",[3563,17661,6347],{"class":3583},[3461,17663],{},[3468,17665,17667,17668,17670,17671,17673,17674,17673,17676],{"id":17666},"порівняльна-таблиця-venvpip-vs-uv-vs-poetry","Порівняльна таблиця: ",[3398,17669,10824],{},"+",[3398,17672,6155],{}," vs ",[3398,17675,11642],{},[3398,17677,11712],{},[8132,17679,17680,17701],{},[8135,17681,17682],{},[8138,17683,17684,17687,17693,17697],{},[8141,17685,17686],{},"Можливість",[8141,17688,17689,11649,17691],{},[3398,17690,10824],{},[3398,17692,6155],{},[8141,17694,17695],{},[3398,17696,11642],{},[8141,17698,17699],{},[3398,17700,11712],{},[8152,17702,17703,17719,17738,17752,17766,17784,17798,17814,17829],{},[8138,17704,17705,17710,17713,17716],{},[8157,17706,17707],{},[3406,17708,17709],{},"Швидкість встановлення",[8157,17711,17712],{},"🐢 Базова",[8157,17714,17715],{},"⚡ 10–100x швидше",[8157,17717,17718],{},"🐇 Швидша за pip",[8138,17720,17721,17726,17729,17734],{},[8157,17722,17723],{},[3406,17724,17725],{},"Lockfile",[8157,17727,17728],{},"❌ Немає (лише freeze)",[8157,17730,17731,17732],{},"✅ ",[3398,17733,11784],{},[8157,17735,17731,17736],{},[3398,17737,14682],{},[8138,17739,17740,17744,17746,17749],{},[8157,17741,17742],{},[3406,17743,12611],{},[8157,17745,15754],{},[8157,17747,17748],{},"✅ Вбудовано",[8157,17750,17751],{},"❌ Потрібен pyenv",[8138,17753,17754,17758,17760,17763],{},[8157,17755,17756],{},[3406,17757,13686],{},[8157,17759,15754],{},[8157,17761,17762],{},"✅ dev groups",[8157,17764,17765],{},"✅ dev\u002Ftest\u002Fdocs groups",[8138,17767,17768,17773,17776,17780],{},[8157,17769,17770],{},[3406,17771,17772],{},"Автоматичне середовище",[8157,17774,17775],{},"❌ Вручну",[8157,17777,17731,17778],{},[3398,17779,12475],{},[8157,17781,17731,17782],{},[3398,17783,14508],{},[8138,17785,17786,17790,17793,17796],{},[8157,17787,17788],{},[3406,17789,13694],{},[8157,17791,17792],{},"❌ Потрібен twine",[8157,17794,17795],{},"❌ Не підтримується",[8157,17797,17748],{},[8138,17799,17800,17805,17808,17811],{},[8157,17801,17802],{},[3406,17803,17804],{},"Сумісність зі стандартами",[8157,17806,17807],{},"✅ Стандарт",[8157,17809,17810],{},"✅ PEP 621",[8157,17812,17813],{},"⚠️ Частково PEP 621",[8138,17815,17816,17821,17824,17826],{},[8157,17817,17818],{},[3406,17819,17820],{},"Навчальна крива",[8157,17822,17823],{},"✅ Проста",[8157,17825,17823],{},[8157,17827,17828],{},"⚠️ Середня",[8138,17830,17831,17836,17838,17841],{},[8157,17832,17833],{},[3406,17834,17835],{},"Зрілість і поширеність",[8157,17837,17807],{},[8157,17839,17840],{},"🆕 Активно зростає",[8157,17842,17843],{},"✅ Широко у production",[3411,17845,17846,17851,17855],{},[3414,17847,17850],{"icon":17848,"title":17849},"i-heroicons-academic-cap","Обирайте venv + pip","Для навчання, простих скриптів, проектів де важлива максимальна сумісність зі стандартними інструментами. Це базовий рівень, який треба знати всім.",[3414,17852,17854],{"icon":11752,"title":17853},"Обирайте uv","Для нових проектів будь-якого розміру. Особливо — для CI\u002FCD, де швидкість встановлення залежностей критична. Найкращий вибір для 2024+ проектів.",[3414,17856,17859],{"icon":17857,"title":17858},"i-heroicons-book-open","Обирайте Poetry","Для бібліотек, що публікуються на PyPI, або для команд що вже використовують Poetry і мають налагоджений workflow. Відмінна підтримка у більшості IDE.",[3461,17861],{},[3389,17863,17865],{"id":17864},"частина-v-стандартна-бібліотека-батарейки-у-комплекті","Частина V: Стандартна бібліотека — «Батарейки у комплекті»",[3468,17867,17869],{"id":17868},"філософія-batteries-included","Філософія \"Batteries Included\"",[3394,17871,17872,17873,17876],{},"Одна з найсильніших сторін Python — філософія ",[3406,17874,17875],{},"\"batteries included\" (батарейки у комплекті)",". Це означає, що разом з інтерпретатором ви отримуєте величезний набір готових, оптимізованих та протестованих модулів стандартної бібліотеки. Вони покривають більшість повсякденних завдань розробника: від математичних обчислень до мережевої взаємодії та роботи з файловою системою.",[3394,17878,17879],{},"Використання стандартної бібліотеки гарантує:",[5138,17881,17882,17888,17894],{},[3508,17883,17884,17887],{},[3406,17885,17886],{},"Портативність",": ваш код працюватиме на будь-якому комп'ютері, де встановлено Python, без необхідності встановлювати сторонні залежності.",[3508,17889,17890,17893],{},[3406,17891,17892],{},"Стабільність",": ці модулі підтримуються та оновлюються ядром команди розробників Python.",[3508,17895,17896,17898],{},[3406,17897,17236],{},": багато критичних частин стандартної бібліотеки написані на мові C для максимальної продуктивності.",[3394,17900,17901],{},"Розглянемо ключові модулі, які формують основу розробки на Python.",[3461,17903],{},[3468,17905,17907,17908],{"id":17906},"математичні-обчислення-модуль-math","Математичні обчислення: модуль ",[3398,17909,17910],{},"math",[3394,17912,17913,17914,17916,17917,4354],{},"Модуль ",[3398,17915,17910],{}," надає доступ до математичних функцій та констант, визначених стандартом мови C. Він працює виключно з дійсними числами (для комплексних чисел існує окремий модуль ",[3398,17918,17919],{},"cmath",[4287,17921,17923],{"id":17922},"константи-та-округлення","Константи та округлення",[3554,17925,17927],{"className":3556,"code":17926,"language":3558,"meta":3559,"style":3559},"import math\n\n# Ключові константи\nprint(f\"pi: {math.pi}\")      # 3.141592653589793\nprint(f\"e: {math.e}\")        # 2.718281828459045\nprint(f\"inf: {math.inf}\")    # Позитивна нескінченність\nprint(f\"nan: {math.nan}\")    # Not a Number (не число)\n\n# Стратегії округлення\nvalue = 5.67\nprint(f\"Округлення вгору (ceil): {math.ceil(value)}\")      # 6\nprint(f\"Округлення вниз (floor): {math.floor(value)}\")     # 5\nprint(f\"Відкидання дробової частини (trunc): {math.trunc(value)}\")  # 5\n",[3398,17928,17929,17935,17939,17944,17970,17995,18021,18046,18050,18055,18063,18088,18114],{"__ignoreMap":3559},[3563,17930,17931,17933],{"class":3565,"line":3566},[3563,17932,3905],{"class":3652},[3563,17934,4502],{"class":3583},[3563,17936,17937],{"class":3565,"line":3573},[3563,17938,3577],{"emptyLinePlaceholder":3576},[3563,17940,17941],{"class":3565,"line":3580},[3563,17942,17943],{"class":3569},"# Ключові константи\n",[3563,17945,17946,17948,17950,17952,17955,17957,17960,17962,17964,17967],{"class":3565,"line":3594},[3563,17947,3955],{"class":3606},[3563,17949,3610],{"class":3583},[3563,17951,3960],{"class":3602},[3563,17953,17954],{"class":3645},"\"pi: ",[3563,17956,3966],{"class":3602},[3563,17958,17959],{"class":3583},"math.pi",[3563,17961,3972],{"class":3602},[3563,17963,3975],{"class":3645},[3563,17965,17966],{"class":3583},")      ",[3563,17968,17969],{"class":3569},"# 3.141592653589793\n",[3563,17971,17972,17974,17976,17978,17981,17983,17986,17988,17990,17992],{"class":3565,"line":3599},[3563,17973,3955],{"class":3606},[3563,17975,3610],{"class":3583},[3563,17977,3960],{"class":3602},[3563,17979,17980],{"class":3645},"\"e: ",[3563,17982,3966],{"class":3602},[3563,17984,17985],{"class":3583},"math.e",[3563,17987,3972],{"class":3602},[3563,17989,3975],{"class":3645},[3563,17991,6410],{"class":3583},[3563,17993,17994],{"class":3569},"# 2.718281828459045\n",[3563,17996,17997,17999,18001,18003,18006,18008,18011,18013,18015,18018],{"class":3565,"line":3642},[3563,17998,3955],{"class":3606},[3563,18000,3610],{"class":3583},[3563,18002,3960],{"class":3602},[3563,18004,18005],{"class":3645},"\"inf: ",[3563,18007,3966],{"class":3602},[3563,18009,18010],{"class":3583},"math.inf",[3563,18012,3972],{"class":3602},[3563,18014,3975],{"class":3645},[3563,18016,18017],{"class":3583},")    ",[3563,18019,18020],{"class":3569},"# Позитивна нескінченність\n",[3563,18022,18023,18025,18027,18029,18032,18034,18037,18039,18041,18043],{"class":3565,"line":3649},[3563,18024,3955],{"class":3606},[3563,18026,3610],{"class":3583},[3563,18028,3960],{"class":3602},[3563,18030,18031],{"class":3645},"\"nan: ",[3563,18033,3966],{"class":3602},[3563,18035,18036],{"class":3583},"math.nan",[3563,18038,3972],{"class":3602},[3563,18040,3975],{"class":3645},[3563,18042,18017],{"class":3583},[3563,18044,18045],{"class":3569},"# Not a Number (не число)\n",[3563,18047,18048],{"class":3565,"line":3659},[3563,18049,3577],{"emptyLinePlaceholder":3576},[3563,18051,18052],{"class":3565,"line":3664},[3563,18053,18054],{"class":3569},"# Стратегії округлення\n",[3563,18056,18057,18060],{"class":3565,"line":3694},[3563,18058,18059],{"class":3583},"value = ",[3563,18061,18062],{"class":3587},"5.67\n",[3563,18064,18065,18067,18069,18071,18074,18076,18079,18081,18083,18085],{"class":3565,"line":3700},[3563,18066,3955],{"class":3606},[3563,18068,3610],{"class":3583},[3563,18070,3960],{"class":3602},[3563,18072,18073],{"class":3645},"\"Округлення вгору (ceil): ",[3563,18075,3966],{"class":3602},[3563,18077,18078],{"class":3583},"math.ceil(value)",[3563,18080,3972],{"class":3602},[3563,18082,3975],{"class":3645},[3563,18084,17966],{"class":3583},[3563,18086,18087],{"class":3569},"# 6\n",[3563,18089,18090,18092,18094,18096,18099,18101,18104,18106,18108,18111],{"class":3565,"line":3708},[3563,18091,3955],{"class":3606},[3563,18093,3610],{"class":3583},[3563,18095,3960],{"class":3602},[3563,18097,18098],{"class":3645},"\"Округлення вниз (floor): ",[3563,18100,3966],{"class":3602},[3563,18102,18103],{"class":3583},"math.floor(value)",[3563,18105,3972],{"class":3602},[3563,18107,3975],{"class":3645},[3563,18109,18110],{"class":3583},")     ",[3563,18112,18113],{"class":3569},"# 5\n",[3563,18115,18116,18118,18120,18122,18125,18127,18130,18132,18134,18136],{"class":3565,"line":3713},[3563,18117,3955],{"class":3606},[3563,18119,3610],{"class":3583},[3563,18121,3960],{"class":3602},[3563,18123,18124],{"class":3645},"\"Відкидання дробової частини (trunc): ",[3563,18126,3966],{"class":3602},[3563,18128,18129],{"class":3583},"math.trunc(value)",[3563,18131,3972],{"class":3602},[3563,18133,3975],{"class":3645},[3563,18135,5128],{"class":3583},[3563,18137,18113],{"class":3569},[4287,18139,18141],{"id":18140},"степені-корені-та-логарифми","Степені, корені та логарифми",[3554,18143,18145],{"className":3556,"code":18144,"language":3558,"meta":3559,"style":3559},"# Квадратний корінь\nprint(math.sqrt(25))  # 5.0 (завжди повертає float)\n\n# Найбільший спільний дільник (НСД) та найменше спільне кратне (НСК)\nprint(math.gcd(48, 64))  # 16\nprint(math.lcm(48, 64))  # 192 (доступно в Python 3.9+)\n\n# Логарифми\nprint(math.log(math.e))  # 1.0 (натуральний логарифм)\nprint(math.log2(1024))   # 10.0\nprint(math.log10(1000))  # 3.0\n",[3398,18146,18147,18152,18167,18171,18176,18196,18214,18218,18223,18233,18248],{"__ignoreMap":3559},[3563,18148,18149],{"class":3565,"line":3566},[3563,18150,18151],{"class":3569},"# Квадратний корінь\n",[3563,18153,18154,18156,18159,18161,18164],{"class":3565,"line":3573},[3563,18155,3955],{"class":3606},[3563,18157,18158],{"class":3583},"(math.sqrt(",[3563,18160,16309],{"class":3587},[3563,18162,18163],{"class":3583},"))  ",[3563,18165,18166],{"class":3569},"# 5.0 (завжди повертає float)\n",[3563,18168,18169],{"class":3565,"line":3580},[3563,18170,3577],{"emptyLinePlaceholder":3576},[3563,18172,18173],{"class":3565,"line":3594},[3563,18174,18175],{"class":3569},"# Найбільший спільний дільник (НСД) та найменше спільне кратне (НСК)\n",[3563,18177,18178,18180,18183,18186,18188,18191,18193],{"class":3565,"line":3599},[3563,18179,3955],{"class":3606},[3563,18181,18182],{"class":3583},"(math.gcd(",[3563,18184,18185],{"class":3587},"48",[3563,18187,3624],{"class":3583},[3563,18189,18190],{"class":3587},"64",[3563,18192,18163],{"class":3583},[3563,18194,18195],{"class":3569},"# 16\n",[3563,18197,18198,18200,18203,18205,18207,18209,18211],{"class":3565,"line":3642},[3563,18199,3955],{"class":3606},[3563,18201,18202],{"class":3583},"(math.lcm(",[3563,18204,18185],{"class":3587},[3563,18206,3624],{"class":3583},[3563,18208,18190],{"class":3587},[3563,18210,18163],{"class":3583},[3563,18212,18213],{"class":3569},"# 192 (доступно в Python 3.9+)\n",[3563,18215,18216],{"class":3565,"line":3649},[3563,18217,3577],{"emptyLinePlaceholder":3576},[3563,18219,18220],{"class":3565,"line":3659},[3563,18221,18222],{"class":3569},"# Логарифми\n",[3563,18224,18225,18227,18230],{"class":3565,"line":3664},[3563,18226,3955],{"class":3606},[3563,18228,18229],{"class":3583},"(math.log(math.e))  ",[3563,18231,18232],{"class":3569},"# 1.0 (натуральний логарифм)\n",[3563,18234,18235,18237,18240,18243,18245],{"class":3565,"line":3694},[3563,18236,3955],{"class":3606},[3563,18238,18239],{"class":3583},"(math.log2(",[3563,18241,18242],{"class":3587},"1024",[3563,18244,7135],{"class":3583},[3563,18246,18247],{"class":3569},"# 10.0\n",[3563,18249,18250,18252,18255,18258,18260],{"class":3565,"line":3700},[3563,18251,3955],{"class":3606},[3563,18253,18254],{"class":3583},"(math.log10(",[3563,18256,18257],{"class":3587},"1000",[3563,18259,18163],{"class":3583},[3563,18261,18262],{"class":3569},"# 3.0\n",[11028,18264,18265,18266,18269,18270,18272,18273,18275,18276,18279,18280,18283,18284,18287,18288,18290,18291,18287,18294,4354],{},"Для звичайного округлення до найближчого цілого використовуйте вбудовану функцію ",[3398,18267,18268],{},"round()",", яка не потребує імпорту ",[3398,18271,17910],{},". Але пам'ятайте, що ",[3398,18274,18268],{}," у Python використовує ",[3406,18277,18278],{},"банківське округлення"," (округлює до найближчого парного числа при закінченні на ",[3398,18281,18282],{},".5",", наприклад ",[3398,18285,18286],{},"round(2.5)"," буде ",[3398,18289,4209],{},", а ",[3398,18292,18293],{},"round(3.5)",[3398,18295,18296],{},"4",[3461,18298],{},[3468,18300,18302,18303],{"id":18301},"псевдовипадковість-модуль-random","Псевдовипадковість: модуль ",[3398,18304,18305],{},"random",[3394,18307,17913,18308,18310,18311,18314,18315,18318,18319,4354],{},[3398,18309,18305],{}," генерує псевдовипадкові числа за допомогою алгоритму ",[3406,18312,18313],{},"Вихру Мерсенна (Mersenne Twister)",". Він підходить для моделювання, симуляцій та ігор, але ",[3406,18316,18317],{},"не є безпечним для криптографії"," (для безпечних токенів або паролів використовуйте модуль ",[3398,18320,18321],{},"secrets",[4287,18323,18325],{"id":18324},"генерація-значень","Генерація значень",[3554,18327,18329],{"className":3556,"code":18328,"language":3558,"meta":3559,"style":3559},"import random\n\n# Дійсне число від 0.0 до 1.0\nprint(f\"random(): {random.random()}\")\n\n# Ціле число в діапазоні [1, 10] включно\nprint(f\"randint(1, 10): {random.randint(1, 10)}\")\n\n# Дійсне число в діапазоні [1.5, 9.5]\nprint(f\"uniform(1.5, 9.5): {random.uniform(1.5, 9.5)}\")\n\n# Випадкове парне число від 0 до 100\nprint(f\"randrange(0, 101, 2): {random.randrange(0, 101, 2)}\")\n",[3398,18330,18331,18338,18342,18347,18369,18373,18378,18408,18412,18417,18449,18453,18458],{"__ignoreMap":3559},[3563,18332,18333,18335],{"class":3565,"line":3566},[3563,18334,3905],{"class":3652},[3563,18336,18337],{"class":3583}," random\n",[3563,18339,18340],{"class":3565,"line":3573},[3563,18341,3577],{"emptyLinePlaceholder":3576},[3563,18343,18344],{"class":3565,"line":3580},[3563,18345,18346],{"class":3569},"# Дійсне число від 0.0 до 1.0\n",[3563,18348,18349,18351,18353,18355,18358,18360,18363,18365,18367],{"class":3565,"line":3594},[3563,18350,3955],{"class":3606},[3563,18352,3610],{"class":3583},[3563,18354,3960],{"class":3602},[3563,18356,18357],{"class":3645},"\"random(): ",[3563,18359,3966],{"class":3602},[3563,18361,18362],{"class":3583},"random.random()",[3563,18364,3972],{"class":3602},[3563,18366,3975],{"class":3645},[3563,18368,3936],{"class":3583},[3563,18370,18371],{"class":3565,"line":3599},[3563,18372,3577],{"emptyLinePlaceholder":3576},[3563,18374,18375],{"class":3565,"line":3642},[3563,18376,18377],{"class":3569},"# Ціле число в діапазоні [1, 10] включно\n",[3563,18379,18380,18382,18384,18386,18389,18391,18394,18396,18398,18400,18402,18404,18406],{"class":3565,"line":3649},[3563,18381,3955],{"class":3606},[3563,18383,3610],{"class":3583},[3563,18385,3960],{"class":3602},[3563,18387,18388],{"class":3645},"\"randint(1, 10): ",[3563,18390,3966],{"class":3602},[3563,18392,18393],{"class":3583},"random.randint(",[3563,18395,5061],{"class":3587},[3563,18397,3624],{"class":3583},[3563,18399,3928],{"class":3587},[3563,18401,3518],{"class":3583},[3563,18403,3972],{"class":3602},[3563,18405,3975],{"class":3645},[3563,18407,3936],{"class":3583},[3563,18409,18410],{"class":3565,"line":3659},[3563,18411,3577],{"emptyLinePlaceholder":3576},[3563,18413,18414],{"class":3565,"line":3664},[3563,18415,18416],{"class":3569},"# Дійсне число в діапазоні [1.5, 9.5]\n",[3563,18418,18419,18421,18423,18425,18428,18430,18433,18436,18438,18441,18443,18445,18447],{"class":3565,"line":3694},[3563,18420,3955],{"class":3606},[3563,18422,3610],{"class":3583},[3563,18424,3960],{"class":3602},[3563,18426,18427],{"class":3645},"\"uniform(1.5, 9.5): ",[3563,18429,3966],{"class":3602},[3563,18431,18432],{"class":3583},"random.uniform(",[3563,18434,18435],{"class":3587},"1.5",[3563,18437,3624],{"class":3583},[3563,18439,18440],{"class":3587},"9.5",[3563,18442,3518],{"class":3583},[3563,18444,3972],{"class":3602},[3563,18446,3975],{"class":3645},[3563,18448,3936],{"class":3583},[3563,18450,18451],{"class":3565,"line":3700},[3563,18452,3577],{"emptyLinePlaceholder":3576},[3563,18454,18455],{"class":3565,"line":3708},[3563,18456,18457],{"class":3569},"# Випадкове парне число від 0 до 100\n",[3563,18459,18460,18462,18464,18466,18469,18471,18474,18476,18478,18481,18483,18485,18487,18489,18491],{"class":3565,"line":3713},[3563,18461,3955],{"class":3606},[3563,18463,3610],{"class":3583},[3563,18465,3960],{"class":3602},[3563,18467,18468],{"class":3645},"\"randrange(0, 101, 2): ",[3563,18470,3966],{"class":3602},[3563,18472,18473],{"class":3583},"random.randrange(",[3563,18475,5922],{"class":3587},[3563,18477,3624],{"class":3583},[3563,18479,18480],{"class":3587},"101",[3563,18482,3624],{"class":3583},[3563,18484,4209],{"class":3587},[3563,18486,3518],{"class":3583},[3563,18488,3972],{"class":3602},[3563,18490,3975],{"class":3645},[3563,18492,3936],{"class":3583},[4287,18494,18496],{"id":18495},"робота-з-послідовностями","Робота з послідовностями",[3554,18498,18500],{"className":3556,"code":18499,"language":3558,"meta":3559,"style":3559},"cards = [\"Туз\", \"Король\", \"Дама\", \"Валет\", \"10\"]\n\n# Вибір одного випадкового елемента\nprint(f\"Випадкова карта: {random.choice(cards)}\")\n\n# Вибір кількох унікальних елементів (без повторень)\nprint(f\"Роздача на двох: {random.sample(cards, 2)}\")\n\n# Перемішування списку на місці (модифікує оригінал!)\nrandom.shuffle(cards)\nprint(f\"Перемішана колода: {cards}\")\n",[3398,18501,18502,18532,18536,18541,18563,18567,18572,18598,18602,18607,18612],{"__ignoreMap":3559},[3563,18503,18504,18507,18510,18512,18515,18517,18520,18522,18525,18527,18530],{"class":3565,"line":3566},[3563,18505,18506],{"class":3583},"cards = [",[3563,18508,18509],{"class":3645},"\"Туз\"",[3563,18511,3624],{"class":3583},[3563,18513,18514],{"class":3645},"\"Король\"",[3563,18516,3624],{"class":3583},[3563,18518,18519],{"class":3645},"\"Дама\"",[3563,18521,3624],{"class":3583},[3563,18523,18524],{"class":3645},"\"Валет\"",[3563,18526,3624],{"class":3583},[3563,18528,18529],{"class":3645},"\"10\"",[3563,18531,6347],{"class":3583},[3563,18533,18534],{"class":3565,"line":3573},[3563,18535,3577],{"emptyLinePlaceholder":3576},[3563,18537,18538],{"class":3565,"line":3580},[3563,18539,18540],{"class":3569},"# Вибір одного випадкового елемента\n",[3563,18542,18543,18545,18547,18549,18552,18554,18557,18559,18561],{"class":3565,"line":3594},[3563,18544,3955],{"class":3606},[3563,18546,3610],{"class":3583},[3563,18548,3960],{"class":3602},[3563,18550,18551],{"class":3645},"\"Випадкова карта: ",[3563,18553,3966],{"class":3602},[3563,18555,18556],{"class":3583},"random.choice(cards)",[3563,18558,3972],{"class":3602},[3563,18560,3975],{"class":3645},[3563,18562,3936],{"class":3583},[3563,18564,18565],{"class":3565,"line":3599},[3563,18566,3577],{"emptyLinePlaceholder":3576},[3563,18568,18569],{"class":3565,"line":3642},[3563,18570,18571],{"class":3569},"# Вибір кількох унікальних елементів (без повторень)\n",[3563,18573,18574,18576,18578,18580,18583,18585,18588,18590,18592,18594,18596],{"class":3565,"line":3649},[3563,18575,3955],{"class":3606},[3563,18577,3610],{"class":3583},[3563,18579,3960],{"class":3602},[3563,18581,18582],{"class":3645},"\"Роздача на двох: ",[3563,18584,3966],{"class":3602},[3563,18586,18587],{"class":3583},"random.sample(cards, ",[3563,18589,4209],{"class":3587},[3563,18591,3518],{"class":3583},[3563,18593,3972],{"class":3602},[3563,18595,3975],{"class":3645},[3563,18597,3936],{"class":3583},[3563,18599,18600],{"class":3565,"line":3659},[3563,18601,3577],{"emptyLinePlaceholder":3576},[3563,18603,18604],{"class":3565,"line":3664},[3563,18605,18606],{"class":3569},"# Перемішування списку на місці (модифікує оригінал!)\n",[3563,18608,18609],{"class":3565,"line":3694},[3563,18610,18611],{"class":3583},"random.shuffle(cards)\n",[3563,18613,18614,18616,18618,18620,18623,18625,18628,18630,18632],{"class":3565,"line":3700},[3563,18615,3955],{"class":3606},[3563,18617,3610],{"class":3583},[3563,18619,3960],{"class":3602},[3563,18621,18622],{"class":3645},"\"Перемішана колода: ",[3563,18624,3966],{"class":3602},[3563,18626,18627],{"class":3583},"cards",[3563,18629,3972],{"class":3602},[3563,18631,3975],{"class":3645},[3563,18633,3936],{"class":3583},[4287,18635,18637,18638],{"id":18636},"концепція-відтворюваності-randomseed","Концепція відтворюваності: ",[3398,18639,18640],{},"random.seed()",[3394,18642,18643],{},"Алгоритм генерації є математичним, тому якщо задати початкову точку (seed), послідовність \"випадкових\" чисел буде абсолютно ідентичною при кожному запуску.",[3554,18645,18647],{"className":3556,"code":18646,"language":3558,"meta":3559,"style":3559},"random.seed(100)\nprint(random.randint(1, 100))  # Завжди виведе 19\nprint(random.randint(1, 100))  # Завжди виведе 59\n\nrandom.seed(100)  # Скидаємо в ту саму початкову точку\nprint(random.randint(1, 100))  # Знову 19!\n",[3398,18648,18649,18659,18677,18694,18698,18709],{"__ignoreMap":3559},[3563,18650,18651,18654,18657],{"class":3565,"line":3566},[3563,18652,18653],{"class":3583},"random.seed(",[3563,18655,18656],{"class":3587},"100",[3563,18658,3936],{"class":3583},[3563,18660,18661,18663,18666,18668,18670,18672,18674],{"class":3565,"line":3573},[3563,18662,3955],{"class":3606},[3563,18664,18665],{"class":3583},"(random.randint(",[3563,18667,5061],{"class":3587},[3563,18669,3624],{"class":3583},[3563,18671,18656],{"class":3587},[3563,18673,18163],{"class":3583},[3563,18675,18676],{"class":3569},"# Завжди виведе 19\n",[3563,18678,18679,18681,18683,18685,18687,18689,18691],{"class":3565,"line":3580},[3563,18680,3955],{"class":3606},[3563,18682,18665],{"class":3583},[3563,18684,5061],{"class":3587},[3563,18686,3624],{"class":3583},[3563,18688,18656],{"class":3587},[3563,18690,18163],{"class":3583},[3563,18692,18693],{"class":3569},"# Завжди виведе 59\n",[3563,18695,18696],{"class":3565,"line":3594},[3563,18697,3577],{"emptyLinePlaceholder":3576},[3563,18699,18700,18702,18704,18706],{"class":3565,"line":3599},[3563,18701,18653],{"class":3583},[3563,18703,18656],{"class":3587},[3563,18705,5128],{"class":3583},[3563,18707,18708],{"class":3569},"# Скидаємо в ту саму початкову точку\n",[3563,18710,18711,18713,18715,18717,18719,18721,18723],{"class":3565,"line":3642},[3563,18712,3955],{"class":3606},[3563,18714,18665],{"class":3583},[3563,18716,5061],{"class":3587},[3563,18718,3624],{"class":3583},[3563,18720,18656],{"class":3587},[3563,18722,18163],{"class":3583},[3563,18724,18725],{"class":3569},"# Знову 19!\n",[10286,18727,18728,18729,18731],{},"Використовуйте ",[3398,18730,18640],{}," у модульних тестах, коли вам потрібно протестувати логіку, яка залежить від випадкових факторів, щоб забезпечити стабільні та передбачувані результати тестів.",[3461,18733],{},[3468,18735,18737,18738],{"id":18736},"робота-з-часом-модуль-datetime","Робота з часом: модуль ",[3398,18739,5854],{},[3394,18741,18742,18743,18745],{},"Час є однією з найскладніших концепцій у програмуванні через високосні роки, часові пояси та переходи на літній час. Модуль ",[3398,18744,5854],{}," надає класи для обробки дат і часу.",[4287,18747,18749],{"id":18748},"основні-класи","Основні класи",[5138,18751,18752,18758,18764,18770],{},[3508,18753,18754,18757],{},[3398,18755,18756],{},"datetime.date",": представлення дати (рік, місяць, день).",[3508,18759,18760,18763],{},[3398,18761,18762],{},"datetime.time",": представлення часу (година, хвилина, секунда, мікросекунда).",[3508,18765,18766,18769],{},[3398,18767,18768],{},"datetime.datetime",": комбінація дати та часу.",[3508,18771,18772,18775],{},[3398,18773,18774],{},"datetime.timedelta",": тривалість або різниця між двома датами\u002Fчасом.",[4287,18777,18779],{"id":18778},"створення-та-арифметика","Створення та арифметика",[3554,18781,18783],{"className":3556,"code":18782,"language":3558,"meta":3559,"style":3559},"import datetime\n\n# Поточні значення\nnow = datetime.datetime.now()\ntoday = datetime.date.today()\nprint(f\"Зараз: {now}\")\nprint(f\"Сьогодні: {today}\")\n\n# Створення конкретної дати\ndeadline = datetime.datetime(2026, 12, 31, 23, 59, 0)\n\n# Розрахунок різниці (timedelta)\ntime_left = deadline - now\nprint(f\"До дедлайну залишилося: {time_left.days} днів та {time_left.seconds \u002F\u002F 3600} годин\")\n\n# Додавання інтервалу часу\nfuture_date = today + datetime.timedelta(weeks=4)\nprint(f\"Через 4 тижні буде: {future_date}\")\n",[3398,18784,18785,18792,18796,18801,18806,18811,18833,18855,18859,18864,18897,18901,18906,18911,18947,18951,18956,18970],{"__ignoreMap":3559},[3563,18786,18787,18789],{"class":3565,"line":3566},[3563,18788,3905],{"class":3652},[3563,18790,18791],{"class":3583}," datetime\n",[3563,18793,18794],{"class":3565,"line":3573},[3563,18795,3577],{"emptyLinePlaceholder":3576},[3563,18797,18798],{"class":3565,"line":3580},[3563,18799,18800],{"class":3569},"# Поточні значення\n",[3563,18802,18803],{"class":3565,"line":3594},[3563,18804,18805],{"class":3583},"now = datetime.datetime.now()\n",[3563,18807,18808],{"class":3565,"line":3599},[3563,18809,18810],{"class":3583},"today = datetime.date.today()\n",[3563,18812,18813,18815,18817,18819,18822,18824,18827,18829,18831],{"class":3565,"line":3642},[3563,18814,3955],{"class":3606},[3563,18816,3610],{"class":3583},[3563,18818,3960],{"class":3602},[3563,18820,18821],{"class":3645},"\"Зараз: ",[3563,18823,3966],{"class":3602},[3563,18825,18826],{"class":3583},"now",[3563,18828,3972],{"class":3602},[3563,18830,3975],{"class":3645},[3563,18832,3936],{"class":3583},[3563,18834,18835,18837,18839,18841,18844,18846,18849,18851,18853],{"class":3565,"line":3649},[3563,18836,3955],{"class":3606},[3563,18838,3610],{"class":3583},[3563,18840,3960],{"class":3602},[3563,18842,18843],{"class":3645},"\"Сьогодні: ",[3563,18845,3966],{"class":3602},[3563,18847,18848],{"class":3583},"today",[3563,18850,3972],{"class":3602},[3563,18852,3975],{"class":3645},[3563,18854,3936],{"class":3583},[3563,18856,18857],{"class":3565,"line":3659},[3563,18858,3577],{"emptyLinePlaceholder":3576},[3563,18860,18861],{"class":3565,"line":3664},[3563,18862,18863],{"class":3569},"# Створення конкретної дати\n",[3563,18865,18866,18869,18872,18874,18876,18878,18881,18883,18886,18888,18891,18893,18895],{"class":3565,"line":3694},[3563,18867,18868],{"class":3583},"deadline = datetime.datetime(",[3563,18870,18871],{"class":3587},"2026",[3563,18873,3624],{"class":3583},[3563,18875,16278],{"class":3587},[3563,18877,3624],{"class":3583},[3563,18879,18880],{"class":3587},"31",[3563,18882,3624],{"class":3583},[3563,18884,18885],{"class":3587},"23",[3563,18887,3624],{"class":3583},[3563,18889,18890],{"class":3587},"59",[3563,18892,3624],{"class":3583},[3563,18894,5922],{"class":3587},[3563,18896,3936],{"class":3583},[3563,18898,18899],{"class":3565,"line":3700},[3563,18900,3577],{"emptyLinePlaceholder":3576},[3563,18902,18903],{"class":3565,"line":3708},[3563,18904,18905],{"class":3569},"# Розрахунок різниці (timedelta)\n",[3563,18907,18908],{"class":3565,"line":3713},[3563,18909,18910],{"class":3583},"time_left = deadline - now\n",[3563,18912,18913,18915,18917,18919,18922,18924,18927,18929,18932,18934,18937,18940,18942,18945],{"class":3565,"line":3743},[3563,18914,3955],{"class":3606},[3563,18916,3610],{"class":3583},[3563,18918,3960],{"class":3602},[3563,18920,18921],{"class":3645},"\"До дедлайну залишилося: ",[3563,18923,3966],{"class":3602},[3563,18925,18926],{"class":3583},"time_left.days",[3563,18928,3972],{"class":3602},[3563,18930,18931],{"class":3645}," днів та ",[3563,18933,3966],{"class":3602},[3563,18935,18936],{"class":3583},"time_left.seconds \u002F\u002F ",[3563,18938,18939],{"class":3587},"3600",[3563,18941,3972],{"class":3602},[3563,18943,18944],{"class":3645}," годин\"",[3563,18946,3936],{"class":3583},[3563,18948,18949],{"class":3565,"line":3749},[3563,18950,3577],{"emptyLinePlaceholder":3576},[3563,18952,18953],{"class":3565,"line":3757},[3563,18954,18955],{"class":3569},"# Додавання інтервалу часу\n",[3563,18957,18958,18961,18964,18966,18968],{"class":3565,"line":3762},[3563,18959,18960],{"class":3583},"future_date = today + datetime.timedelta(",[3563,18962,18963],{"class":3613},"weeks",[3563,18965,7810],{"class":3583},[3563,18967,18296],{"class":3587},[3563,18969,3936],{"class":3583},[3563,18971,18972,18974,18976,18978,18981,18983,18986,18988,18990],{"class":3565,"line":3785},[3563,18973,3955],{"class":3606},[3563,18975,3610],{"class":3583},[3563,18977,3960],{"class":3602},[3563,18979,18980],{"class":3645},"\"Через 4 тижні буде: ",[3563,18982,3966],{"class":3602},[3563,18984,18985],{"class":3583},"future_date",[3563,18987,3972],{"class":3602},[3563,18989,3975],{"class":3645},[3563,18991,3936],{"class":3583},[4287,18993,18995],{"id":18994},"форматування-та-парсинг","Форматування та парсинг",[3394,18997,18998,18999,19002,19003,19006],{},"Для перетворення часу в рядок використовується метод ",[3398,19000,19001],{},"strftime"," (format time), а для зворотного парсингу з рядка — ",[3398,19004,19005],{},"strptime"," (parse time).",[19008,19009,19010,19089],"code-group",{},[3554,19011,19014],{"className":3556,"code":19012,"filename":19013,"language":3558,"meta":3559,"style":3559},"import datetime\nnow = datetime.datetime.now()\n\n# Використовуємо спеціальні директиви (специфікатори)\nformatted = now.strftime(\"%Y-%m-%d %H:%M:%S\")\nprint(formatted)  # \"2026-06-13 20:30:15\"\n\nhuman_friendly = now.strftime(\"%d %B %Y, (%A)\")\nprint(human_friendly)  # \"13 June 2026, (Saturday)\"\n","Форматування (Time to String)",[3398,19015,19016,19022,19026,19030,19035,19051,19061,19065,19079],{"__ignoreMap":3559},[3563,19017,19018,19020],{"class":3565,"line":3566},[3563,19019,3905],{"class":3652},[3563,19021,18791],{"class":3583},[3563,19023,19024],{"class":3565,"line":3573},[3563,19025,18805],{"class":3583},[3563,19027,19028],{"class":3565,"line":3580},[3563,19029,3577],{"emptyLinePlaceholder":3576},[3563,19031,19032],{"class":3565,"line":3594},[3563,19033,19034],{"class":3569},"# Використовуємо спеціальні директиви (специфікатори)\n",[3563,19036,19037,19040,19043,19046,19049],{"class":3565,"line":3599},[3563,19038,19039],{"class":3583},"formatted = now.strftime(",[3563,19041,19042],{"class":3645},"\"%Y-%m-",[3563,19044,19045],{"class":3602},"%d",[3563,19047,19048],{"class":3645}," %H:%M:%S\"",[3563,19050,3936],{"class":3583},[3563,19052,19053,19055,19058],{"class":3565,"line":3642},[3563,19054,3955],{"class":3606},[3563,19056,19057],{"class":3583},"(formatted)  ",[3563,19059,19060],{"class":3569},"# \"2026-06-13 20:30:15\"\n",[3563,19062,19063],{"class":3565,"line":3649},[3563,19064,3577],{"emptyLinePlaceholder":3576},[3563,19066,19067,19070,19072,19074,19077],{"class":3565,"line":3659},[3563,19068,19069],{"class":3583},"human_friendly = now.strftime(",[3563,19071,3975],{"class":3645},[3563,19073,19045],{"class":3602},[3563,19075,19076],{"class":3645}," %B %Y, (%A)\"",[3563,19078,3936],{"class":3583},[3563,19080,19081,19083,19086],{"class":3565,"line":3664},[3563,19082,3955],{"class":3606},[3563,19084,19085],{"class":3583},"(human_friendly)  ",[3563,19087,19088],{"class":3569},"# \"13 June 2026, (Saturday)\"\n",[3554,19090,19093],{"className":3556,"code":19091,"filename":19092,"language":3558,"meta":3559,"style":3559},"import datetime\n\ndate_str = \"15\u002F09\u002F2025 18:45\"\n# Шаблон MUST точно збігатися з форматом рядка\nparsed = datetime.datetime.strptime(date_str, \"%d\u002F%m\u002F%Y %H:%M\")\nprint(parsed)  # 2025-09-15 18:45:00\nprint(type(parsed))  # \u003Cclass 'datetime.datetime'>\n","Парсинг (String to Time)",[3398,19094,19095,19101,19105,19113,19118,19132,19142],{"__ignoreMap":3559},[3563,19096,19097,19099],{"class":3565,"line":3566},[3563,19098,3905],{"class":3652},[3563,19100,18791],{"class":3583},[3563,19102,19103],{"class":3565,"line":3573},[3563,19104,3577],{"emptyLinePlaceholder":3576},[3563,19106,19107,19110],{"class":3565,"line":3580},[3563,19108,19109],{"class":3583},"date_str = ",[3563,19111,19112],{"class":3645},"\"15\u002F09\u002F2025 18:45\"\n",[3563,19114,19115],{"class":3565,"line":3594},[3563,19116,19117],{"class":3569},"# Шаблон MUST точно збігатися з форматом рядка\n",[3563,19119,19120,19123,19125,19127,19130],{"class":3565,"line":3599},[3563,19121,19122],{"class":3583},"parsed = datetime.datetime.strptime(date_str, ",[3563,19124,3975],{"class":3645},[3563,19126,19045],{"class":3602},[3563,19128,19129],{"class":3645},"\u002F%m\u002F%Y %H:%M\"",[3563,19131,3936],{"class":3583},[3563,19133,19134,19136,19139],{"class":3565,"line":3642},[3563,19135,3955],{"class":3606},[3563,19137,19138],{"class":3583},"(parsed)  ",[3563,19140,19141],{"class":3569},"# 2025-09-15 18:45:00\n",[3563,19143,19144,19146,19148,19150,19153],{"class":3565,"line":3649},[3563,19145,3955],{"class":3606},[3563,19147,3610],{"class":3583},[3563,19149,5601],{"class":3620},[3563,19151,19152],{"class":3583},"(parsed))  ",[3563,19154,19155],{"class":3569},"# \u003Cclass 'datetime.datetime'>\n",[4287,19157,19159],{"id":19158},"naive-vs-aware-обєкти-часу","Naive vs Aware об'єкти часу",[3394,19161,19162,19163,19165,19166,19169,19170,3459],{},"За замовчуванням об'єкти ",[3398,19164,5854],{}," є ",[3406,19167,19168],{},"naive (наївними)"," — вони не містять інформації про часовий пояс. Це небезпечно для серверних систем, де клієнти можуть бути з різних куточків світу. Об'єкти з інформацією про часовий пояс називаються ",[3406,19171,19172],{},"aware (усвідомленими)",[3394,19174,19175,19176,19179],{},"З Python 3.9 вбудовано модуль ",[3398,19177,19178],{},"zoneinfo"," для зручної роботи з базою даних часових поясів IANA:",[3554,19181,19183],{"className":3556,"code":19182,"language":3558,"meta":3559,"style":3559},"from datetime import datetime\nfrom zoneinfo import ZoneInfo\n\n# Створення часу в часовому поясі Києва\nkyiv_time = datetime.now(ZoneInfo(\"Europe\u002FKyiv\"))\nprint(f\"Київ: {kyiv_time}\")  # Наприкінці з'явиться зміщення UTC: +03:00 (або +02:00)\n\n# Конвертація в часовий пояс Нью-Йорка\nny_time = kyiv_time.astimezone(ZoneInfo(\"America\u002FNew_York\"))\nprint(f\"Нью-Йорк: {ny_time}\")  # Час автоматично перераховується\n",[3398,19184,19185,19196,19208,19212,19217,19227,19252,19256,19261,19271],{"__ignoreMap":3559},[3563,19186,19187,19189,19192,19194],{"class":3565,"line":3566},[3563,19188,4907],{"class":3652},[3563,19190,19191],{"class":3583}," datetime ",[3563,19193,3905],{"class":3652},[3563,19195,18791],{"class":3583},[3563,19197,19198,19200,19203,19205],{"class":3565,"line":3573},[3563,19199,4907],{"class":3652},[3563,19201,19202],{"class":3583}," zoneinfo ",[3563,19204,3905],{"class":3652},[3563,19206,19207],{"class":3583}," ZoneInfo\n",[3563,19209,19210],{"class":3565,"line":3580},[3563,19211,3577],{"emptyLinePlaceholder":3576},[3563,19213,19214],{"class":3565,"line":3594},[3563,19215,19216],{"class":3569},"# Створення часу в часовому поясі Києва\n",[3563,19218,19219,19222,19225],{"class":3565,"line":3599},[3563,19220,19221],{"class":3583},"kyiv_time = datetime.now(ZoneInfo(",[3563,19223,19224],{"class":3645},"\"Europe\u002FKyiv\"",[3563,19226,5279],{"class":3583},[3563,19228,19229,19231,19233,19235,19238,19240,19243,19245,19247,19249],{"class":3565,"line":3642},[3563,19230,3955],{"class":3606},[3563,19232,3610],{"class":3583},[3563,19234,3960],{"class":3602},[3563,19236,19237],{"class":3645},"\"Київ: ",[3563,19239,3966],{"class":3602},[3563,19241,19242],{"class":3583},"kyiv_time",[3563,19244,3972],{"class":3602},[3563,19246,3975],{"class":3645},[3563,19248,5128],{"class":3583},[3563,19250,19251],{"class":3569},"# Наприкінці з'явиться зміщення UTC: +03:00 (або +02:00)\n",[3563,19253,19254],{"class":3565,"line":3649},[3563,19255,3577],{"emptyLinePlaceholder":3576},[3563,19257,19258],{"class":3565,"line":3659},[3563,19259,19260],{"class":3569},"# Конвертація в часовий пояс Нью-Йорка\n",[3563,19262,19263,19266,19269],{"class":3565,"line":3664},[3563,19264,19265],{"class":3583},"ny_time = kyiv_time.astimezone(ZoneInfo(",[3563,19267,19268],{"class":3645},"\"America\u002FNew_York\"",[3563,19270,5279],{"class":3583},[3563,19272,19273,19275,19277,19279,19282,19284,19287,19289,19291,19293],{"class":3565,"line":3694},[3563,19274,3955],{"class":3606},[3563,19276,3610],{"class":3583},[3563,19278,3960],{"class":3602},[3563,19280,19281],{"class":3645},"\"Нью-Йорк: ",[3563,19283,3966],{"class":3602},[3563,19285,19286],{"class":3583},"ny_time",[3563,19288,3972],{"class":3602},[3563,19290,3975],{"class":3645},[3563,19292,5128],{"class":3583},[3563,19294,19295],{"class":3569},"# Час автоматично перераховується\n",[3461,19297],{},[3468,19299,19301,19302,17673,19304,17673,19306],{"id":19300},"системна-взаємодія-os-vs-sys-vs-pathlib","Системна взаємодія: ",[3398,19303,5845],{},[3398,19305,5848],{},[3398,19307,19308],{},"pathlib",[3394,19310,19311],{},"Ці модулі забезпечують взаємодію з операційною системою та інтерпретатором Python.",[4287,19313,19315,19316,4481,19318],{"id":19314},"порівняння-призначення-os-та-sys","Порівняння призначення ",[3398,19317,5845],{},[3398,19319,5848],{},[5138,19321,19322,19329],{},[3508,19323,19324,19328],{},[3406,19325,19326],{},[3398,19327,5845],{},": відповідає за роботу з операційною системою (робота з файлами на диску, створення папок, змінні оточення ОС, системні виклики).",[3508,19330,19331,19335,19336,19338],{},[3406,19332,19333],{},[3398,19334,5848],{},": відповідає за взаємодію з самим інтерпретатором Python (параметри запуску скрипта, керування шляхами імпорту ",[3398,19337,3517],{},", внутрішні налаштування пам'яті та лімітів рекурсії).",[4287,19340,19342,19344],{"id":19341},"pathlib-сучасний-стандарт-для-роботи-зі-шляхами",[3398,19343,19308],{}," — сучасний стандарт для роботи зі шляхами",[3394,19346,19347,19348,19351,19352,19354],{},"Раніше для роботи зі шляхами використовувався модуль ",[3398,19349,19350],{},"os.path",". Сьогодні рекомендованим є модуль ",[3398,19353,19308],{},", який надає об'єктно-орієнтований підхід до шляхів.",[19008,19356,19357,19538],{},[3554,19358,19361],{"className":3556,"code":19359,"filename":19360,"language":3558,"meta":3559,"style":3559},"from pathlib import Path\n\n# Створення об'єкта шляху\nproject_dir = Path(\"\u002Fhome\u002Fuser\u002Fproject\")\n\n# Об'єднання шляхів через оператор '\u002F' (дуже зручно!)\nfile_path = project_dir \u002F \"src\" \u002F \"config.json\"\nprint(file_path)  # \u002Fhome\u002Fuser\u002Fproject\u002Fsrc\u002Fconfig.json\n\n# Перевірки та операції\nprint(f\"Чи існує? {file_path.exists()}\")\nprint(f\"Розширення: {file_path.suffix}\")\nprint(f\"Ім'я файлу: {file_path.name}\")\n\n# Створення папки разом із батьківськими\nPath(\"new_folder\u002Fsub_folder\").mkdir(parents=True, exist_ok=True)\n","Сучасний підхід (pathlib)",[3398,19362,19363,19375,19379,19384,19394,19398,19403,19415,19425,19429,19434,19456,19478,19500,19504,19509],{"__ignoreMap":3559},[3563,19364,19365,19367,19370,19372],{"class":3565,"line":3566},[3563,19366,4907],{"class":3652},[3563,19368,19369],{"class":3583}," pathlib ",[3563,19371,3905],{"class":3652},[3563,19373,19374],{"class":3583}," Path\n",[3563,19376,19377],{"class":3565,"line":3573},[3563,19378,3577],{"emptyLinePlaceholder":3576},[3563,19380,19381],{"class":3565,"line":3580},[3563,19382,19383],{"class":3569},"# Створення об'єкта шляху\n",[3563,19385,19386,19389,19392],{"class":3565,"line":3594},[3563,19387,19388],{"class":3583},"project_dir = Path(",[3563,19390,19391],{"class":3645},"\"\u002Fhome\u002Fuser\u002Fproject\"",[3563,19393,3936],{"class":3583},[3563,19395,19396],{"class":3565,"line":3599},[3563,19397,3577],{"emptyLinePlaceholder":3576},[3563,19399,19400],{"class":3565,"line":3642},[3563,19401,19402],{"class":3569},"# Об'єднання шляхів через оператор '\u002F' (дуже зручно!)\n",[3563,19404,19405,19408,19410,19412],{"class":3565,"line":3649},[3563,19406,19407],{"class":3583},"file_path = project_dir \u002F ",[3563,19409,17069],{"class":3645},[3563,19411,8106],{"class":3583},[3563,19413,19414],{"class":3645},"\"config.json\"\n",[3563,19416,19417,19419,19422],{"class":3565,"line":3659},[3563,19418,3955],{"class":3606},[3563,19420,19421],{"class":3583},"(file_path)  ",[3563,19423,19424],{"class":3569},"# \u002Fhome\u002Fuser\u002Fproject\u002Fsrc\u002Fconfig.json\n",[3563,19426,19427],{"class":3565,"line":3664},[3563,19428,3577],{"emptyLinePlaceholder":3576},[3563,19430,19431],{"class":3565,"line":3694},[3563,19432,19433],{"class":3569},"# Перевірки та операції\n",[3563,19435,19436,19438,19440,19442,19445,19447,19450,19452,19454],{"class":3565,"line":3700},[3563,19437,3955],{"class":3606},[3563,19439,3610],{"class":3583},[3563,19441,3960],{"class":3602},[3563,19443,19444],{"class":3645},"\"Чи існує? ",[3563,19446,3966],{"class":3602},[3563,19448,19449],{"class":3583},"file_path.exists()",[3563,19451,3972],{"class":3602},[3563,19453,3975],{"class":3645},[3563,19455,3936],{"class":3583},[3563,19457,19458,19460,19462,19464,19467,19469,19472,19474,19476],{"class":3565,"line":3708},[3563,19459,3955],{"class":3606},[3563,19461,3610],{"class":3583},[3563,19463,3960],{"class":3602},[3563,19465,19466],{"class":3645},"\"Розширення: ",[3563,19468,3966],{"class":3602},[3563,19470,19471],{"class":3583},"file_path.suffix",[3563,19473,3972],{"class":3602},[3563,19475,3975],{"class":3645},[3563,19477,3936],{"class":3583},[3563,19479,19480,19482,19484,19486,19489,19491,19494,19496,19498],{"class":3565,"line":3713},[3563,19481,3955],{"class":3606},[3563,19483,3610],{"class":3583},[3563,19485,3960],{"class":3602},[3563,19487,19488],{"class":3645},"\"Ім'я файлу: ",[3563,19490,3966],{"class":3602},[3563,19492,19493],{"class":3583},"file_path.name",[3563,19495,3972],{"class":3602},[3563,19497,3975],{"class":3645},[3563,19499,3936],{"class":3583},[3563,19501,19502],{"class":3565,"line":3743},[3563,19503,3577],{"emptyLinePlaceholder":3576},[3563,19505,19506],{"class":3565,"line":3749},[3563,19507,19508],{"class":3569},"# Створення папки разом із батьківськими\n",[3563,19510,19511,19514,19517,19520,19523,19525,19527,19529,19532,19534,19536],{"class":3565,"line":3757},[3563,19512,19513],{"class":3583},"Path(",[3563,19515,19516],{"class":3645},"\"new_folder\u002Fsub_folder\"",[3563,19518,19519],{"class":3583},").mkdir(",[3563,19521,19522],{"class":3613},"parents",[3563,19524,7810],{"class":3583},[3563,19526,6476],{"class":3602},[3563,19528,3624],{"class":3583},[3563,19530,19531],{"class":3613},"exist_ok",[3563,19533,7810],{"class":3583},[3563,19535,6476],{"class":3602},[3563,19537,3936],{"class":3583},[3554,19539,19542],{"className":3556,"code":19540,"filename":19541,"language":3558,"meta":3559,"style":3559},"import os\n\nproject_dir = \"\u002Fhome\u002Fuser\u002Fproject\"\n\n# Об'єднання шляхів через os.path.join\nfile_path = os.path.join(project_dir, \"src\", \"config.json\")\nprint(file_path)  # \u002Fhome\u002Fuser\u002Fproject\u002Fsrc\u002Fconfig.json\n\n# Перевірки та операції\nprint(f\"Чи існує? {os.path.exists(file_path)}\")\nprint(f\"Розширення: {os.path.splitext(file_path)[1]}\")\nprint(f\"Ім'я файлу: {os.path.basename(file_path)}\")\n\n# Створення папки\nos.makedirs(\"new_folder\u002Fsub_folder\", exist_ok=True)\n","Старий підхід (os.path)",[3398,19543,19544,19550,19554,19562,19566,19571,19585,19593,19597,19601,19622,19647,19668,19672,19677],{"__ignoreMap":3559},[3563,19545,19546,19548],{"class":3565,"line":3566},[3563,19547,3905],{"class":3652},[3563,19549,4850],{"class":3583},[3563,19551,19552],{"class":3565,"line":3573},[3563,19553,3577],{"emptyLinePlaceholder":3576},[3563,19555,19556,19559],{"class":3565,"line":3580},[3563,19557,19558],{"class":3583},"project_dir = ",[3563,19560,19561],{"class":3645},"\"\u002Fhome\u002Fuser\u002Fproject\"\n",[3563,19563,19564],{"class":3565,"line":3594},[3563,19565,3577],{"emptyLinePlaceholder":3576},[3563,19567,19568],{"class":3565,"line":3599},[3563,19569,19570],{"class":3569},"# Об'єднання шляхів через os.path.join\n",[3563,19572,19573,19576,19578,19580,19583],{"class":3565,"line":3642},[3563,19574,19575],{"class":3583},"file_path = os.path.join(project_dir, ",[3563,19577,17069],{"class":3645},[3563,19579,3624],{"class":3583},[3563,19581,19582],{"class":3645},"\"config.json\"",[3563,19584,3936],{"class":3583},[3563,19586,19587,19589,19591],{"class":3565,"line":3649},[3563,19588,3955],{"class":3606},[3563,19590,19421],{"class":3583},[3563,19592,19424],{"class":3569},[3563,19594,19595],{"class":3565,"line":3659},[3563,19596,3577],{"emptyLinePlaceholder":3576},[3563,19598,19599],{"class":3565,"line":3664},[3563,19600,19433],{"class":3569},[3563,19602,19603,19605,19607,19609,19611,19613,19616,19618,19620],{"class":3565,"line":3694},[3563,19604,3955],{"class":3606},[3563,19606,3610],{"class":3583},[3563,19608,3960],{"class":3602},[3563,19610,19444],{"class":3645},[3563,19612,3966],{"class":3602},[3563,19614,19615],{"class":3583},"os.path.exists(file_path)",[3563,19617,3972],{"class":3602},[3563,19619,3975],{"class":3645},[3563,19621,3936],{"class":3583},[3563,19623,19624,19626,19628,19630,19632,19634,19637,19639,19641,19643,19645],{"class":3565,"line":3700},[3563,19625,3955],{"class":3606},[3563,19627,3610],{"class":3583},[3563,19629,3960],{"class":3602},[3563,19631,19466],{"class":3645},[3563,19633,3966],{"class":3602},[3563,19635,19636],{"class":3583},"os.path.splitext(file_path)[",[3563,19638,5061],{"class":3587},[3563,19640,4741],{"class":3583},[3563,19642,3972],{"class":3602},[3563,19644,3975],{"class":3645},[3563,19646,3936],{"class":3583},[3563,19648,19649,19651,19653,19655,19657,19659,19662,19664,19666],{"class":3565,"line":3708},[3563,19650,3955],{"class":3606},[3563,19652,3610],{"class":3583},[3563,19654,3960],{"class":3602},[3563,19656,19488],{"class":3645},[3563,19658,3966],{"class":3602},[3563,19660,19661],{"class":3583},"os.path.basename(file_path)",[3563,19663,3972],{"class":3602},[3563,19665,3975],{"class":3645},[3563,19667,3936],{"class":3583},[3563,19669,19670],{"class":3565,"line":3713},[3563,19671,3577],{"emptyLinePlaceholder":3576},[3563,19673,19674],{"class":3565,"line":3743},[3563,19675,19676],{"class":3569},"# Створення папки\n",[3563,19678,19679,19682,19684,19686,19688,19690,19692],{"class":3565,"line":3749},[3563,19680,19681],{"class":3583},"os.makedirs(",[3563,19683,19516],{"class":3645},[3563,19685,3624],{"class":3583},[3563,19687,19531],{"class":3613},[3563,19689,7810],{"class":3583},[3563,19691,6476],{"class":3602},[3563,19693,3936],{"class":3583},[4287,19695,19697,19698],{"id":19696},"ключові-можливості-sys","Ключові можливості ",[3398,19699,5848],{},[3554,19701,19703],{"className":3556,"code":19702,"language":3558,"meta":3559,"style":3559},"import sys\n\n# Аргументи командного рядка (наприклад: python main.py data.txt)\n# sys.argv[0] — це завжди ім'я самого скрипта\nprint(f\"Аргументи запуску: {sys.argv}\")\n\n# Платформа та версія\nprint(sys.platform)  # 'darwin' (macOS), 'win32' (Windows), 'linux' (Linux)\nprint(sys.version)   # Детальна версія інтерпретатора\n\n# Безпечне завершення роботи скрипта з кодом виходу\n# 0 = успіх, будь-яке інше число = помилка\nsys.exit(0)\n",[3398,19704,19705,19711,19715,19720,19725,19747,19751,19756,19766,19776,19780,19785,19790],{"__ignoreMap":3559},[3563,19706,19707,19709],{"class":3565,"line":3566},[3563,19708,3905],{"class":3652},[3563,19710,4857],{"class":3583},[3563,19712,19713],{"class":3565,"line":3573},[3563,19714,3577],{"emptyLinePlaceholder":3576},[3563,19716,19717],{"class":3565,"line":3580},[3563,19718,19719],{"class":3569},"# Аргументи командного рядка (наприклад: python main.py data.txt)\n",[3563,19721,19722],{"class":3565,"line":3594},[3563,19723,19724],{"class":3569},"# sys.argv[0] — це завжди ім'я самого скрипта\n",[3563,19726,19727,19729,19731,19733,19736,19738,19741,19743,19745],{"class":3565,"line":3599},[3563,19728,3955],{"class":3606},[3563,19730,3610],{"class":3583},[3563,19732,3960],{"class":3602},[3563,19734,19735],{"class":3645},"\"Аргументи запуску: ",[3563,19737,3966],{"class":3602},[3563,19739,19740],{"class":3583},"sys.argv",[3563,19742,3972],{"class":3602},[3563,19744,3975],{"class":3645},[3563,19746,3936],{"class":3583},[3563,19748,19749],{"class":3565,"line":3642},[3563,19750,3577],{"emptyLinePlaceholder":3576},[3563,19752,19753],{"class":3565,"line":3649},[3563,19754,19755],{"class":3569},"# Платформа та версія\n",[3563,19757,19758,19760,19763],{"class":3565,"line":3659},[3563,19759,3955],{"class":3606},[3563,19761,19762],{"class":3583},"(sys.platform)  ",[3563,19764,19765],{"class":3569},"# 'darwin' (macOS), 'win32' (Windows), 'linux' (Linux)\n",[3563,19767,19768,19770,19773],{"class":3565,"line":3664},[3563,19769,3955],{"class":3606},[3563,19771,19772],{"class":3583},"(sys.version)   ",[3563,19774,19775],{"class":3569},"# Детальна версія інтерпретатора\n",[3563,19777,19778],{"class":3565,"line":3694},[3563,19779,3577],{"emptyLinePlaceholder":3576},[3563,19781,19782],{"class":3565,"line":3700},[3563,19783,19784],{"class":3569},"# Безпечне завершення роботи скрипта з кодом виходу\n",[3563,19786,19787],{"class":3565,"line":3708},[3563,19788,19789],{"class":3569},"# 0 = успіх, будь-яке інше число = помилка\n",[3563,19791,19792,19795,19797],{"class":3565,"line":3713},[3563,19793,19794],{"class":3583},"sys.exit(",[3563,19796,5922],{"class":3587},[3563,19798,3936],{"class":3583},[3461,19800],{},[3468,19802,19804,19805],{"id":19803},"спеціалізовані-контейнери-модуль-collections","Спеціалізовані контейнери: модуль ",[3398,19806,19807],{},"collections",[3394,19809,19810,19811,3624,19813,3624,19815,4481,19818,19821,19822,19824],{},"Стандартні типи ",[3398,19812,4276],{},[3398,19814,4666],{},[3398,19816,19817],{},"set",[3398,19819,19820],{},"tuple"," чудово підходять для більшості завдань, але модуль ",[3398,19823,19807],{}," надає альтернативні контейнери з розширеною поведінкою.",[4287,19826,19828,19831],{"id":19827},"namedtuple-кортеж-з-іменованими-полями",[3398,19829,19830],{},"namedtuple"," — кортеж з іменованими полями",[3394,19833,19834,19835,19838,19839,19842],{},"Коли вам потрібен легковажний, незмінний об'єкт (наприклад, для представлення точки на карті чи запису користувача), писати повноцінний клас занадто довго. Звичайний кортеж ",[3398,19836,19837],{},"Point = (50.45, 30.52)"," змушує звертатися за індексами ",[3398,19840,19841],{},"Point[0]",", що шкодить читабельності.",[3554,19844,19846],{"className":3556,"code":19845,"language":3558,"meta":3559,"style":3559},"from collections import namedtuple\n\n# Створюємо тип (фабрику) Geopoint з полями latitude та longitude\nGeopoint = namedtuple(\"Geopoint\", [\"latitude\", \"longitude\"])\n\n# Створюємо екземпляр\nkyiv = Geopoint(latitude=50.4501, longitude=30.5234)\n\n# Звернення за іменами полів!\nprint(f\"Широта: {kyiv.latitude}, Довгота: {kyiv.longitude}\")\n\n# Але це все ще кортеж (сумісність збережена)\nprint(f\"Індекс 0: {kyiv[0]}\")\nlat, lon = kyiv  # Розпакування працює\n",[3398,19847,19848,19860,19864,19869,19889,19893,19898,19923,19927,19932,19964,19968,19973,19999],{"__ignoreMap":3559},[3563,19849,19850,19852,19855,19857],{"class":3565,"line":3566},[3563,19851,4907],{"class":3652},[3563,19853,19854],{"class":3583}," collections ",[3563,19856,3905],{"class":3652},[3563,19858,19859],{"class":3583}," namedtuple\n",[3563,19861,19862],{"class":3565,"line":3573},[3563,19863,3577],{"emptyLinePlaceholder":3576},[3563,19865,19866],{"class":3565,"line":3580},[3563,19867,19868],{"class":3569},"# Створюємо тип (фабрику) Geopoint з полями latitude та longitude\n",[3563,19870,19871,19874,19877,19879,19882,19884,19887],{"class":3565,"line":3594},[3563,19872,19873],{"class":3583},"Geopoint = namedtuple(",[3563,19875,19876],{"class":3645},"\"Geopoint\"",[3563,19878,9965],{"class":3583},[3563,19880,19881],{"class":3645},"\"latitude\"",[3563,19883,3624],{"class":3583},[3563,19885,19886],{"class":3645},"\"longitude\"",[3563,19888,5072],{"class":3583},[3563,19890,19891],{"class":3565,"line":3599},[3563,19892,3577],{"emptyLinePlaceholder":3576},[3563,19894,19895],{"class":3565,"line":3642},[3563,19896,19897],{"class":3569},"# Створюємо екземпляр\n",[3563,19899,19900,19903,19906,19908,19911,19913,19916,19918,19921],{"class":3565,"line":3649},[3563,19901,19902],{"class":3583},"kyiv = Geopoint(",[3563,19904,19905],{"class":3613},"latitude",[3563,19907,7810],{"class":3583},[3563,19909,19910],{"class":3587},"50.4501",[3563,19912,3624],{"class":3583},[3563,19914,19915],{"class":3613},"longitude",[3563,19917,7810],{"class":3583},[3563,19919,19920],{"class":3587},"30.5234",[3563,19922,3936],{"class":3583},[3563,19924,19925],{"class":3565,"line":3659},[3563,19926,3577],{"emptyLinePlaceholder":3576},[3563,19928,19929],{"class":3565,"line":3664},[3563,19930,19931],{"class":3569},"# Звернення за іменами полів!\n",[3563,19933,19934,19936,19938,19940,19943,19945,19948,19950,19953,19955,19958,19960,19962],{"class":3565,"line":3694},[3563,19935,3955],{"class":3606},[3563,19937,3610],{"class":3583},[3563,19939,3960],{"class":3602},[3563,19941,19942],{"class":3645},"\"Широта: ",[3563,19944,3966],{"class":3602},[3563,19946,19947],{"class":3583},"kyiv.latitude",[3563,19949,3972],{"class":3602},[3563,19951,19952],{"class":3645},", Довгота: ",[3563,19954,3966],{"class":3602},[3563,19956,19957],{"class":3583},"kyiv.longitude",[3563,19959,3972],{"class":3602},[3563,19961,3975],{"class":3645},[3563,19963,3936],{"class":3583},[3563,19965,19966],{"class":3565,"line":3700},[3563,19967,3577],{"emptyLinePlaceholder":3576},[3563,19969,19970],{"class":3565,"line":3708},[3563,19971,19972],{"class":3569},"# Але це все ще кортеж (сумісність збережена)\n",[3563,19974,19975,19977,19979,19981,19984,19986,19989,19991,19993,19995,19997],{"class":3565,"line":3713},[3563,19976,3955],{"class":3606},[3563,19978,3610],{"class":3583},[3563,19980,3960],{"class":3602},[3563,19982,19983],{"class":3645},"\"Індекс 0: ",[3563,19985,3966],{"class":3602},[3563,19987,19988],{"class":3583},"kyiv[",[3563,19990,5922],{"class":3587},[3563,19992,4741],{"class":3583},[3563,19994,3972],{"class":3602},[3563,19996,3975],{"class":3645},[3563,19998,3936],{"class":3583},[3563,20000,20001,20004],{"class":3565,"line":3743},[3563,20002,20003],{"class":3583},"lat, lon = kyiv  ",[3563,20005,20006],{"class":3569},"# Розпакування працює\n",[4287,20008,20010,20013],{"id":20009},"defaultdict-словник-зі-значенням-за-замовчуванням",[3398,20011,20012],{},"defaultdict"," — словник зі значенням за замовчуванням",[3394,20015,20016,20017,20019,20020,20022,20023,20025],{},"При роботі зі звичайним ",[3398,20018,4276],{}," звернення до неіснуючого ключа викликає ",[3398,20021,4353],{},". ",[3398,20024,20012],{}," автоматично створює значення за замовчуванням при першому зверненні до нового ключа.",[3554,20027,20029],{"className":3556,"code":20028,"language":3558,"meta":3559,"style":3559},"from collections import defaultdict\n\n# Словник, який за замовчуванням створює порожній список (list) для нових ключів\ngrouped_students = defaultdict(list)\n\n# Нам не потрібно перевіряти, чи є ключ \"Python\" у словнику!\ngrouped_students[\"Python\"].append(\"Олег\")\ngrouped_students[\"Python\"].append(\"Марія\")\ngrouped_students[\"Go\"].append(\"Іван\")\n\nprint(grouped_students)\n# defaultdict(\u003Cclass 'list'>, {'Python': ['Олег', 'Марія'], 'Go': ['Іван']})\n",[3398,20030,20031,20042,20046,20051,20060,20064,20069,20085,20098,20112,20116,20123],{"__ignoreMap":3559},[3563,20032,20033,20035,20037,20039],{"class":3565,"line":3566},[3563,20034,4907],{"class":3652},[3563,20036,19854],{"class":3583},[3563,20038,3905],{"class":3652},[3563,20040,20041],{"class":3583}," defaultdict\n",[3563,20043,20044],{"class":3565,"line":3573},[3563,20045,3577],{"emptyLinePlaceholder":3576},[3563,20047,20048],{"class":3565,"line":3580},[3563,20049,20050],{"class":3569},"# Словник, який за замовчуванням створює порожній список (list) для нових ключів\n",[3563,20052,20053,20056,20058],{"class":3565,"line":3594},[3563,20054,20055],{"class":3583},"grouped_students = defaultdict(",[3563,20057,4666],{"class":3620},[3563,20059,3936],{"class":3583},[3563,20061,20062],{"class":3565,"line":3599},[3563,20063,3577],{"emptyLinePlaceholder":3576},[3563,20065,20066],{"class":3565,"line":3642},[3563,20067,20068],{"class":3569},"# Нам не потрібно перевіряти, чи є ключ \"Python\" у словнику!\n",[3563,20070,20071,20074,20077,20080,20083],{"class":3565,"line":3649},[3563,20072,20073],{"class":3583},"grouped_students[",[3563,20075,20076],{"class":3645},"\"Python\"",[3563,20078,20079],{"class":3583},"].append(",[3563,20081,20082],{"class":3645},"\"Олег\"",[3563,20084,3936],{"class":3583},[3563,20086,20087,20089,20091,20093,20096],{"class":3565,"line":3659},[3563,20088,20073],{"class":3583},[3563,20090,20076],{"class":3645},[3563,20092,20079],{"class":3583},[3563,20094,20095],{"class":3645},"\"Марія\"",[3563,20097,3936],{"class":3583},[3563,20099,20100,20102,20105,20107,20110],{"class":3565,"line":3664},[3563,20101,20073],{"class":3583},[3563,20103,20104],{"class":3645},"\"Go\"",[3563,20106,20079],{"class":3583},[3563,20108,20109],{"class":3645},"\"Іван\"",[3563,20111,3936],{"class":3583},[3563,20113,20114],{"class":3565,"line":3694},[3563,20115,3577],{"emptyLinePlaceholder":3576},[3563,20117,20118,20120],{"class":3565,"line":3700},[3563,20119,3955],{"class":3606},[3563,20121,20122],{"class":3583},"(grouped_students)\n",[3563,20124,20125],{"class":3565,"line":3708},[3563,20126,20127],{"class":3569},"# defaultdict(\u003Cclass 'list'>, {'Python': ['Олег', 'Марія'], 'Go': ['Іван']})\n",[4287,20129,20131,20134],{"id":20130},"counter-зручний-лічильник-елементів",[3398,20132,20133],{},"Counter"," — зручний лічильник елементів",[3394,20136,20137,20138,20140,20141,20143],{},"Клас ",[3398,20139,20133],{}," призначений для швидкого підрахунку кількості об'єктів. Він є підкласом ",[3398,20142,4276],{},", тому успадковує всі його методи.",[3554,20145,20147],{"className":3556,"code":20146,"language":3558,"meta":3559,"style":3559},"from collections import Counter\n\nwords = [\"яблуко\", \"банан\", \"яблуко\", \"апельсин\", \"банан\", \"яблуко\"]\ncounter = Counter(words)\n\nprint(counter)  # Counter({'яблуко': 3, 'банан': 2, 'апельсин': 1})\nprint(f\"Кількість бананів: {counter['банан']}\")\nprint(f\"Кількість неіснуючих елементів: {counter['груша']}\")  # Повертає 0 замість KeyError!\n\n# Отримання топ-N найпопулярніших елементів\nprint(f\"Найпопулярніші: {counter.most_common(2)}\")  # [('яблуко', 3), ('банан', 2)]\n",[3398,20148,20149,20160,20164,20196,20201,20205,20215,20242,20271,20275,20280],{"__ignoreMap":3559},[3563,20150,20151,20153,20155,20157],{"class":3565,"line":3566},[3563,20152,4907],{"class":3652},[3563,20154,19854],{"class":3583},[3563,20156,3905],{"class":3652},[3563,20158,20159],{"class":3583}," Counter\n",[3563,20161,20162],{"class":3565,"line":3573},[3563,20163,3577],{"emptyLinePlaceholder":3576},[3563,20165,20166,20169,20172,20174,20177,20179,20181,20183,20186,20188,20190,20192,20194],{"class":3565,"line":3580},[3563,20167,20168],{"class":3583},"words = [",[3563,20170,20171],{"class":3645},"\"яблуко\"",[3563,20173,3624],{"class":3583},[3563,20175,20176],{"class":3645},"\"банан\"",[3563,20178,3624],{"class":3583},[3563,20180,20171],{"class":3645},[3563,20182,3624],{"class":3583},[3563,20184,20185],{"class":3645},"\"апельсин\"",[3563,20187,3624],{"class":3583},[3563,20189,20176],{"class":3645},[3563,20191,3624],{"class":3583},[3563,20193,20171],{"class":3645},[3563,20195,6347],{"class":3583},[3563,20197,20198],{"class":3565,"line":3594},[3563,20199,20200],{"class":3583},"counter = Counter(words)\n",[3563,20202,20203],{"class":3565,"line":3599},[3563,20204,3577],{"emptyLinePlaceholder":3576},[3563,20206,20207,20209,20212],{"class":3565,"line":3642},[3563,20208,3955],{"class":3606},[3563,20210,20211],{"class":3583},"(counter)  ",[3563,20213,20214],{"class":3569},"# Counter({'яблуко': 3, 'банан': 2, 'апельсин': 1})\n",[3563,20216,20217,20219,20221,20223,20226,20228,20231,20234,20236,20238,20240],{"class":3565,"line":3649},[3563,20218,3955],{"class":3606},[3563,20220,3610],{"class":3583},[3563,20222,3960],{"class":3602},[3563,20224,20225],{"class":3645},"\"Кількість бананів: ",[3563,20227,3966],{"class":3602},[3563,20229,20230],{"class":3583},"counter[",[3563,20232,20233],{"class":3645},"'банан'",[3563,20235,4741],{"class":3583},[3563,20237,3972],{"class":3602},[3563,20239,3975],{"class":3645},[3563,20241,3936],{"class":3583},[3563,20243,20244,20246,20248,20250,20253,20255,20257,20260,20262,20264,20266,20268],{"class":3565,"line":3659},[3563,20245,3955],{"class":3606},[3563,20247,3610],{"class":3583},[3563,20249,3960],{"class":3602},[3563,20251,20252],{"class":3645},"\"Кількість неіснуючих елементів: ",[3563,20254,3966],{"class":3602},[3563,20256,20230],{"class":3583},[3563,20258,20259],{"class":3645},"'груша'",[3563,20261,4741],{"class":3583},[3563,20263,3972],{"class":3602},[3563,20265,3975],{"class":3645},[3563,20267,5128],{"class":3583},[3563,20269,20270],{"class":3569},"# Повертає 0 замість KeyError!\n",[3563,20272,20273],{"class":3565,"line":3664},[3563,20274,3577],{"emptyLinePlaceholder":3576},[3563,20276,20277],{"class":3565,"line":3694},[3563,20278,20279],{"class":3569},"# Отримання топ-N найпопулярніших елементів\n",[3563,20281,20282,20284,20286,20288,20291,20293,20296,20298,20300,20302,20304,20306],{"class":3565,"line":3700},[3563,20283,3955],{"class":3606},[3563,20285,3610],{"class":3583},[3563,20287,3960],{"class":3602},[3563,20289,20290],{"class":3645},"\"Найпопулярніші: ",[3563,20292,3966],{"class":3602},[3563,20294,20295],{"class":3583},"counter.most_common(",[3563,20297,4209],{"class":3587},[3563,20299,3518],{"class":3583},[3563,20301,3972],{"class":3602},[3563,20303,3975],{"class":3645},[3563,20305,5128],{"class":3583},[3563,20307,20308],{"class":3569},"# [('яблуко', 3), ('банан', 2)]\n",[4287,20310,20312,20315],{"id":20311},"deque-оптимізована-двостороння-черга",[3398,20313,20314],{},"deque"," — оптимізована двостороння черга",[3394,20317,20318,20319,20321,20322,4310,20325,20328,20329,20332],{},"Звичайний список Python ",[3398,20320,4666],{}," оптимізований для операцій у кінці структури. Додавання або видалення елемента з початку списку (",[3398,20323,20324],{},"list.insert(0, val)",[3398,20326,20327],{},"list.pop(0)",") має складність ",[3406,20330,20331],{},"$O(N)$",", оскільки всі інші елементи в пам'яті мають зсунутися на один крок.",[3394,20334,20335,20337,20338,3459],{},[3398,20336,20314],{}," (double-ended queue) реалізований як двобічно зв'язаний список, що робить додавання та видалення елементів з обох кінців надзвичайно швидким — за ",[3406,20339,20340],{},"$O(1)$",[3554,20342,20344],{"className":3556,"code":20343,"language":3558,"meta":3559,"style":3559},"from collections import deque\n\nqueue = deque([\"Користувач 1\", \"Користувач 2\"])\n\n# Швидке додавання в кінець\nqueue.append(\"Користувач 3\")\n\n# Швидке додавання на початок\nqueue.appendleft(\"VIP Користувач\")\nprint(queue)  # deque(['VIP Користувач', 'Користувач 1', ...])\n\n# Видалення з обох кінців\nfirst_in = queue.popleft()  # 'VIP Користувач'\nlast_in = queue.pop()       # 'Користувач 3'\n",[3398,20345,20346,20357,20361,20376,20380,20385,20395,20399,20404,20414,20424,20428,20433,20441],{"__ignoreMap":3559},[3563,20347,20348,20350,20352,20354],{"class":3565,"line":3566},[3563,20349,4907],{"class":3652},[3563,20351,19854],{"class":3583},[3563,20353,3905],{"class":3652},[3563,20355,20356],{"class":3583}," deque\n",[3563,20358,20359],{"class":3565,"line":3573},[3563,20360,3577],{"emptyLinePlaceholder":3576},[3563,20362,20363,20366,20369,20371,20374],{"class":3565,"line":3580},[3563,20364,20365],{"class":3583},"queue = deque([",[3563,20367,20368],{"class":3645},"\"Користувач 1\"",[3563,20370,3624],{"class":3583},[3563,20372,20373],{"class":3645},"\"Користувач 2\"",[3563,20375,5072],{"class":3583},[3563,20377,20378],{"class":3565,"line":3594},[3563,20379,3577],{"emptyLinePlaceholder":3576},[3563,20381,20382],{"class":3565,"line":3599},[3563,20383,20384],{"class":3569},"# Швидке додавання в кінець\n",[3563,20386,20387,20390,20393],{"class":3565,"line":3642},[3563,20388,20389],{"class":3583},"queue.append(",[3563,20391,20392],{"class":3645},"\"Користувач 3\"",[3563,20394,3936],{"class":3583},[3563,20396,20397],{"class":3565,"line":3649},[3563,20398,3577],{"emptyLinePlaceholder":3576},[3563,20400,20401],{"class":3565,"line":3659},[3563,20402,20403],{"class":3569},"# Швидке додавання на початок\n",[3563,20405,20406,20409,20412],{"class":3565,"line":3664},[3563,20407,20408],{"class":3583},"queue.appendleft(",[3563,20410,20411],{"class":3645},"\"VIP Користувач\"",[3563,20413,3936],{"class":3583},[3563,20415,20416,20418,20421],{"class":3565,"line":3694},[3563,20417,3955],{"class":3606},[3563,20419,20420],{"class":3583},"(queue)  ",[3563,20422,20423],{"class":3569},"# deque(['VIP Користувач', 'Користувач 1', ...])\n",[3563,20425,20426],{"class":3565,"line":3700},[3563,20427,3577],{"emptyLinePlaceholder":3576},[3563,20429,20430],{"class":3565,"line":3708},[3563,20431,20432],{"class":3569},"# Видалення з обох кінців\n",[3563,20434,20435,20438],{"class":3565,"line":3713},[3563,20436,20437],{"class":3583},"first_in = queue.popleft()  ",[3563,20439,20440],{"class":3569},"# 'VIP Користувач'\n",[3563,20442,20443,20446],{"class":3565,"line":3743},[3563,20444,20445],{"class":3583},"last_in = queue.pop()       ",[3563,20447,20448],{"class":3569},"# 'Користувач 3'\n",[10286,20450,18728,20451,20453,20454,20457,20458,20461],{},[3398,20452,20314],{}," для реалізації стеків, черг завдань (FIFO\u002FLIFO) або для зберігання логів фіксованого розміру (задавши параметр ",[3398,20455,20456],{},"maxlen"," при створенні, наприклад ",[3398,20459,20460],{},"deque(maxlen=100)"," — при додаванні 101-го елемента перший автоматично видалиться).",[3461,20463],{},[3389,20465,20467],{"id":20466},"повний-цикл-роботи-від-нуля-до-готового-проекту","Повний цикл роботи: від нуля до готового проекту",[3394,20469,20470],{},"Це стандартна послідовність дій при створенні нового Python-проекту:",[3554,20472,20474],{"className":11048,"code":20473,"language":11050,"meta":3559,"style":3559},"# 1. Створити директорію проекту\nmkdir my-awesome-project\ncd my-awesome-project\n\n# 2. Ініціалізувати git-репозиторій (опціонально, але рекомендується)\ngit init\n\n# 3. Створити файл .gitignore — ОДРАЗУ, до будь-яких комітів\ncat > .gitignore \u003C\u003C 'EOF'\n# Віртуальне середовище — ніколи не комітимо!\n.venv\u002F\nvenv\u002F\n\n# Байткод Python\n__pycache__\u002F\n*.pyc\n*.pyo\n\n# Середовища та IDE\n.env\n.DS_Store\n.idea\u002F\n.vscode\u002F\nEOF\n\n# 4. Створити та активувати venv\npython -m venv .venv\nsource .venv\u002Fbin\u002Factivate  # (.venv) з'явиться у промпті\n\n# 5. Встановити залежності проекту\npip install requests django pytest\n\n# 6. Зафіксувати залежності\npip freeze > requirements.txt\n\n# 7. Написати код...\n\n# 8. Перед завершенням — оновити requirements.txt\npip freeze > requirements.txt\ngit add requirements.txt\ngit commit -m \"chore: update dependencies\"\n",[3398,20475,20476,20481,20488,20494,20498,20503,20509,20513,20518,20532,20537,20541,20545,20549,20554,20558,20563,20567,20571,20576,20580,20585,20589,20593,20598,20602,20607,20617,20627,20631,20636,20648,20652,20657,20667,20671,20676,20680,20685,20695,20703],{"__ignoreMap":3559},[3563,20477,20478],{"class":3565,"line":3566},[3563,20479,20480],{"class":3569},"# 1. Створити директорію проекту\n",[3563,20482,20483,20485],{"class":3565,"line":3573},[3563,20484,11945],{"class":3606},[3563,20486,20487],{"class":3645}," my-awesome-project\n",[3563,20489,20490,20492],{"class":3565,"line":3580},[3563,20491,11929],{"class":3606},[3563,20493,20487],{"class":3645},[3563,20495,20496],{"class":3565,"line":3594},[3563,20497,3577],{"emptyLinePlaceholder":3576},[3563,20499,20500],{"class":3565,"line":3599},[3563,20501,20502],{"class":3569},"# 2. Ініціалізувати git-репозиторій (опціонально, але рекомендується)\n",[3563,20504,20505,20507],{"class":3565,"line":3642},[3563,20506,15188],{"class":3606},[3563,20508,11963],{"class":3645},[3563,20510,20511],{"class":3565,"line":3649},[3563,20512,3577],{"emptyLinePlaceholder":3576},[3563,20514,20515],{"class":3565,"line":3659},[3563,20516,20517],{"class":3569},"# 3. Створити файл .gitignore — ОДРАЗУ, до будь-яких комітів\n",[3563,20519,20520,20522,20524,20526,20529],{"class":3565,"line":3664},[3563,20521,11519],{"class":3606},[3563,20523,11507],{"class":3583},[3563,20525,15760],{"class":3645},[3563,20527,20528],{"class":3583}," \u003C\u003C ",[3563,20530,20531],{"class":3583},"'EOF'\n",[3563,20533,20534],{"class":3565,"line":3694},[3563,20535,20536],{"class":3645},"# Віртуальне середовище — ніколи не комітимо!\n",[3563,20538,20539],{"class":3565,"line":3700},[3563,20540,15826],{"class":3645},[3563,20542,20543],{"class":3565,"line":3708},[3563,20544,15831],{"class":3645},[3563,20546,20547],{"class":3565,"line":3713},[3563,20548,3577],{"emptyLinePlaceholder":3576},[3563,20550,20551],{"class":3565,"line":3743},[3563,20552,20553],{"class":3645},"# Байткод Python\n",[3563,20555,20556],{"class":3565,"line":3749},[3563,20557,15850],{"class":3645},[3563,20559,20560],{"class":3565,"line":3757},[3563,20561,20562],{"class":3645},"*.pyc\n",[3563,20564,20565],{"class":3565,"line":3762},[3563,20566,15865],{"class":3645},[3563,20568,20569],{"class":3565,"line":3785},[3563,20570,3577],{"emptyLinePlaceholder":3576},[3563,20572,20573],{"class":3565,"line":3791},[3563,20574,20575],{"class":3645},"# Середовища та IDE\n",[3563,20577,20578],{"class":3565,"line":3802},[3563,20579,15951],{"class":3645},[3563,20581,20582],{"class":3565,"line":3807},[3563,20583,20584],{"class":3645},".DS_Store\n",[3563,20586,20587],{"class":3565,"line":3828},[3563,20588,15975],{"class":3645},[3563,20590,20591],{"class":3565,"line":3834},[3563,20592,15980],{"class":3645},[3563,20594,20595],{"class":3565,"line":3840},[3563,20596,20597],{"class":3583},"EOF\n",[3563,20599,20600],{"class":3565,"line":3846},[3563,20601,3577],{"emptyLinePlaceholder":3576},[3563,20603,20604],{"class":3565,"line":3851},[3563,20605,20606],{"class":3569},"# 4. Створити та активувати venv\n",[3563,20608,20609,20611,20613,20615],{"class":3565,"line":5463},[3563,20610,3558],{"class":3606},[3563,20612,11073],{"class":3602},[3563,20614,11076],{"class":3645},[3563,20616,11597],{"class":3645},[3563,20618,20619,20621,20624],{"class":3565,"line":5468},[3563,20620,11033],{"class":3606},[3563,20622,20623],{"class":3645}," .venv\u002Fbin\u002Factivate",[3563,20625,20626],{"class":3569},"  # (.venv) з'явиться у промпті\n",[3563,20628,20629],{"class":3565,"line":5474},[3563,20630,3577],{"emptyLinePlaceholder":3576},[3563,20632,20633],{"class":3565,"line":5480},[3563,20634,20635],{"class":3569},"# 5. Встановити залежності проекту\n",[3563,20637,20638,20640,20642,20644,20646],{"class":3565,"line":5486},[3563,20639,6155],{"class":3606},[3563,20641,11285],{"class":3645},[3563,20643,11288],{"class":3645},[3563,20645,11327],{"class":3645},[3563,20647,12540],{"class":3645},[3563,20649,20650],{"class":3565,"line":5492},[3563,20651,3577],{"emptyLinePlaceholder":3576},[3563,20653,20654],{"class":3565,"line":5498},[3563,20655,20656],{"class":3569},"# 6. Зафіксувати залежності\n",[3563,20658,20659,20661,20663,20665],{"class":3565,"line":5504},[3563,20660,6155],{"class":3606},[3563,20662,11504],{"class":3645},[3563,20664,11507],{"class":3583},[3563,20666,11510],{"class":3645},[3563,20668,20669],{"class":3565,"line":5509},[3563,20670,3577],{"emptyLinePlaceholder":3576},[3563,20672,20673],{"class":3565,"line":5514},[3563,20674,20675],{"class":3569},"# 7. Написати код...\n",[3563,20677,20678],{"class":3565,"line":5520},[3563,20679,3577],{"emptyLinePlaceholder":3576},[3563,20681,20682],{"class":3565,"line":5526},[3563,20683,20684],{"class":3569},"# 8. Перед завершенням — оновити requirements.txt\n",[3563,20686,20687,20689,20691,20693],{"class":3565,"line":5532},[3563,20688,6155],{"class":3606},[3563,20690,11504],{"class":3645},[3563,20692,11507],{"class":3583},[3563,20694,11510],{"class":3645},[3563,20696,20697,20699,20701],{"class":3565,"line":5538},[3563,20698,15188],{"class":3606},[3563,20700,3607],{"class":3645},[3563,20702,11522],{"class":3645},[3563,20704,20705,20707,20710,20712],{"class":3565,"line":5544},[3563,20706,15188],{"class":3606},[3563,20708,20709],{"class":3645}," commit",[3563,20711,11073],{"class":3602},[3563,20713,20714],{"class":3645}," \"chore: update dependencies\"\n",[5969,20716,20717,20720,20721,20723,20724,20726],{},[3406,20718,20719],{},"Критично важливо:"," ніколи не комітьте директорію ",[3398,20722,13811],{}," у Git-репозиторій. Вона містить сотні файлів і повністю залежить від конкретної машини та версії Python. Замість цього комітьте ",[3398,20725,11473],{}," — це єдине, що потрібно колезі або CI\u002FCD для відтворення вашого середовища.",[3461,20728],{},[3389,20730,20732],{"id":20731},"практичний-приклад-від-а-до-я-cli-інструмент-завантаження-та-оптимізації-зображень","Практичний приклад від А до Я: CLI-інструмент завантаження та оптимізації зображень",[3394,20734,20735,20736,3624,20738,3624,20740,3624,20742,3624,20744,4481,20746,20748,20749,3459],{},"Щоб об'єднати всі вивчені концепції (модулі, пакети, ",[3398,20737,10824],{},[3398,20739,3517],{},[3398,20741,3496],{},[3398,20743,19740],{},[3398,20745,20133],{},[3398,20747,19308],{},") в єдине ціле, створимо реальний виробничий інструмент командного рядка — ",[3406,20750,20751],{},"Image Processor CLI",[3468,20753,20755],{"id":20754},"постановка-задачі","Постановка задачі",[3394,20757,20758],{},"Нам потрібно написати утиліту, яка:",[3505,20760,20761,20764,20767,20772,20782],{},[3508,20762,20763],{},"Приймає текстовий файл зі списком URL-адрес зображень.",[3508,20765,20766],{},"Створює ізольовану вихідну директорію для збереження результатів.",[3508,20768,20769,20770,4354],{},"Завантажує зображення з мережі (потребує стороннього пакета ",[3398,20771,5876],{},[3508,20773,20774,20775,20778,20779,4354],{},"Змінює розмір зображень до заданої ширини та конвертує їх у сучасний оптимізований формат ",[3406,20776,20777],{},"WebP"," (потребує стороннього пакета ",[3398,20780,20781],{},"Pillow",[3508,20783,20784,20785,20788],{},"Збирає детальну статистику про хід виконання (успіх, помилка мережі, помилка обробки) за допомогою ",[3398,20786,20787],{},"collections.Counter"," та повертає відповідний код виходу в систему.",[3468,20790,20792],{"id":20791},"архітектура-проекту","Архітектура проекту",[3394,20794,20795],{},"Проект буде організований як повноцінний пакет Python з такою структурою директорій:",[3551,20797,20798,21097,21107,21253,21524,21534,21690],{},[3554,20799,20802],{"className":3556,"code":20800,"filename":20801,"language":3558,"meta":3559,"style":3559},"# Фасад пакета. Визначає версію та експортує головну функцію процесу.\n__version__ = \"1.0.0\"\n__all__ = [\"process_images\"]\n\nfrom .core.downloader import download_image\nfrom .core.converter import optimize_image\n\ndef process_images(urls: list, output_dir: str, width: int) -> dict:\n    \"\"\"Високорівнева функція-фасад для оркестрації завантаження та обробки.\"\"\"\n    from collections import Counter\n    from pathlib import Path\n\n    stats = Counter()\n    out_path = Path(output_dir)\n    out_path.mkdir(parents=True, exist_ok=True)\n\n    for i, url in enumerate(urls, 1):\n        try:\n            # Завантаження\n            img_bytes = download_image(url)\n            # Конвертація\n            dest_file = out_path \u002F f\"image_{i}.webp\"\n            optimize_image(img_bytes, dest_file, width)\n            stats[\"success\"] += 1\n        except ConnectionError:\n            stats[\"network_error\"] += 1\n        except Exception:\n            stats[\"processing_error\"] += 1\n\n    return dict(stats)\n","image_processor\u002F__init__.py",[3398,20803,20804,20809,20817,20828,20832,20844,20856,20860,20900,20905,20916,20926,20930,20935,20940,20961,20965,20983,20990,20995,21000,21005,21024,21029,21042,21052,21063,21072,21083,21087],{"__ignoreMap":3559},[3563,20805,20806],{"class":3565,"line":3566},[3563,20807,20808],{"class":3569},"# Фасад пакета. Визначає версію та експортує головну функцію процесу.\n",[3563,20810,20811,20813,20815],{"class":3565,"line":3573},[3563,20812,8868],{"class":3613},[3563,20814,8871],{"class":3583},[3563,20816,8874],{"class":3645},[3563,20818,20819,20821,20823,20826],{"class":3565,"line":3580},[3563,20820,5295],{"class":3613},[3563,20822,8890],{"class":3583},[3563,20824,20825],{"class":3645},"\"process_images\"",[3563,20827,6347],{"class":3583},[3563,20829,20830],{"class":3565,"line":3594},[3563,20831,3577],{"emptyLinePlaceholder":3576},[3563,20833,20834,20836,20839,20841],{"class":3565,"line":3599},[3563,20835,4907],{"class":3652},[3563,20837,20838],{"class":3583}," .core.downloader ",[3563,20840,3905],{"class":3652},[3563,20842,20843],{"class":3583}," download_image\n",[3563,20845,20846,20848,20851,20853],{"class":3565,"line":3642},[3563,20847,4907],{"class":3652},[3563,20849,20850],{"class":3583}," .core.converter ",[3563,20852,3905],{"class":3652},[3563,20854,20855],{"class":3583}," optimize_image\n",[3563,20857,20858],{"class":3565,"line":3649},[3563,20859,3577],{"emptyLinePlaceholder":3576},[3563,20861,20862,20864,20867,20869,20872,20874,20876,20878,20881,20883,20885,20887,20890,20892,20894,20896,20898],{"class":3565,"line":3659},[3563,20863,3603],{"class":3602},[3563,20865,20866],{"class":3606}," process_images",[3563,20868,3610],{"class":3583},[3563,20870,20871],{"class":3613},"urls",[3563,20873,3617],{"class":3583},[3563,20875,4666],{"class":3620},[3563,20877,3624],{"class":3583},[3563,20879,20880],{"class":3613},"output_dir",[3563,20882,3617],{"class":3583},[3563,20884,4145],{"class":3620},[3563,20886,3624],{"class":3583},[3563,20888,20889],{"class":3613},"width",[3563,20891,3617],{"class":3583},[3563,20893,3867],{"class":3620},[3563,20895,3634],{"class":3583},[3563,20897,4276],{"class":3620},[3563,20899,3639],{"class":3583},[3563,20901,20902],{"class":3565,"line":3664},[3563,20903,20904],{"class":3645},"    \"\"\"Високорівнева функція-фасад для оркестрації завантаження та обробки.\"\"\"\n",[3563,20906,20907,20910,20912,20914],{"class":3565,"line":3694},[3563,20908,20909],{"class":3652},"    from",[3563,20911,19854],{"class":3583},[3563,20913,3905],{"class":3652},[3563,20915,20159],{"class":3583},[3563,20917,20918,20920,20922,20924],{"class":3565,"line":3700},[3563,20919,20909],{"class":3652},[3563,20921,19369],{"class":3583},[3563,20923,3905],{"class":3652},[3563,20925,19374],{"class":3583},[3563,20927,20928],{"class":3565,"line":3708},[3563,20929,3577],{"emptyLinePlaceholder":3576},[3563,20931,20932],{"class":3565,"line":3713},[3563,20933,20934],{"class":3583},"    stats = Counter()\n",[3563,20936,20937],{"class":3565,"line":3743},[3563,20938,20939],{"class":3583},"    out_path = Path(output_dir)\n",[3563,20941,20942,20945,20947,20949,20951,20953,20955,20957,20959],{"class":3565,"line":3749},[3563,20943,20944],{"class":3583},"    out_path.mkdir(",[3563,20946,19522],{"class":3613},[3563,20948,7810],{"class":3583},[3563,20950,6476],{"class":3602},[3563,20952,3624],{"class":3583},[3563,20954,19531],{"class":3613},[3563,20956,7810],{"class":3583},[3563,20958,6476],{"class":3602},[3563,20960,3936],{"class":3583},[3563,20962,20963],{"class":3565,"line":3757},[3563,20964,3577],{"emptyLinePlaceholder":3576},[3563,20966,20967,20969,20972,20974,20976,20979,20981],{"class":3565,"line":3762},[3563,20968,9211],{"class":3652},[3563,20970,20971],{"class":3583}," i, url ",[3563,20973,3883],{"class":3652},[3563,20975,5653],{"class":3606},[3563,20977,20978],{"class":3583},"(urls, ",[3563,20980,5061],{"class":3587},[3563,20982,7337],{"class":3583},[3563,20984,20985,20988],{"class":3565,"line":3785},[3563,20986,20987],{"class":3652},"        try",[3563,20989,3639],{"class":3583},[3563,20991,20992],{"class":3565,"line":3791},[3563,20993,20994],{"class":3569},"            # Завантаження\n",[3563,20996,20997],{"class":3565,"line":3802},[3563,20998,20999],{"class":3583},"            img_bytes = download_image(url)\n",[3563,21001,21002],{"class":3565,"line":3807},[3563,21003,21004],{"class":3569},"            # Конвертація\n",[3563,21006,21007,21010,21012,21015,21017,21019,21021],{"class":3565,"line":3828},[3563,21008,21009],{"class":3583},"            dest_file = out_path \u002F ",[3563,21011,3960],{"class":3602},[3563,21013,21014],{"class":3645},"\"image_",[3563,21016,3966],{"class":3602},[3563,21018,5673],{"class":3583},[3563,21020,3972],{"class":3602},[3563,21022,21023],{"class":3645},".webp\"\n",[3563,21025,21026],{"class":3565,"line":3834},[3563,21027,21028],{"class":3583},"            optimize_image(img_bytes, dest_file, width)\n",[3563,21030,21031,21034,21037,21040],{"class":3565,"line":3840},[3563,21032,21033],{"class":3583},"            stats[",[3563,21035,21036],{"class":3645},"\"success\"",[3563,21038,21039],{"class":3583},"] += ",[3563,21041,6872],{"class":3587},[3563,21043,21044,21047,21050],{"class":3565,"line":3846},[3563,21045,21046],{"class":3652},"        except",[3563,21048,21049],{"class":3620}," ConnectionError",[3563,21051,3639],{"class":3583},[3563,21053,21054,21056,21059,21061],{"class":3565,"line":3851},[3563,21055,21033],{"class":3583},[3563,21057,21058],{"class":3645},"\"network_error\"",[3563,21060,21039],{"class":3583},[3563,21062,6872],{"class":3587},[3563,21064,21065,21067,21070],{"class":3565,"line":5463},[3563,21066,21046],{"class":3652},[3563,21068,21069],{"class":3620}," Exception",[3563,21071,3639],{"class":3583},[3563,21073,21074,21076,21079,21081],{"class":3565,"line":5468},[3563,21075,21033],{"class":3583},[3563,21077,21078],{"class":3645},"\"processing_error\"",[3563,21080,21039],{"class":3583},[3563,21082,6872],{"class":3587},[3563,21084,21085],{"class":3565,"line":5474},[3563,21086,3577],{"emptyLinePlaceholder":3576},[3563,21088,21089,21091,21094],{"class":3565,"line":5480},[3563,21090,3653],{"class":3652},[3563,21092,21093],{"class":3620}," dict",[3563,21095,21096],{"class":3583},"(stats)\n",[3554,21098,21101],{"className":3556,"code":21099,"filename":21100,"language":3558,"meta":3559,"style":3559},"# Ініціалізація підпакета core\n","image_processor\u002Fcore\u002F__init__.py",[3398,21102,21103],{"__ignoreMap":3559},[3563,21104,21105],{"class":3565,"line":3566},[3563,21106,21099],{"class":3569},[3554,21108,21111],{"className":3556,"code":21109,"filename":21110,"language":3558,"meta":3559,"style":3559},"import requests\n\ndef download_image(url: str) -> bytes:\n    \"\"\"Завантажує зображення за посиланням і повертає сирі байти.\"\"\"\n    try:\n        response = requests.get(url, timeout=10)\n        response.raise_for_status()  # підніме HTTPError при статус-кодах 4xx\u002F5xx\n        return response.content\n    except requests.RequestException as e:\n        # Логуємо помилку для налагодження\n        print(f\"Помилка мережі при завантаженні {url}: {e}\")\n        raise ConnectionError(f\"Не вдалося завантажити зображення: {e}\")\n","image_processor\u002Fcore\u002Fdownloader.py",[3398,21112,21113,21119,21123,21145,21150,21156,21170,21178,21185,21196,21201,21230],{"__ignoreMap":3559},[3563,21114,21115,21117],{"class":3565,"line":3566},[3563,21116,3905],{"class":3652},[3563,21118,11368],{"class":3583},[3563,21120,21121],{"class":3565,"line":3573},[3563,21122,3577],{"emptyLinePlaceholder":3576},[3563,21124,21125,21127,21130,21132,21134,21136,21138,21140,21143],{"class":3565,"line":3580},[3563,21126,3603],{"class":3602},[3563,21128,21129],{"class":3606}," download_image",[3563,21131,3610],{"class":3583},[3563,21133,6853],{"class":3613},[3563,21135,3617],{"class":3583},[3563,21137,4145],{"class":3620},[3563,21139,3634],{"class":3583},[3563,21141,21142],{"class":3620},"bytes",[3563,21144,3639],{"class":3583},[3563,21146,21147],{"class":3565,"line":3594},[3563,21148,21149],{"class":3645},"    \"\"\"Завантажує зображення за посиланням і повертає сирі байти.\"\"\"\n",[3563,21151,21152,21154],{"class":3565,"line":3599},[3563,21153,7929],{"class":3652},[3563,21155,3639],{"class":3583},[3563,21157,21158,21161,21164,21166,21168],{"class":3565,"line":3642},[3563,21159,21160],{"class":3583},"        response = requests.get(url, ",[3563,21162,21163],{"class":3613},"timeout",[3563,21165,7810],{"class":3583},[3563,21167,3928],{"class":3587},[3563,21169,3936],{"class":3583},[3563,21171,21172,21175],{"class":3565,"line":3649},[3563,21173,21174],{"class":3583},"        response.raise_for_status()  ",[3563,21176,21177],{"class":3569},"# підніме HTTPError при статус-кодах 4xx\u002F5xx\n",[3563,21179,21180,21182],{"class":3565,"line":3659},[3563,21181,7673],{"class":3652},[3563,21183,21184],{"class":3583}," response.content\n",[3563,21186,21187,21189,21192,21194],{"class":3565,"line":3664},[3563,21188,7991],{"class":3652},[3563,21190,21191],{"class":3583}," requests.RequestException ",[3563,21193,4991],{"class":3652},[3563,21195,8000],{"class":3583},[3563,21197,21198],{"class":3565,"line":3694},[3563,21199,21200],{"class":3569},"        # Логуємо помилку для налагодження\n",[3563,21202,21203,21205,21207,21209,21212,21214,21216,21218,21220,21222,21224,21226,21228],{"class":3565,"line":3700},[3563,21204,4572],{"class":3606},[3563,21206,3610],{"class":3583},[3563,21208,3960],{"class":3602},[3563,21210,21211],{"class":3645},"\"Помилка мережі при завантаженні ",[3563,21213,3966],{"class":3602},[3563,21215,6853],{"class":3583},[3563,21217,3972],{"class":3602},[3563,21219,3617],{"class":3645},[3563,21221,3966],{"class":3602},[3563,21223,8016],{"class":3583},[3563,21225,3972],{"class":3602},[3563,21227,3975],{"class":3645},[3563,21229,3936],{"class":3583},[3563,21231,21232,21234,21236,21238,21240,21243,21245,21247,21249,21251],{"class":3565,"line":3708},[3563,21233,9314],{"class":3652},[3563,21235,21049],{"class":3620},[3563,21237,3610],{"class":3583},[3563,21239,3960],{"class":3602},[3563,21241,21242],{"class":3645},"\"Не вдалося завантажити зображення: ",[3563,21244,3966],{"class":3602},[3563,21246,8016],{"class":3583},[3563,21248,3972],{"class":3602},[3563,21250,3975],{"class":3645},[3563,21252,3936],{"class":3583},[3554,21254,21257],{"className":3556,"code":21255,"filename":21256,"language":3558,"meta":3559,"style":3559},"import io\nfrom PIL import Image\nfrom pathlib import Path\n\ndef optimize_image(image_bytes: bytes, output_path: Path, target_width: int) -> None:\n    \"\"\"Змінює розмір зображення (зберігаючи пропорції) та конвертує в WebP.\"\"\"\n    try:\n        # Читаємо зображення з байтового потоку в пам'яті\n        with Image.open(io.BytesIO(image_bytes)) as img:\n            # Розрахунок нової висоти зі збереженням пропорцій\n            width_percent = target_width \u002F float(img.size[0])\n            target_height = int(float(img.size[1]) * float(width_percent))\n\n            # Зміна розміру\n            resized_img = img.resize((target_width, target_height), Image.Resampling.LANCZOS)\n\n            # Збереження у форматі WebP з оптимізацією якості\n            resized_img.save(output_path, format=\"WEBP\", quality=85)\n            print(f\"Збережено оптимізоване зображення: {output_path}\")\n    except Exception as e:\n        print(f\"Помилка обробки зображення: {e}\")\n        raise RuntimeError(f\"Не вдалося обробити зображення: {e}\")\n","image_processor\u002Fcore\u002Fconverter.py",[3398,21258,21259,21266,21278,21288,21292,21328,21333,21339,21344,21357,21362,21376,21399,21403,21408,21413,21417,21422,21447,21469,21479,21500],{"__ignoreMap":3559},[3563,21260,21261,21263],{"class":3565,"line":3566},[3563,21262,3905],{"class":3652},[3563,21264,21265],{"class":3583}," io\n",[3563,21267,21268,21270,21273,21275],{"class":3565,"line":3573},[3563,21269,4907],{"class":3652},[3563,21271,21272],{"class":3583}," PIL ",[3563,21274,3905],{"class":3652},[3563,21276,21277],{"class":3583}," Image\n",[3563,21279,21280,21282,21284,21286],{"class":3565,"line":3580},[3563,21281,4907],{"class":3652},[3563,21283,19369],{"class":3583},[3563,21285,3905],{"class":3652},[3563,21287,19374],{"class":3583},[3563,21289,21290],{"class":3565,"line":3594},[3563,21291,3577],{"emptyLinePlaceholder":3576},[3563,21293,21294,21296,21299,21301,21304,21306,21308,21310,21312,21315,21318,21320,21322,21324,21326],{"class":3565,"line":3599},[3563,21295,3603],{"class":3602},[3563,21297,21298],{"class":3606}," optimize_image",[3563,21300,3610],{"class":3583},[3563,21302,21303],{"class":3613},"image_bytes",[3563,21305,3617],{"class":3583},[3563,21307,21142],{"class":3620},[3563,21309,3624],{"class":3583},[3563,21311,7766],{"class":3613},[3563,21313,21314],{"class":3583},": Path, ",[3563,21316,21317],{"class":3613},"target_width",[3563,21319,3617],{"class":3583},[3563,21321,3867],{"class":3620},[3563,21323,3634],{"class":3583},[3563,21325,6862],{"class":3602},[3563,21327,3639],{"class":3583},[3563,21329,21330],{"class":3565,"line":3642},[3563,21331,21332],{"class":3645},"    \"\"\"Змінює розмір зображення (зберігаючи пропорції) та конвертує в WebP.\"\"\"\n",[3563,21334,21335,21337],{"class":3565,"line":3649},[3563,21336,7929],{"class":3652},[3563,21338,3639],{"class":3583},[3563,21340,21341],{"class":3565,"line":3659},[3563,21342,21343],{"class":3569},"        # Читаємо зображення з байтового потоку в пам'яті\n",[3563,21345,21346,21349,21352,21354],{"class":3565,"line":3664},[3563,21347,21348],{"class":3652},"        with",[3563,21350,21351],{"class":3583}," Image.open(io.BytesIO(image_bytes)) ",[3563,21353,4991],{"class":3652},[3563,21355,21356],{"class":3583}," img:\n",[3563,21358,21359],{"class":3565,"line":3694},[3563,21360,21361],{"class":3569},"            # Розрахунок нової висоти зі збереженням пропорцій\n",[3563,21363,21364,21367,21369,21372,21374],{"class":3565,"line":3700},[3563,21365,21366],{"class":3583},"            width_percent = target_width \u002F ",[3563,21368,3621],{"class":3620},[3563,21370,21371],{"class":3583},"(img.size[",[3563,21373,5922],{"class":3587},[3563,21375,5072],{"class":3583},[3563,21377,21378,21381,21383,21385,21387,21389,21391,21394,21396],{"class":3565,"line":3708},[3563,21379,21380],{"class":3583},"            target_height = ",[3563,21382,3867],{"class":3620},[3563,21384,3610],{"class":3583},[3563,21386,3621],{"class":3620},[3563,21388,21371],{"class":3583},[3563,21390,5061],{"class":3587},[3563,21392,21393],{"class":3583},"]) * ",[3563,21395,3621],{"class":3620},[3563,21397,21398],{"class":3583},"(width_percent))\n",[3563,21400,21401],{"class":3565,"line":3713},[3563,21402,3577],{"emptyLinePlaceholder":3576},[3563,21404,21405],{"class":3565,"line":3743},[3563,21406,21407],{"class":3569},"            # Зміна розміру\n",[3563,21409,21410],{"class":3565,"line":3749},[3563,21411,21412],{"class":3583},"            resized_img = img.resize((target_width, target_height), Image.Resampling.LANCZOS)\n",[3563,21414,21415],{"class":3565,"line":3757},[3563,21416,3577],{"emptyLinePlaceholder":3576},[3563,21418,21419],{"class":3565,"line":3762},[3563,21420,21421],{"class":3569},"            # Збереження у форматі WebP з оптимізацією якості\n",[3563,21423,21424,21427,21430,21432,21435,21437,21440,21442,21445],{"class":3565,"line":3785},[3563,21425,21426],{"class":3583},"            resized_img.save(output_path, ",[3563,21428,21429],{"class":3613},"format",[3563,21431,7810],{"class":3583},[3563,21433,21434],{"class":3645},"\"WEBP\"",[3563,21436,3624],{"class":3583},[3563,21438,21439],{"class":3613},"quality",[3563,21441,7810],{"class":3583},[3563,21443,21444],{"class":3587},"85",[3563,21446,3936],{"class":3583},[3563,21448,21449,21452,21454,21456,21459,21461,21463,21465,21467],{"class":3565,"line":3791},[3563,21450,21451],{"class":3606},"            print",[3563,21453,3610],{"class":3583},[3563,21455,3960],{"class":3602},[3563,21457,21458],{"class":3645},"\"Збережено оптимізоване зображення: ",[3563,21460,3966],{"class":3602},[3563,21462,7766],{"class":3583},[3563,21464,3972],{"class":3602},[3563,21466,3975],{"class":3645},[3563,21468,3936],{"class":3583},[3563,21470,21471,21473,21475,21477],{"class":3565,"line":3802},[3563,21472,7991],{"class":3652},[3563,21474,21069],{"class":3620},[3563,21476,7997],{"class":3652},[3563,21478,8000],{"class":3583},[3563,21480,21481,21483,21485,21487,21490,21492,21494,21496,21498],{"class":3565,"line":3807},[3563,21482,4572],{"class":3606},[3563,21484,3610],{"class":3583},[3563,21486,3960],{"class":3602},[3563,21488,21489],{"class":3645},"\"Помилка обробки зображення: ",[3563,21491,3966],{"class":3602},[3563,21493,8016],{"class":3583},[3563,21495,3972],{"class":3602},[3563,21497,3975],{"class":3645},[3563,21499,3936],{"class":3583},[3563,21501,21502,21504,21507,21509,21511,21514,21516,21518,21520,21522],{"class":3565,"line":3828},[3563,21503,9314],{"class":3652},[3563,21505,21506],{"class":3620}," RuntimeError",[3563,21508,3610],{"class":3583},[3563,21510,3960],{"class":3602},[3563,21512,21513],{"class":3645},"\"Не вдалося обробити зображення: ",[3563,21515,3966],{"class":3602},[3563,21517,8016],{"class":3583},[3563,21519,3972],{"class":3602},[3563,21521,3975],{"class":3645},[3563,21523,3936],{"class":3583},[3554,21525,21528],{"className":3556,"code":21526,"filename":21527,"language":3558,"meta":3559,"style":3559},"# Ініціалізація підпакета utils\n","image_processor\u002Futils\u002F__init__.py",[3398,21529,21530],{"__ignoreMap":3559},[3563,21531,21532],{"class":3565,"line":3566},[3563,21533,21526],{"class":3569},[3554,21535,21538],{"className":3556,"code":21536,"filename":21537,"language":3558,"meta":3559,"style":3559},"from pathlib import Path\n\ndef load_urls_from_file(file_path: str) -> list:\n    \"\"\"Читає список URL-адрес із текстового файлу, очищаючи порожні рядки.\"\"\"\n    path = Path(file_path)\n    if not path.is_file():\n        raise FileNotFoundError(f\"Файл конфігурації не знайдено за шляхом: {file_path}\")\n\n    with open(path, \"r\", encoding=\"utf-8\") as f:\n        # Читаємо рядки, прибираємо пробіли та фільтруємо порожні\n        return [line.strip() for line in f if line.strip() and not line.startswith(\"#\")]\n","image_processor\u002Futils\u002Fhelpers.py",[3398,21539,21540,21550,21554,21576,21581,21586,21595,21618,21622,21650,21655],{"__ignoreMap":3559},[3563,21541,21542,21544,21546,21548],{"class":3565,"line":3566},[3563,21543,4907],{"class":3652},[3563,21545,19369],{"class":3583},[3563,21547,3905],{"class":3652},[3563,21549,19374],{"class":3583},[3563,21551,21552],{"class":3565,"line":3573},[3563,21553,3577],{"emptyLinePlaceholder":3576},[3563,21555,21556,21558,21561,21563,21566,21568,21570,21572,21574],{"class":3565,"line":3580},[3563,21557,3603],{"class":3602},[3563,21559,21560],{"class":3606}," load_urls_from_file",[3563,21562,3610],{"class":3583},[3563,21564,21565],{"class":3613},"file_path",[3563,21567,3617],{"class":3583},[3563,21569,4145],{"class":3620},[3563,21571,3634],{"class":3583},[3563,21573,4666],{"class":3620},[3563,21575,3639],{"class":3583},[3563,21577,21578],{"class":3565,"line":3594},[3563,21579,21580],{"class":3645},"    \"\"\"Читає список URL-адрес із текстового файлу, очищаючи порожні рядки.\"\"\"\n",[3563,21582,21583],{"class":3565,"line":3599},[3563,21584,21585],{"class":3583},"    path = Path(file_path)\n",[3563,21587,21588,21590,21592],{"class":3565,"line":3642},[3563,21589,7854],{"class":3652},[3563,21591,16776],{"class":3602},[3563,21593,21594],{"class":3583}," path.is_file():\n",[3563,21596,21597,21599,21601,21603,21605,21608,21610,21612,21614,21616],{"class":3565,"line":3649},[3563,21598,9314],{"class":3652},[3563,21600,7994],{"class":3620},[3563,21602,3610],{"class":3583},[3563,21604,3960],{"class":3602},[3563,21606,21607],{"class":3645},"\"Файл конфігурації не знайдено за шляхом: ",[3563,21609,3966],{"class":3602},[3563,21611,21565],{"class":3583},[3563,21613,3972],{"class":3602},[3563,21615,3975],{"class":3645},[3563,21617,3936],{"class":3583},[3563,21619,21620],{"class":3565,"line":3659},[3563,21621,3577],{"emptyLinePlaceholder":3576},[3563,21623,21624,21626,21628,21631,21634,21636,21639,21641,21644,21646,21648],{"class":3565,"line":3664},[3563,21625,7657],{"class":3652},[3563,21627,7660],{"class":3606},[3563,21629,21630],{"class":3583},"(path, ",[3563,21632,21633],{"class":3645},"\"r\"",[3563,21635,3624],{"class":3583},[3563,21637,21638],{"class":3613},"encoding",[3563,21640,7810],{"class":3583},[3563,21642,21643],{"class":3645},"\"utf-8\"",[3563,21645,4005],{"class":3583},[3563,21647,4991],{"class":3652},[3563,21649,7668],{"class":3583},[3563,21651,21652],{"class":3565,"line":3694},[3563,21653,21654],{"class":3569},"        # Читаємо рядки, прибираємо пробіли та фільтруємо порожні\n",[3563,21656,21657,21659,21662,21664,21667,21669,21672,21674,21677,21680,21682,21685,21688],{"class":3565,"line":3700},[3563,21658,7673],{"class":3652},[3563,21660,21661],{"class":3583}," [line.strip() ",[3563,21663,3877],{"class":3652},[3563,21665,21666],{"class":3583}," line ",[3563,21668,3883],{"class":3652},[3563,21670,21671],{"class":3583}," f ",[3563,21673,7464],{"class":3652},[3563,21675,21676],{"class":3583}," line.strip() ",[3563,21678,21679],{"class":3602},"and",[3563,21681,16776],{"class":3602},[3563,21683,21684],{"class":3583}," line.startswith(",[3563,21686,21687],{"class":3645},"\"#\"",[3563,21689,7741],{"class":3583},[3554,21691,21694],{"className":3556,"code":21692,"filename":21693,"language":3558,"meta":3559,"style":3559},"import sys\nfrom pathlib import Path\nfrom image_processor.utils.helpers import load_urls_from_file\nfrom image_processor import process_images\n\ndef main() -> int:\n    \"\"\"\n    Головна точка входу.\n    Використання: python -m image_processor.main \u003Curls.txt> \u003Coutput_dir> [width]\n    Повертає 0 при успіху, 1 при загальній помилці конфігурації.\n    \"\"\"\n    if len(sys.argv) \u003C 3:\n        print(\"Помилка: Недостатньо аргументів!\")\n        print(f\"Використання: python -m {__package__}.main \u003Curls.txt> \u003Coutput_dir> [width]\")\n        return 1\n\n    urls_file = sys.argv[1]\n    output_dir = sys.argv[2]\n    # Опціональний параметр ширини, за замовчуванням 800px\n    target_width = int(sys.argv[3]) if len(sys.argv) > 3 else 800\n\n    try:\n        # Завантаження лінків через хелпер\n        urls = load_urls_from_file(urls_file)\n        if not urls:\n            print(f\"Попередження: Файл {urls_file} не містить URL для обробки.\")\n            return 0\n\n        print(f\"Знайдено {len(urls)} посилань. Починаємо обробку...\")\n\n        # Запуск оркестратора з фасаду\n        stats = process_images(urls, output_dir, target_width)\n\n        print(\"\\n=== Статистика обробки ===\")\n        print(f\"  Успішно оброблено: {stats.get('success', 0)}\")\n        print(f\"  Помилок мережі:    {stats.get('network_error', 0)}\")\n        print(f\"  Помилок обробки:   {stats.get('processing_error', 0)}\")\n\n        return 0\n\n    except FileNotFoundError as e:\n        print(f\"Помилка конфігурації: {e}\")\n        return 1\n    except ValueError:\n        print(\"Помилка: Параметр ширини має бути цілим числом!\")\n        return 1\n\nif __name__ == \"__main__\":\n    # Повертаємо статус-код оболонці\n    sys.exit(main())\n","image_processor\u002Fmain.py",[3398,21695,21696,21702,21712,21724,21736,21740,21752,21756,21761,21766,21771,21775,21788,21799,21822,21828,21832,21841,21850,21855,21885,21889,21895,21900,21905,21914,21937,21943,21947,21972,21976,21981,21986,21990,22005,22036,22066,22096,22100,22106,22110,22120,22141,22147,22155,22166,22172,22177,22190,22196],{"__ignoreMap":3559},[3563,21697,21698,21700],{"class":3565,"line":3566},[3563,21699,3905],{"class":3652},[3563,21701,4857],{"class":3583},[3563,21703,21704,21706,21708,21710],{"class":3565,"line":3573},[3563,21705,4907],{"class":3652},[3563,21707,19369],{"class":3583},[3563,21709,3905],{"class":3652},[3563,21711,19374],{"class":3583},[3563,21713,21714,21716,21719,21721],{"class":3565,"line":3580},[3563,21715,4907],{"class":3652},[3563,21717,21718],{"class":3583}," image_processor.utils.helpers ",[3563,21720,3905],{"class":3652},[3563,21722,21723],{"class":3583}," load_urls_from_file\n",[3563,21725,21726,21728,21731,21733],{"class":3565,"line":3594},[3563,21727,4907],{"class":3652},[3563,21729,21730],{"class":3583}," image_processor ",[3563,21732,3905],{"class":3652},[3563,21734,21735],{"class":3583}," process_images\n",[3563,21737,21738],{"class":3565,"line":3599},[3563,21739,3577],{"emptyLinePlaceholder":3576},[3563,21741,21742,21744,21746,21748,21750],{"class":3565,"line":3642},[3563,21743,3603],{"class":3602},[3563,21745,7825],{"class":3606},[3563,21747,6937],{"class":3583},[3563,21749,3867],{"class":3620},[3563,21751,3639],{"class":3583},[3563,21753,21754],{"class":3565,"line":3649},[3563,21755,3831],{"class":3645},[3563,21757,21758],{"class":3565,"line":3659},[3563,21759,21760],{"class":3645},"    Головна точка входу.\n",[3563,21762,21763],{"class":3565,"line":3664},[3563,21764,21765],{"class":3645},"    Використання: python -m image_processor.main \u003Curls.txt> \u003Coutput_dir> [width]\n",[3563,21767,21768],{"class":3565,"line":3694},[3563,21769,21770],{"class":3645},"    Повертає 0 при успіху, 1 при загальній помилці конфігурації.\n",[3563,21772,21773],{"class":3565,"line":3700},[3563,21774,3831],{"class":3645},[3563,21776,21777,21779,21781,21784,21786],{"class":3565,"line":3708},[3563,21778,7854],{"class":3652},[3563,21780,7857],{"class":3606},[3563,21782,21783],{"class":3583},"(sys.argv) \u003C ",[3563,21785,5051],{"class":3587},[3563,21787,3639],{"class":3583},[3563,21789,21790,21792,21794,21797],{"class":3565,"line":3713},[3563,21791,4572],{"class":3606},[3563,21793,3610],{"class":3583},[3563,21795,21796],{"class":3645},"\"Помилка: Недостатньо аргументів!\"",[3563,21798,3936],{"class":3583},[3563,21800,21801,21803,21805,21807,21810,21812,21815,21817,21820],{"class":3565,"line":3743},[3563,21802,4572],{"class":3606},[3563,21804,3610],{"class":3583},[3563,21806,3960],{"class":3602},[3563,21808,21809],{"class":3645},"\"Використання: python -m ",[3563,21811,3966],{"class":3602},[3563,21813,21814],{"class":3613},"__package__",[3563,21816,3972],{"class":3602},[3563,21818,21819],{"class":3645},".main \u003Curls.txt> \u003Coutput_dir> [width]\"",[3563,21821,3936],{"class":3583},[3563,21823,21824,21826],{"class":3565,"line":3749},[3563,21825,7673],{"class":3652},[3563,21827,7898],{"class":3587},[3563,21829,21830],{"class":3565,"line":3757},[3563,21831,3577],{"emptyLinePlaceholder":3576},[3563,21833,21834,21837,21839],{"class":3565,"line":3762},[3563,21835,21836],{"class":3583},"    urls_file = sys.argv[",[3563,21838,5061],{"class":3587},[3563,21840,6347],{"class":3583},[3563,21842,21843,21846,21848],{"class":3565,"line":3785},[3563,21844,21845],{"class":3583},"    output_dir = sys.argv[",[3563,21847,4209],{"class":3587},[3563,21849,6347],{"class":3583},[3563,21851,21852],{"class":3565,"line":3791},[3563,21853,21854],{"class":3569},"    # Опціональний параметр ширини, за замовчуванням 800px\n",[3563,21856,21857,21860,21862,21865,21867,21870,21872,21874,21877,21879,21882],{"class":3565,"line":3802},[3563,21858,21859],{"class":3583},"    target_width = ",[3563,21861,3867],{"class":3620},[3563,21863,21864],{"class":3583},"(sys.argv[",[3563,21866,5051],{"class":3587},[3563,21868,21869],{"class":3583},"]) ",[3563,21871,7464],{"class":3652},[3563,21873,7857],{"class":3606},[3563,21875,21876],{"class":3583},"(sys.argv) > ",[3563,21878,5051],{"class":3587},[3563,21880,21881],{"class":3652}," else",[3563,21883,21884],{"class":3587}," 800\n",[3563,21886,21887],{"class":3565,"line":3807},[3563,21888,3577],{"emptyLinePlaceholder":3576},[3563,21890,21891,21893],{"class":3565,"line":3828},[3563,21892,7929],{"class":3652},[3563,21894,3639],{"class":3583},[3563,21896,21897],{"class":3565,"line":3834},[3563,21898,21899],{"class":3569},"        # Завантаження лінків через хелпер\n",[3563,21901,21902],{"class":3565,"line":3840},[3563,21903,21904],{"class":3583},"        urls = load_urls_from_file(urls_file)\n",[3563,21906,21907,21909,21911],{"class":3565,"line":3846},[3563,21908,9224],{"class":3652},[3563,21910,16776],{"class":3602},[3563,21912,21913],{"class":3583}," urls:\n",[3563,21915,21916,21918,21920,21922,21925,21927,21930,21932,21935],{"class":3565,"line":3851},[3563,21917,21451],{"class":3606},[3563,21919,3610],{"class":3583},[3563,21921,3960],{"class":3602},[3563,21923,21924],{"class":3645},"\"Попередження: Файл ",[3563,21926,3966],{"class":3602},[3563,21928,21929],{"class":3583},"urls_file",[3563,21931,3972],{"class":3602},[3563,21933,21934],{"class":3645}," не містить URL для обробки.\"",[3563,21936,3936],{"class":3583},[3563,21938,21939,21941],{"class":3565,"line":5463},[3563,21940,9237],{"class":3652},[3563,21942,7986],{"class":3587},[3563,21944,21945],{"class":3565,"line":5468},[3563,21946,3577],{"emptyLinePlaceholder":3576},[3563,21948,21949,21951,21953,21955,21958,21960,21962,21965,21967,21970],{"class":3565,"line":5474},[3563,21950,4572],{"class":3606},[3563,21952,3610],{"class":3583},[3563,21954,3960],{"class":3602},[3563,21956,21957],{"class":3645},"\"Знайдено ",[3563,21959,3966],{"class":3602},[3563,21961,5629],{"class":3606},[3563,21963,21964],{"class":3583},"(urls)",[3563,21966,3972],{"class":3602},[3563,21968,21969],{"class":3645}," посилань. Починаємо обробку...\"",[3563,21971,3936],{"class":3583},[3563,21973,21974],{"class":3565,"line":5480},[3563,21975,3577],{"emptyLinePlaceholder":3576},[3563,21977,21978],{"class":3565,"line":5486},[3563,21979,21980],{"class":3569},"        # Запуск оркестратора з фасаду\n",[3563,21982,21983],{"class":3565,"line":5492},[3563,21984,21985],{"class":3583},"        stats = process_images(urls, output_dir, target_width)\n",[3563,21987,21988],{"class":3565,"line":5498},[3563,21989,3577],{"emptyLinePlaceholder":3576},[3563,21991,21992,21994,21996,21998,22000,22003],{"class":3565,"line":5504},[3563,21993,4572],{"class":3606},[3563,21995,3610],{"class":3583},[3563,21997,3975],{"class":3645},[3563,21999,4647],{"class":4646},[3563,22001,22002],{"class":3645},"=== Статистика обробки ===\"",[3563,22004,3936],{"class":3583},[3563,22006,22007,22009,22011,22013,22016,22018,22021,22024,22026,22028,22030,22032,22034],{"class":3565,"line":5509},[3563,22008,4572],{"class":3606},[3563,22010,3610],{"class":3583},[3563,22012,3960],{"class":3602},[3563,22014,22015],{"class":3645},"\"  Успішно оброблено: ",[3563,22017,3966],{"class":3602},[3563,22019,22020],{"class":3583},"stats.get(",[3563,22022,22023],{"class":3645},"'success'",[3563,22025,3624],{"class":3583},[3563,22027,5922],{"class":3587},[3563,22029,3518],{"class":3583},[3563,22031,3972],{"class":3602},[3563,22033,3975],{"class":3645},[3563,22035,3936],{"class":3583},[3563,22037,22038,22040,22042,22044,22047,22049,22051,22054,22056,22058,22060,22062,22064],{"class":3565,"line":5514},[3563,22039,4572],{"class":3606},[3563,22041,3610],{"class":3583},[3563,22043,3960],{"class":3602},[3563,22045,22046],{"class":3645},"\"  Помилок мережі:    ",[3563,22048,3966],{"class":3602},[3563,22050,22020],{"class":3583},[3563,22052,22053],{"class":3645},"'network_error'",[3563,22055,3624],{"class":3583},[3563,22057,5922],{"class":3587},[3563,22059,3518],{"class":3583},[3563,22061,3972],{"class":3602},[3563,22063,3975],{"class":3645},[3563,22065,3936],{"class":3583},[3563,22067,22068,22070,22072,22074,22077,22079,22081,22084,22086,22088,22090,22092,22094],{"class":3565,"line":5520},[3563,22069,4572],{"class":3606},[3563,22071,3610],{"class":3583},[3563,22073,3960],{"class":3602},[3563,22075,22076],{"class":3645},"\"  Помилок обробки:   ",[3563,22078,3966],{"class":3602},[3563,22080,22020],{"class":3583},[3563,22082,22083],{"class":3645},"'processing_error'",[3563,22085,3624],{"class":3583},[3563,22087,5922],{"class":3587},[3563,22089,3518],{"class":3583},[3563,22091,3972],{"class":3602},[3563,22093,3975],{"class":3645},[3563,22095,3936],{"class":3583},[3563,22097,22098],{"class":3565,"line":5526},[3563,22099,3577],{"emptyLinePlaceholder":3576},[3563,22101,22102,22104],{"class":3565,"line":5532},[3563,22103,7673],{"class":3652},[3563,22105,7986],{"class":3587},[3563,22107,22108],{"class":3565,"line":5538},[3563,22109,3577],{"emptyLinePlaceholder":3576},[3563,22111,22112,22114,22116,22118],{"class":3565,"line":5544},[3563,22113,7991],{"class":3652},[3563,22115,7994],{"class":3620},[3563,22117,7997],{"class":3652},[3563,22119,8000],{"class":3583},[3563,22121,22122,22124,22126,22128,22131,22133,22135,22137,22139],{"class":3565,"line":5550},[3563,22123,4572],{"class":3606},[3563,22125,3610],{"class":3583},[3563,22127,3960],{"class":3602},[3563,22129,22130],{"class":3645},"\"Помилка конфігурації: ",[3563,22132,3966],{"class":3602},[3563,22134,8016],{"class":3583},[3563,22136,3972],{"class":3602},[3563,22138,3975],{"class":3645},[3563,22140,3936],{"class":3583},[3563,22142,22143,22145],{"class":3565,"line":5556},[3563,22144,7673],{"class":3652},[3563,22146,7898],{"class":3587},[3563,22148,22149,22151,22153],{"class":3565,"line":5561},[3563,22150,7991],{"class":3652},[3563,22152,9317],{"class":3620},[3563,22154,3639],{"class":3583},[3563,22156,22157,22159,22161,22164],{"class":3565,"line":8077},[3563,22158,4572],{"class":3606},[3563,22160,3610],{"class":3583},[3563,22162,22163],{"class":3645},"\"Помилка: Параметр ширини має бути цілим числом!\"",[3563,22165,3936],{"class":3583},[3563,22167,22168,22170],{"class":3565,"line":8090},[3563,22169,7673],{"class":3652},[3563,22171,7898],{"class":3587},[3563,22173,22175],{"class":3565,"line":22174},47,[3563,22176,3577],{"emptyLinePlaceholder":3576},[3563,22178,22180,22182,22184,22186,22188],{"class":3565,"line":22179},48,[3563,22181,7464],{"class":3652},[3563,22183,7467],{"class":3613},[3563,22185,7470],{"class":3583},[3563,22187,7473],{"class":3645},[3563,22189,3639],{"class":3583},[3563,22191,22193],{"class":3565,"line":22192},49,[3563,22194,22195],{"class":3569},"    # Повертаємо статус-код оболонці\n",[3563,22197,22199],{"class":3565,"line":22198},50,[3563,22200,22201],{"class":3583},"    sys.exit(main())\n",[3461,22203],{},[3468,22205,22207],{"id":22206},"пакетна-реалізація-проекту-крок-за-кроком","Пакетна реалізація проекту крок за кроком",[4299,22209,22210,22214,22222,22276,22280,22288,22326,22330,22337,22358,22362,22373,22379,22383,22400,22459,22463,22472],{},[3468,22211,22213],{"id":22212},"налаштування-директорії-та-ізоляції-venv","Налаштування директорії та ізоляції (venv)",[3394,22215,22216,22217,4481,22219,22221],{},"Створимо структуру папок та ініціалізуємо ізольоване віртуальне середовище, щоб сторонні пакети ",[3398,22218,5876],{},[3398,22220,20781],{}," не конфліктували з іншими версіями у глобальній системі.",[4032,22223,22225,22234,22243,22252,22260,22272],{"title":22224},"Ініціалізація оточення",[4036,22226,22228,4044,22231],{"className":22227},[3565],[3563,22229,4043],{"className":22230},[4042],[3406,22232,22233],{},"mkdir -p my_project\u002Fimage_processor\u002Fcore my_project\u002Fimage_processor\u002Futils",[4036,22235,22237,4044,22240],{"className":22236},[3565],[3563,22238,4043],{"className":22239},[4042],[3406,22241,22242],{},"cd my_project",[4036,22244,22246,4044,22249],{"className":22245},[3565],[3563,22247,4043],{"className":22248},[4042],[3406,22250,22251],{},"python3.12 -m venv .venv",[4036,22253,22255,4044,22258],{"className":22254},[3565],[3563,22256,4043],{"className":22257},[4042],[3406,22259,11001],{},[4036,22261,22263,4044,22266,4044,22269],{"className":22262},[3565],[3563,22264,11378],{"className":22265},[4054],[3563,22267,4043],{"className":22268},[4042],[3406,22270,22271],{},"which python",[4036,22273,22275],{"className":22274},[3565],"\u002FUsers\u002Fuser\u002Fmy_project\u002F.venv\u002Fbin\u002Fpython",[3468,22277,22279],{"id":22278},"встановлення-та-фіксація-залежностей","Встановлення та фіксація залежностей",[3394,22281,22282,22283,22285,22286,3459],{},"Встановимо необхідні сторонні бібліотеки через ",[3398,22284,6155],{}," та запишемо їх у ",[3398,22287,11473],{},[4032,22289,22291,22303,22307,22311,22315],{"title":22290},"Встановлення залежностей через pip",[4036,22292,22294,4044,22297,4044,22300],{"className":22293},[3565],[3563,22295,11378],{"className":22296},[4054],[3563,22298,4043],{"className":22299},[4042],[3406,22301,22302],{},"pip install requests Pillow",[4036,22304,22306],{"className":22305},[3565],"Collecting requests...",[4036,22308,22310],{"className":22309},[3565],"Collecting Pillow...",[4036,22312,22314],{"className":22313},[3565],"Successfully installed requests-2.31.0 Pillow-10.2.0 ...",[4036,22316,22318,4044,22321,4044,22324],{"className":22317},[3565],[3563,22319,11378],{"className":22320},[4054],[3563,22322,4043],{"className":22323},[4042],[3406,22325,11537],{},[3468,22327,22329],{"id":22328},"створення-вихідних-файлів-коду","Створення вихідних файлів коду",[3394,22331,22332,22333,22336],{},"Запишіть код для кожного з файлів структури проекту ",[3398,22334,22335],{},"image_processor"," відповідно до архітектурного опису, наведеного вище.",[11028,22338,22339,22340,3639,22342,22345,22346,22348,22349,22352,22353,22355,22356,3459],{},"Зверніть увагу на відносні імпорти у файлі ",[3398,22341,20801],{},[3398,22343,22344],{},"from .core.downloader import download_image","\nЦе гарантує локальну цілісність пакета. Натомість у файлі ",[3398,22347,3400],{},", який виступає точкою запуску, використовуються абсолютні імпорти:\n",[3398,22350,22351],{},"from image_processor import process_images","\nоскільки при запуску через ",[3398,22354,8118],{}," точка входу має викликатися з кореня ",[3398,22357,3517],{},[3468,22359,22361],{"id":22360},"підготовка-тестових-даних","Підготовка тестових даних",[3394,22363,22364,22365,22368,22369,22372],{},"Створимо файл ",[3398,22366,22367],{},"urls.txt"," в корені проекту ",[3398,22370,22371],{},"my_project\u002F"," зі списком реальних тестових зображень для завантаження:",[3554,22374,22377],{"className":22375,"code":22376,"language":8718,"meta":3559},[8716],"# urls.txt\n# Список зображень для оптимізації\nhttps:\u002F\u002Fimages.unsplash.com\u002Fphoto-1579783900882-c0d3dad7b119?w=1200\nhttps:\u002F\u002Fimages.unsplash.com\u002Fphoto-1541701494587-cb58502866ab?w=1200\n# Невалідний URL для тестування стійкості до помилок:\nhttps:\u002F\u002Fnon-existent-domain-xyz.com\u002Fimage.jpg\n",[3398,22378,22376],{"__ignoreMap":3559},[3468,22380,22382],{"id":22381},"запуск-та-аналіз-роботи-cli","Запуск та аналіз роботи CLI",[3394,22384,22385,22386,22388,22389,22391,22392,22395,22396,22399],{},"Запустимо наш пакет із кореневої папки проекту за допомогою прапорця інтерпретатора ",[3398,22387,5817],{},". Ми вкажемо вхідний файл ",[3398,22390,22367],{},", папку збереження ",[3398,22393,22394],{},"optimized_images"," та бажану ширину ",[3398,22397,22398],{},"600"," пікселів.",[4032,22401,22403,22415,22419,22423,22427,22431,22434,22438,22445,22452],{"title":22402},"Запуск утиліти",[4036,22404,22406,4044,22409,4044,22412],{"className":22405},[3565],[3563,22407,11378],{"className":22408},[4054],[3563,22410,4043],{"className":22411},[4042],[3406,22413,22414],{},"python -m image_processor.main urls.txt .\u002Foptimized_images 600",[4036,22416,22418],{"className":22417},[3565],"Знайдено 2 посилань. Починаємо обробку...",[4036,22420,22422],{"className":22421},[3565],"Збережено оптимізоване зображення: optimized_images\u002Fimage_1.webp",[4036,22424,22426],{"className":22425},[3565],"Збережено оптимізоване зображення: optimized_images\u002Fimage_2.webp",[4036,22428,22430],{"className":22429},[3565],"Помилка мережі при завантаженні https:\u002F\u002Fnon-existent-domain-xyz.com\u002Fimage.jpg...",[4036,22432],{"className":22433},[3565],[4036,22435,22437],{"className":22436},[3565],"=== Статистика обробки ===",[4036,22439,22441,22442],{"className":22440},[3565],"  Успішно оброблено: ",[3563,22443,4209],{"className":22444},[4054],[4036,22446,22448,22449],{"className":22447},[3565],"  Помилок мережі:    ",[3563,22450,5061],{"className":22451},[6748],[4036,22453,22455,22456],{"className":22454},[3565],"  Помилок обробки:   ",[3563,22457,5922],{"className":22458},[6748],[3468,22460,22462],{"id":22461},"перевірка-результатів-на-диску","Перевірка результатів на диску",[3394,22464,22465,22466,22468,22469,22471],{},"Перевіримо вміст автоматично створеної директорії ",[3398,22467,22394],{}," за допомогою ",[3398,22470,19308],{},"-подібних команд або звичайної утиліти перегляду.",[4032,22473,22475,22487,22491,22495],{"title":22474},"Перевірка результатів",[4036,22476,22478,4044,22481,4044,22484],{"className":22477},[3565],[3563,22479,11378],{"className":22480},[4054],[3563,22482,4043],{"className":22483},[4042],[3406,22485,22486],{},"ls -l optimized_images\u002F",[4036,22488,22490],{"className":22489},[3565],"-rw-r--r--  1 user  staff  42104 Jun 13 20:45 image_1.webp",[4036,22492,22494],{"className":22493},[3565],"-rw-r--r--  1 user  staff  38942 Jun 13 20:45 image_2.webp",[4036,22496,22498],{"className":22497},[3565],[3563,22499,22502],{"className":22500},[4054,22501],"opacity-60","← Зображення успішно стиснені, зменшені та збережені у форматі WebP!",[3461,22504],{},[3389,22506,22508],{"id":22507},"порівняльна-таблиця-стратегії-імпорту","Порівняльна таблиця: стратегії імпорту",[8132,22510,22511,22529],{},[8135,22512,22513],{},[8138,22514,22515,22518,22521,22524,22527],{},[8141,22516,22517],{},"Синтаксис",[8141,22519,22520],{},"Простір імен",[8141,22522,22523],{},"Ризик конфлікту",[8141,22525,22526],{},"Читабельність",[8141,22528,17312],{},[8152,22530,22531,22549,22567,22583],{},[8138,22532,22533,22537,22540,22543,22546],{},[8157,22534,22535],{},[3398,22536,4252],{},[8157,22538,22539],{},"ізольований",[8157,22541,22542],{},"❌ мінімальний",[8157,22544,22545],{},"✅ висока",[8157,22547,22548],{},"✅ основний підхід",[8138,22550,22551,22555,22558,22561,22564],{},[8157,22552,22553],{},[3398,22554,4897],{},[8157,22556,22557],{},"поточний",[8157,22559,22560],{},"⚠️ є",[8157,22562,22563],{},"⚠️ середня",[8157,22565,22566],{},"✅ для 1-3 об'єктів",[8138,22568,22569,22573,22575,22577,22580],{},[8157,22570,22571],{},[3398,22572,4977],{},[8157,22574,22539],{},[8157,22576,22542],{},[8157,22578,22579],{},"✅ висока (якщо alias відомий)",[8157,22581,22582],{},"✅ для довгих імен",[8138,22584,22585,22589,22591,22594,22597],{},[8157,22586,22587],{},[3398,22588,4256],{},[8157,22590,22557],{},[8157,22592,22593],{},"❌❌ гарантований",[8157,22595,22596],{},"❌ низька",[8157,22598,22599],{},"❌ уникати завжди",[3461,22601],{},[3389,22603,22605],{"id":22604},"підсумки-та-найкращі-практики","Підсумки та найкращі практики",[3411,22607,22608,22621,22631,22645,22649,22652],{},[3414,22609,22611,22612,22614,22615,22617,22618,22620],{"icon":11792,"title":22610},"Модулі","Кожен ",[3398,22613,3481],{},"-файл — модуль. Ділить код на логічні одиниці. Завантажується один раз, кешується у ",[3398,22616,3496],{},". Пишіть ",[3398,22619,7254],{}," для двоїстих файлів.",[3414,22622,22625,22627,22628,22630],{"icon":22623,"title":22624},"i-heroicons-magnifying-glass","sys.path і sys.modules",[3398,22626,3517],{}," — список директорій для пошуку. ",[3398,22629,3496],{}," — кеш завантажених модулів. Розуміння цих двох структур пояснює більшість «магії» імпорту.",[3414,22632,22635,22636,22638,22639,22641,22642,22644],{"icon":22633,"title":22634},"i-heroicons-folder-open","Пакети","Директорія з ",[3398,22637,8808],{},". Організує модулі ієрархічно. ",[3398,22640,8808],{}," слугує фасадом публічного API. ",[3398,22643,5295],{}," документує контракт модуля.",[3414,22646,22648],{"icon":13665,"title":22647},"venv + pip","Базовий стандарт ізоляції, вбудований у Python. Вивчіть його першим — він підвалина для розуміння того, як працюють uv та Poetry.",[3414,22650,22651],{"icon":11752,"title":11642},"Рекомендований вибір для нових проектів. У 10–100 разів швидший за pip, управляє версіями Python, має lockfile та не потребує ручної активації mid venv.",[3414,22653,22654],{"icon":17857,"title":11712},"Ідеальний для публікації бібліотек на PyPI та для команд з розвиненим workflow. Чіткі групи залежностей (dev\u002Ftest\u002Fdocs) і зрілий tooling навколо.",[3394,22656,22657],{},[3406,22658,22659],{},"Золоті правила, що варто запам'ятати:",[3505,22661,22662,22673,22682,22694,22707,22719,22726,22729],{},[3508,22663,17731,22664,22667,22668,3624,22670,22672],{},[3406,22665,22666],{},"Завжди"," використовуйте ізольоване середовище для кожного проекту (",[3398,22669,10824],{},[3398,22671,11768],{}," або Poetry)",[3508,22674,17731,22675,22677,22678,8445,22680],{},[3406,22676,22666],{}," додавайте ",[3398,22679,13811],{},[3398,22681,15760],{},[3508,22683,17731,22684,22686,22687,22689,22690,8106,22692,3518],{},[3406,22685,22666],{}," фіксуйте залежності: ",[3398,22688,11537],{}," або через lockfile (",[3398,22691,11784],{},[3398,22693,14682],{},[3508,22695,22696,22697,22700,22701,22703,22704,22706],{},"✅ Для ",[3406,22698,22699],{},"нових проектів"," — обирайте ",[3398,22702,11642],{}," (швидкість + простота) або ",[3398,22705,11712],{}," (якщо плануєте публікацію на PyPI)",[3508,22708,22709,22710,4310,22712,3624,22714,4044,22717],{},"✅ Використовуйте ",[3398,22711,4252],{},[3398,22713,4897],{},[3406,22715,22716],{},"уникайте",[3398,22718,4256],{},[3508,22720,22721,22722,22725],{},"✅ Пишіть ",[3398,22723,22724],{},"if __name__ == \"__main__\":"," у кожному файлі, що може запускатися напряму",[3508,22727,22728],{},"✅ Структуруйте код у пакети при наявності більш ніж 5–7 модулів",[3508,22730,22731],{},"✅ Використовуйте абсолютні імпорти між пакетами, відносні — всередині одного пакета",[22733,22734,22735],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sLwNe, html code.shiki .sLwNe{--shiki-light:#0451A5;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sjcCO, html code.shiki .sjcCO{--shiki-light:#EE0000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"title":3559,"searchDepth":3573,"depth":3573,"links":22737},[22738,22739,22751,22760,22768,22776,22792,22798,22804,22812,22832,22845,22846,22857,22858],{"id":3391,"depth":3573,"text":3392},{"id":3465,"depth":3573,"text":3466,"children":22740},[22741,22742,22743,22744,22745,22746,22747,22748,22749],{"id":3470,"depth":3580,"text":3471},{"id":4074,"depth":3580,"text":4075},{"id":4259,"depth":3580,"text":4260},{"id":4303,"depth":3580,"text":4304},{"id":4317,"depth":3580,"text":4318},{"id":4324,"depth":3580,"text":4325},{"id":4331,"depth":3580,"text":4332},{"id":4822,"depth":3580,"text":4823},{"id":5157,"depth":3580,"text":22750},"Конвенція _private: приватні атрибути модуля",{"id":5308,"depth":3573,"text":22752,"children":22753},"Система пошуку модулів: sys.path зсередини",[22754,22756,22758],{"id":5315,"depth":3580,"text":22755},"Алгоритм пошуку import",{"id":5566,"depth":3580,"text":22757},"Анатомія sys.path: що там насправді",{"id":5885,"depth":3580,"text":22759},"Маніпуляції з sys.path: коли і як",{"id":6164,"depth":3573,"text":22761,"children":22762},"Кешування імпортів: sys.modules та Singleton-поведінка",[22763,22764,22766],{"id":6171,"depth":3580,"text":6172},{"id":6774,"depth":3580,"text":22765},"sys.modules як Singleton-реєстр: спільний стан",{"id":7082,"depth":3580,"text":22767},"Перезавантаження модуля: importlib.reload",{"id":7250,"depth":3573,"text":22769,"children":22770},"Подвійне призначення файлу: if __name__ == \"__main__\"",[22771,22772,22774],{"id":7257,"depth":3580,"text":7258},{"id":7584,"depth":3580,"text":22773},"Патерн main(): структурований точок входу",{"id":8115,"depth":3580,"text":22775},"python -m: запуск модуля як скрипта",{"id":8224,"depth":3573,"text":8225,"children":22777},[22778,22779,22781,22783,22785,22787,22789,22791],{"id":8228,"depth":3580,"text":8229},{"id":8409,"depth":3580,"text":22780},"Python починає виконувати a.py",{"id":8427,"depth":3580,"text":22782},"Python починає виконувати b.py",{"id":8441,"depth":3580,"text":22784},"Python виявляє a у sys.modules",{"id":8482,"depth":3580,"text":22786},"b.py успішно завантажується",{"id":8498,"depth":3580,"text":22788},"Виконання повертається до a.py",{"id":8514,"depth":3580,"text":22790},"Виклик a.func_a() → b.func_b()",{"id":8703,"depth":3580,"text":8704},{"id":8785,"depth":3573,"text":8786,"children":22793},[22794,22795,22796],{"id":8789,"depth":3580,"text":8790},{"id":8812,"depth":3580,"text":8813},{"id":10003,"depth":3580,"text":22797},"Роль __init__.py: ворота пакета",{"id":10121,"depth":3573,"text":10122,"children":22799},[22800,22801,22802],{"id":10125,"depth":3580,"text":10126},{"id":10194,"depth":3580,"text":10195},{"id":10321,"depth":3580,"text":22803},"__all__: контракт публічного API",{"id":10492,"depth":3573,"text":10493,"children":22805},[22806,22807,22809,22810],{"id":10496,"depth":3580,"text":10497},{"id":10821,"depth":3580,"text":22808},"Що таке venv: ізольований Python від стандартної бібліотеки",{"id":11039,"depth":3580,"text":11040},{"id":11470,"depth":3580,"text":22811},"requirements.txt: заморожування залежностей",{"id":11657,"depth":3573,"text":11658,"children":22813},[22814,22816,22818,22820,22821,22822,22823,22824,22825,22826,22827,22828,22830],{"id":11718,"depth":3580,"text":22815},"uv — ультрашвидкий менеджер нового покоління",{"id":13641,"depth":3580,"text":22817},"Poetry — зрілий менеджер для складних проектів",{"id":15184,"depth":3580,"text":22819},"Робота з git: що робити після git clone?",{"id":15276,"depth":3580,"text":15277},{"id":15301,"depth":3580,"text":15302},{"id":15342,"depth":3580,"text":15343},{"id":15427,"depth":3580,"text":15428},{"id":15493,"depth":3580,"text":15277},{"id":15514,"depth":3580,"text":15515},{"id":15538,"depth":3580,"text":15539},{"id":15619,"depth":3580,"text":15428},{"id":15990,"depth":3580,"text":22829},"Статичний аналіз типів: mypy та Pyright",{"id":17666,"depth":3580,"text":22831},"Порівняльна таблиця: venv+pip vs uv vs Poetry",{"id":17864,"depth":3573,"text":17865,"children":22833},[22834,22835,22837,22839,22841,22843],{"id":17868,"depth":3580,"text":17869},{"id":17906,"depth":3580,"text":22836},"Математичні обчислення: модуль math",{"id":18301,"depth":3580,"text":22838},"Псевдовипадковість: модуль random",{"id":18736,"depth":3580,"text":22840},"Робота з часом: модуль datetime",{"id":19300,"depth":3580,"text":22842},"Системна взаємодія: os vs sys vs pathlib",{"id":19803,"depth":3580,"text":22844},"Спеціалізовані контейнери: модуль collections",{"id":20466,"depth":3573,"text":20467},{"id":20731,"depth":3573,"text":20732,"children":22847},[22848,22849,22850,22851,22852,22853,22854,22855,22856],{"id":20754,"depth":3580,"text":20755},{"id":20791,"depth":3580,"text":20792},{"id":22206,"depth":3580,"text":22207},{"id":22212,"depth":3580,"text":22213},{"id":22278,"depth":3580,"text":22279},{"id":22328,"depth":3580,"text":22329},{"id":22360,"depth":3580,"text":22361},{"id":22381,"depth":3580,"text":22382},{"id":22461,"depth":3580,"text":22462},{"id":22507,"depth":3573,"text":22508},{"id":22604,"depth":3573,"text":22605},"Глибоке дослідження системи модулів Python — від механізмів пошуку файлів через sys.path до кешування імпортів у sys.modules, архітектури пакетів з __init__.py та ізоляції залежностей через venv. Фундамент для будь-якого серйозного Python-проекту.","md",null,{},{"title":2554,"description":22859},"KSD3Q-hMhB8rvObIKzRFbXbuTwR7Qh_nEkTuui4fu4M",[22866,22868],{"title":2544,"path":2545,"stem":2546,"description":22867,"children":-1},"Від вихідного коду до готового інсталятора: створення Fat JAR, використання jpackage для генерації нативних інсталяторів під Windows, macOS та Linux, публікація релізів у GitHub Releases.",{"title":71,"path":2558,"stem":2559,"description":22869,"children":-1},"Глибоке дослідження механізму класів і об'єктів у Python — від фундаментальних принципів інстанціювання до CPython internals, різниці між __init__ та __new__, оптимізації пам'яті через __slots__ та природи self як неявного першого аргументу.",1783248082039]