Learning Platform
Troubleshooting
Глоссарий

Глоссарий — Python для Data Engineer

Справочник ключевых терминов курса. От CPython internals до production tooling.

6 категорий · 80 терминов

Производительность

`__slots__`

__slots__
Термин

Class attribute, заменяющий per-instance __dict__ на fixed set member_descriptor'ов (data descriptors с C-implemented __get__/__set__, читающие fixed offsets в instance memory). Объявление: `class C: __slots__ = ('x', 'y')`. CPython при создании класса (Objects/typeobject.c функция type_new_descriptors) устанавливает tp_dictoffset = 0 и создаёт member_descriptor для каждого slot имени. Verified empirical (Python 3.12.7): WithSlots() instance = 48 байт (PyObject header + 2 slots, no __dict__); WithoutSlots() = 48 байт + 296 байт (PyDictObject) = 344 байт total. Экономия ~6-7x для small classes. Subclass rule: каждый класс в иерархии должен иметь __slots__, иначе __dict__ возвращается (CPython устанавливает tp_dictoffset = 0 только если все базовые тоже имеют 0); child пишет ТОЛЬКО дополнительные slots, не повторяет parent. Также блокирует динамические attrs: `obj.unknown = ...` → AttributeError. `@dataclass(slots=True)` (Python 3.10+) автоматизирует через _add_slots() в Lib/dataclasses.py. Use case: production records, создающиеся миллионами (events, log entries, market data) — savings ~300MB на 1M instances. См. PEP 412 (split-keys dict, M02 урок 04 alternative); Python data model § __slots__.

Подробнее в уроках:

Амортизационный анализ

Amortized analysis
Термин

Метод оценки средней стоимости одной операции в худшем случае по последовательности из n операций (worst-case avg over n ops), а не стоимости одной отдельной операции. Классический пример: list.append имеет worst-case O(n) (когда срабатывает реаллокация и копирование всех элементов в новый буфер), но amortized O(1) — реаллокации происходят геометрически (capacity ≈ 1.125·n в CPython), поэтому суммарная стоимость n append-ов = O(n), и средняя по n = O(1). Формальные техники: aggregate method, accounting method, potential method (см. CLRS гл. 17). Big-O лидера-операции и amortized-O последовательности — разные вещи; смешивать их — типичная ошибка.

Подробнее в уроках:

Геометрическая реаллокация

Geometric reallocation
Термин

Стратегия роста capacity динамического массива (list, vector, ArrayList) геометрической прогрессией — каждый realloc увеличивает capacity на постоянный множитель c > 1, а не на постоянное число элементов. CPython list_resize в Objects/listobject.c использует формулу new_allocated = (newsize + (newsize >> 3) + 6) & ~3, что соответствует фактору ~1.125x. Java ArrayList — 1.5x, Go slice — 2.0x при размере < 1024 затем 1.25x, C++ std::vector — обычно 2.0x. Назначение: amortized O(1) для append. Без геометрии (linear realloc на +1 элемент) суммарная работа n appends = 1+2+...+n = O(n²), per-append O(n). С геометрией суммарная работа = O(n), per-append O(1) amortized. Чем больше factor c, тем меньше realloc'ов, но больше memory waste. CPython 1.125 — компромисс: маленький overhead, но чаще realloc. См. CLRS гл. 17 для формального доказательства.

Подробнее в уроках:

Коллизия

Hash collision
Термин

Ситуация, когда h(k₁) ≡ h(k₂) (mod table_size) для двух различных ключей k₁ ≠ k₂. Поскольку число возможных ключей обычно превышает размер таблицы, коллизии неизбежны (pigeonhole principle), и стратегия их обработки определяет производительность hash table. CPython использует open addressing с perturbation: при коллизии следующий слот вычисляется как (5*i + 1 + perturb) mod size, где perturb сдвигается на PERTURB_SHIFT=5 каждой итерации (см. dictobject.c#lookdict). Альтернативная стратегия — separate chaining (Java HashMap до версии 8) — хранит цепочку записей в одном bucket.

Подробнее в уроках:

Коэффициент загрузки

Load factor
Термин

Отношение n/m, где n — число занятых слотов, а m — общее число слотов в hash table. CPython держит load factor ниже USABLE_FRACTION = 2/3 (≈0.66): при превышении dict удваивается в размере (resize-up). Низкий load factor означает мало коллизий, но больше памяти; высокий — плотнее упаковку, но рост среднего числа проб при поиске. Для linear probing среднее число проб при удачном поиске оценивается как ~0.5·(1 + 1/(1−α)), где α = load factor; при α→1 число проб взрывается, что и оправдывает геометрический resize-порог.

Подробнее в уроках:

Перегрузка пробы (perturbation)

Perturbation probe
Термин

Probe sequence формула CPython dict/set: `i = (5*i + 1 + perturb) & mask; perturb >>= PERTURB_SHIFT (5)`. Initial: `perturb = hash`. Назначение: избежать primary clustering, типичной проблемы linear probing — keys с одинаковыми low bits hash'а имеют идентичную probe sequence, склеиваются в смежные кластеры, lookup degrade'ится до O(n). Perturbation вводит high bits hash'а (которые `& mask` обычно отбрасывает) в формулу — keys с разными high bits идут разными probe sequences. `5*i + 1` обеспечивает full cycle (probe пройдёт все slots до повторения). Через ~13 итераций perturb становится 0, формула вырождается в чистый `5*i + 1` — всё ещё full cycle. Алгоритм восходит к Tim Peters'у (python-dev 2000). См. Objects/dictobject.c.

Подробнее в уроках:

Разрешение коллизий хеша

Hash collision resolution
Термин

Способ обработки случая, когда два разных ключа дают одинаковый индекс в хеш-таблице. CPython PyDictObject использует open addressing с perturbation probe (см. CPython Objects/dictobject.c, lookdict): при коллизии следующий слот вычисляется как `i = (5*i + 1 + perturb) % capacity`, где `perturb >>= 5` каждую итерацию. Это даёт лучшую дисперсию чем линейное пробирование и сохраняет cache locality. Альтернатива — separate chaining через linked-list (Java HashMap до 8) — CPython не использует, чтобы не дробить cache lines дополнительной indirection. Cross-link: M02 урок 03 (`hash` + open addressing demo).

Пример:
# Демонстрация коллизий через подгонку capacity:
>>> hash("abc") % 8
3
>>> hash("xyz") % 8
3   # коллизия для capacity=8
# CPython probe sequence (5*i + 1 + perturb) — детерминированный обход слотов
Подробнее в уроках:

Хэш-функция

Hash function
Термин

Функция h: K → ℤ, отображающая ключи произвольного размера в целые числа фиксированного диапазона. Для словарей CPython используется реализация, основанная на SipHash (для str/bytes — рандомизированная при старте процесса, чтобы снизить риск hash-flood DoS). Хорошая хэш-функция распределяет ключи равномерно (uniform distribution), стремится минимизировать коллизии и вычисляется за O(|key|). Для пользовательских классов хэш переопределяется методом __hash__; объекты, равные по __eq__, обязаны иметь одинаковый хэш. См. CPython/Python/pyhash.c и dictobject.c.

Подробнее в уроках:

Big-O нотация

Big-O notation
Термин

Асимптотическая верхняя оценка скорости роста функции. f(n) = O(g(n)), если существуют константы c > 0 и n₀, такие что для всех n ≥ n₀ выполняется |f(n)| ≤ c·|g(n)|. Используется для классификации сложности алгоритмов независимо от константного фактора и младших членов. Ориентиры для Python: dict lookup amortized O(1), list.append amortized O(1), list.insert(0, x) — O(n), set membership — O(1), оператор `'x' in [...]` — O(n). Big-O описывает worst case (верхняя оценка); Big-Θ — точная оценка сверху и снизу одновременно; Big-Ω — нижняя оценка. Не путать с amortized big-O последовательности операций.

Подробнее в уроках:

Cache line (строка кэша)

Cache line
Термин

Минимальная единица передачи данных между основной памятью и L1/L2/L3 кэшами процессора — обычно 64 байта на x86_64 и aarch64. Когда CPU читает один байт, аппаратура загружает целиком всю cache line, в которой этот байт находится. Это объясняет, почему contiguous-memory структуры (list, tuple, NumPy ndarray) обеспечивают высокую пропускную способность при последовательном обходе: следующий элемент с большой вероятностью уже в той же cache line, что использует spatial locality. Linked list, напротив, требует random access к разным cache lines на каждом шаге, и каждый промах кэша стоит десятки-сотни циклов.

Подробнее в уроках:

Cache line CPython

CPython cache-line behavior
Термин

CPython объекты выровнены и аллоцированы так, чтобы next-element access попадал в ту же cache line (~64 байта на x86_64). PyListObject хранит указатели на PyObject в contiguous-памяти (`ob_item` — массив `PyObject **`), что обеспечивает spatial locality при последовательном обходе: 8 указателей умещаются в одну 64-байтовую cache line. Однако сами объекты-значения хранятся вразброс по heap (через указатель — indirection cost). Linked list, напротив, тратит cache miss на каждом шаге. Понимание cache line behavior — основа объяснения, почему `sum(lst)` быстрее `sum(linked_list)` на одинаковых N. Cross-link: M02 урок 06 (mutability + cache).

Пример:
# Contiguous list — cache-friendly
lst = [i for i in range(1_000_000)]
sum(lst)   # spatial locality: prefetch работает

# Linked-list (Python list of dicts) — random access pattern
# Каждый next pointer = potential cache miss
Подробнее в уроках:

IEEE 754

IEEE 754
Термин

Стандарт IEEE для представления чисел с плавающей точкой. Python float использует double-precision (64-bit): 1 бит знака + 11 бит экспоненты (biased на 1023) + 52 бита мантиссы (плюс implicit leading 1 для нормализованных). Это даёт ~15-17 значащих десятичных цифр и диапазон ±[2.2e-308 .. 1.8e308]. Особые битовые паттерны представляют +inf/-inf, NaN, denormalized. Round-off error: десятичные дроби типа 0.1 не имеют точного binary representation (бесконечная двоичная дробь обрезается до 52 бит), поэтому 0.1+0.2 != 0.3. Machine epsilon = sys.float_info.epsilon ≈ 2.22e-16 — минимальное ε такое, что 1.0+ε > 1.0. Для корректного сравнения используйте math.isclose; для финансовых расчётов — decimal.Decimal (произвольная десятичная точность). См. Objects/floatobject.c, sys.float_info.

Подробнее в уроках:

LRU cache

Least Recently Used cache
Термин

`functools.lru_cache(maxsize=N)` — декоратор для memoization функций. Cache хранится в `dict` (open addressing с perturbation, см. M02 урок 03), ключ = hash(args). При достижении maxsize evict наименее recently used entry (через linked list, поддерживающий MRU/LRU порядок). C-accelerated в `Modules/_functoolsmodule.c`; pure-Python fallback в `Lib/functools.py`. Args обязаны быть hashable (mutable list/dict/set → TypeError 'unhashable type'). Возвращаемая wrapped функция имеет `cache_info()` → CacheInfo(hits, misses, maxsize, currsize) и `cache_clear()`. `@cache` (Python 3.9+) — alias для `@lru_cache(maxsize=None)` (unbounded). Use cases: рекурсивные функции (fib экспоненциально → линейный с cache), expensive pure functions, request memoization. Не подходит для: функций с side effects, mutable args, time-sensitive cache (используйте `cachetools.TTLCache`).

Подробнее в уроках:

Open addressing

Open addressing
Термин

Стратегия разрешения коллизий в hash table: при коллизии probe sequence ищет другой slot **в той же таблице** (без отдельных linked list / chains). Альтернатива — separate chaining (Java HashMap до 8: linked list per slot). CPython использует open addressing для dict, set, frozenset. Преимущества: лучшая cache locality (всё в одном смежном массиве, sequential probing с prefetcher); нет per-slot pointer overhead. Probe sequences: linear probing (i+1 mod size — страдает от primary clustering), quadratic probing (i² + i — better, но не CPython), perturbation probe CPython — `i = (5*i + 1 + perturb) & mask` где perturb рандомизирует через high bits hash'а. См. Objects/dictobject.c функция lookdict, Knuth Vol 3 Section 6.4.

Подробнее в уроках:

Row group (Parquet)

Parquet row group
Термин

Логическое горизонтальное partition'ирование Parquet файла. Файл = sequence row groups; row group = collection column chunks (один per column); column chunk = sequence pages (data + dictionary + index). Default row group size — 128 MB (uncompressed) или 1 млн rows. Компрессия и encoding применяются на page level; dictionary encoding (для repeated values) — на column-chunk level. **Predicate pushdown** работает через min/max statistics в row group footer: filter `WHERE age > 100` skips row groups где `max(age) ≤ 100` без чтения column chunks (massive I/O savings). **Column projection** — reader обращается только к requested columns chunks внутри row group. Trade-off: больше row groups → больше metadata overhead + better skip granularity; меньше → меньше overhead + worse selectivity. Cross-course deep dive: /storage-formats/02-parquet/ — 7 уроков (row groups, column chunks, pages, encodings, metadata-statistics, nested data Dremel, file viewer). Cross-course также DataFusion / Spark / ClickHouse / DuckDB consume same Parquet structure. Cite [parquet.apache.org/docs/file-format](https://parquet.apache.org/docs/file-format/) + Storage Formats course.

Подробнее в уроках:

Small-int cache

Small-int cache
Термин

Оптимизация CPython, при которой целые числа в диапазоне [-5, 256] предкэшируются в статическом массиве `_PyLong_SMALL_INTS` (объявлен в Objects/longobject.c). Функция PyLong_FromLong через макрос IS_SMALL_INT(ival) проверяет, попадает ли значение в этот диапазон — если да, возвращает указатель на кэшированный объект и инкрементирует refcount, минуя heap-аллокацию. Из-за этого `id(256) == id(256)` всегда True в стандартном CPython, а `id(257) == id(257)` обычно False. Cache не ускоряет сами операции (сложение/умножение), а уменьшает allocation overhead для частых констант: счётчиков циклов, малых индексов, бул-флагов. Границы [-5, 256] — implementation detail CPython; PyPy/MicroPython могут использовать другие. Никогда не сравнивайте int через `is` — это баг, ждущий выхода значения из кэша.

Подробнее в уроках:

USABLE_FRACTION

Usable fraction
Термин

Макрос CPython dict в Objects/dictobject.c: `USABLE_FRACTION(n) ((n << 1)/3)`. Определяет максимальное число валидных entries как `2n/3` от размера table — load factor ≤ 2/3. Для n=8 → 5 entries; n=16 → 10; n=32 → 21. При insert, который превысил бы threshold, dict resize'ится (обычно ×2 через макрос GROWTH_RATE) и все existing keys рехешируются. Значение 2/3 — компромисс: при load factor α средняя длина probe sequence для open addressing ≈ 0.5·(1 + 1/(1-α)). При α=2/3 → ~2 probes avg; при α=0.9 → 5.5 (взрыв). Меньший α тратит память; больший делает probes дорогими. Resize amortized O(1) per insert (происходит каждые n/3 inserts, copies все entries). См. CLRS глава 11.

Подробнее в уроках:

Язык и синтаксис

Замыкание

Closure
Термин

Функция, которая «захватывает» переменные из enclosing scope (внешней функции или модуля), сохраняя ссылку на них даже после того, как enclosing scope завершил исполнение. В CPython реализовано через cell objects: PyFunctionObject хранит `func_closure` — tuple из PyCellObject, каждый из которых wraps captured variable. Доступ через специальные opcodes LOAD_DEREF / STORE_DEREF (vs LOAD_FAST / STORE_FAST для обычных локалов). Free variable (захватываемая) обнаруживается компилятором при создании bytecode. Use case: декораторы (`def wrapper(): wrapped(...)` — wrapper closes over wrapped); partial application через nested defs; counters / accumulators в functional style. См. Objects/funcobject.c, Python/compile.c (free vs cellvar analysis). Закрытия — основа функционального программирования и mechanism behind декораторов в Phase 66 M06.

Подробнее в уроках:

Compact dict (PEP 468)

Compact dict (PEP 468)
Термин

Layout dict в Python 3.6+: разделение на dk_indices (sparse, 1/2/4/8-byte indices, для hash lookup и probing) + dk_entries (dense, insertion-ordered (hash, key, value) triples). Lookup: hash → probe в dk_indices → entry_idx → dk_entries[entry_idx]. Memory savings ~30-65% vs old наивный sparse table (где каждый slot — 24 байта (h,k,v) независимо занят или нет): для 10-entry dict 768 → 256 байт. Insertion order preserved бесплатно: dk_entries заполняется sequentially при insert, iteration читает entries linearly. Python 3.6 — implementation detail; Python 3.7 — language guarantee. Реализация: Naoki Inada + Raymond Hettinger; talk Hettinger 'Modern Dictionaries' (PyCon 2017). См. Objects/dictobject.c структура PyDictKeysObject.

Подробнее в уроках:

Comprehension

List/dict/set comprehension
Термин

Синтаксический сахар для построения list / dict / set из итерируемого источника одной строкой. Bytecode для `[x*2 for x in range(3)]` (Python 3.11+) использует `LIST_APPEND` opcode внутри отдельного frame — comprehension получает свой собственный scope (Python 3+) для переменной итерации, чтобы не загрязнять enclosing scope (см. PEP 3000). Сравнение с generator expression: `(x*2 for x in range(3))` использует `YIELD_VALUE` opcode и lazy iteration через PyGenObject — память O(1) vs O(n) для list comprehension. Dict / set comprehension — `{k: v for ...}` / `{x for ...}` — same machinery с `MAP_ADD` / `SET_ADD` opcodes.

Пример:
# List comprehension — eager, материализует весь список
>>> [x*2 for x in range(3)]
[0, 2, 4]
# Generator expression — lazy, O(1) память
>>> sum(x*2 for x in range(1_000_000))
# Dict / set comprehension
>>> {k: k*k for k in range(3)}
{0: 0, 1: 1, 2: 4}
Подробнее в уроках:

Context manager protocol

Context manager protocol
Термин

Протокол из двух dunder-методов __enter__ и __exit__, формализованный PEP 343 (Python 2.5, 2005). `with cm as v: body` — синтаксический сахар, эквивалентный: `_cm = cm; v = _cm.__enter__(); try: body(v); finally: _cm.__exit__(exc_type, exc_val, exc_tb)`. __enter__ — setup phase: возвращает значение для `as v`-binding (часто self для class-based pattern). __exit__ — teardown phase: tri-arg signature обязателен — exc_type (класс exception или None при normal exit), exc_val (instance exception или None), exc_tb (traceback object для traceback.format_tb). На normal exit все три = (None, None, None); на exception path — actual values из sys.exc_info(). Resource cleanup invariant: __exit__ ГАРАНТИРОВАННО вызывается на любом exit path (normal или exception) — это и есть main value `with`. Pitfall 3 — __exit__ returning truthy (True) подавляет exception (силлогизм PEP 343 — для conditional suppress); это anti-pattern для general usage (silent exception suppression — debugging impossible). Default __exit__ возвращает None → exception пробрасывается; conditional suppress: return exc_type is KeyError. Idiomatic suppress — contextlib.suppress(SpecificException) — targeted, self-documenting. Multi-context (PEP 617, Python 3.10+): `with a as x, b as y:` — синтаксический сахар для nested with, cleanup в LIFO order (b.__exit__ до a.__exit__). Bytecode lowering Python 3.12+: try/finally + with компилируются через ExceptionTable (отдельная structure на code object'е, описывающая (start, end, target, depth, lasti) tuples), а не через SETUP_FINALLY/END_FINALLY opcodes — zero-cost exceptions на normal path (empirically verified Python 3.12.7 через dis.dis). Forward-link Phase 67 pytest fixtures: yield-style fixtures используют context-manager protocol. Cite: PEP 343 (peps.python.org/pep-0343), PEP 617 (peps.python.org/pep-0617), datamodel.html#context-managers, Python 3.11 changelog ExceptionTable.

Подробнее в уроках:

Descriptor protocol

Descriptor protocol
Термин

Соглашение Python data model: объект называется дескриптором, если у него определён хотя бы один из методов `__get__(self, obj, owner=None)`, `__set__(self, obj, value)`, `__delete__(self, obj)`. Дополнительный `__set_name__(self, owner, name)` (PEP 487, Python 3.6+) — вызывается ОДИН раз при создании класса (через type_new_impl в Objects/typeobject.c функция type_new_set_names) — сообщает дескриптору имя, под которым он живёт в class. Два типа: data descriptor (имеет __set__ или __delete__) — пример @property; non-data descriptor (только __get__) — пример @classmethod, @staticmethod, обычные functions (методы). Lookup precedence в _PyObject_GenericGetAttrWithDict (Objects/object.c): **data descriptor (class) > instance __dict__ > non-data descriptor (class)**. Это enforcement на уровне CPython — НЕ просто 'контракт на бумаге'. Use cases: typed attributes (Pydantic, attrs), runtime validation (Django ORM fields), lazy properties, computed attributes. См. docs.python.org/3/howto/descriptor.html (Raymond Hettinger); Objects/typeobject.c type_getattro_impl; Objects/descrobject.c.

Подробнее в уроках:

F-string (PEP 498)

f-string (formatted string literal)
Термин

Formatted string literal, введён PEP 498 (Python 3.6+). Префикс `f` или `F` перед строковым литералом превращает его в выражение: `{expr}` подставляет результат `expr` (с опциональным format spec через `:`). Реализация на уровне bytecode: компилятор генерирует `FORMAT_VALUE` + `BUILD_STRING` opcodes, минуя runtime parsing — быстрее чем `str.format()` (~2x) и `%-formatting`. Python 3.8+ — debug-вариант `f"{x=}"` печатает имя выражения + значение (`x=42`). Python 3.12+ — PEP 701 снимает ограничения на вложенные кавычки и многострочные выражения внутри `{}`. Cross-link: M01 урок 04 (PEP 393 — Latin-1/UCS-2/UCS-4 storage для строкового результата).

Пример:
>>> name = "Лев"; n = 42
>>> f"Привет, {name}! count={n:03d}"
'Привет, Лев! count=042'
>>> f"{n=}"           # Python 3.8+ debug
'n=42'
Подробнее в уроках:

Generator expression

Generator expression (gen-expr)
Термин

Синтаксис `(expr for x in iter if cond)` (круглые скобки, не square / curly) — создаёт generator object: ленивый итератор, производящий элементы по требованию (по одному за `next()`). Ключевое отличие от list comprehension: O(1) память (≈120 байт PyGenObject) vs O(N) для list-comp (8MB для N=10⁶). Compiles в специальную generator function: PyGenObject содержит ссылку на frame, который suspended/resumed при каждом next(). Single-pass: после exhaustion (StopIteration) повторно итерировать нельзя — нужно создать новый. Идеально для агрегатных операций (sum/max/min/any/all) — потребитель читает по одному, никогда не materialize всё. Используется как input в map/filter chains, передача в функции, ожидающие iterable. См. Objects/genobject.c, PEP 289 (Generator Expressions, Python 2.4). Переходный мост к Phase 66 M05 (iterator/generator protocol).

Подробнее в уроках:

Iterator protocol

Iterator protocol
Термин

Контракт Python, описывающий, как объекты участвуют в итерации (`for`, `list()`, unpacking, comprehensions). Состоит из двух dunder-методов и одного fundamental signal. (1) `__iter__(self)` — возвращает iterator (объект с `__next__`); определён в Iterable ABC. Каждый вызов iter(iterable) обычно создаёт fresh iterator. (2) `__next__(self)` — возвращает следующее значение или raises `StopIteration`; определён в Iterator ABC. (3) Invariant `iter(it) is it` для proper iterator: метод `__iter__` у Iterator должен возвращать self (Iterator ABC defines this default `def __iter__(self): return self`). Без этого invariant for-loop ломается — внутренний iter() сбрасывал бы state. (4) StopIteration — control-flow signal (не error): for-loop ловит её через FOR_ITER opcode и завершается gracefully. Desugar `for x in iterable:` это `_it = iter(iterable); while True: try: x = next(_it); except StopIteration: break`. Iterable vs Iterator: iterable можно итерировать многократно (iter() даёт fresh iterator); iterator single-pass (после exhaustion `list(it)` возвращает []). Defined через ABCs в Lib/_collections_abc.py с structural typing через `__subclasshook__` — любой класс с правильными методами автоматически считается subclass. Cross-link M04 урок 02: __iter__ → tp_iter slot; __next__ → tp_iternext slot. См. Lib/_collections_abc.py Iterable + Iterator ABCs, docs.python.org/3/glossary.html#term-iterator.

Подробнее в уроках:

MRO (C3 linearization)

Method Resolution Order (C3)
Термин

Method Resolution Order — упорядоченный кортеж классов, по которому CPython идёт при attribute lookup. Хранится в `cls.__mro__` (Python) / `tp_mro` (C-struct PyTypeObject). Вычисляется один раз при создании класса через **C3 linearization** — алгоритм из работы Barrett, Cassel, Haahr, Moon, Playford, Withington (OOPSLA 1996, оригинально для Dylan; принят Python 2.3 в 2003). C3 гарантирует одновременно три constraints: (1) local precedence — порядок direct bases сохраняется, (2) monotonicity — порядок не переворачивается в subclass, (3) EPG consistency — родитель идёт раньше своих собственных родителей. Алгоритм: рекурсивный merge с правилом good head (head, не появляющийся в tail других списков). Если ни один head не good на каком-то шаге → невозможная linearization → TypeError 'Cannot create a consistent MRO'. Для diamond `D(B,C)` с `B(A), C(A)`: MRO = (D, B, C, A, object). Big-O: merge — O(n²·m²), irrelevant для production (один раз при class creation). См. Objects/typeobject.c функция mro_implementation; docs.python.org/3/howto/mro.html.

Подробнее в уроках:

PEP 393

Flexible String Representation
Термин

Python Enhancement Proposal 393 (Python 3.3, 2012) ввёл flexible string representation. До PEP 393 строки хранились как UCS-2 (narrow build, 16 бит/codepoint, не поддерживал non-BMP корректно) или UCS-4 (wide build, 32 бит/codepoint, тратил 4 байта даже на ASCII). После PEP 393 каждая строка во время создания выбирает kind = 1, 2 или 4 байта на codepoint в зависимости от max codepoint: PyUnicode_1BYTE_KIND для Latin-1 (≤ 0xFF), PyUnicode_2BYTE_KIND для BMP (≤ 0xFFFF), PyUnicode_4BYTE_KIND для non-BMP (≤ 0x10FFFF). Для pure-ASCII строк используется отдельная компактная структура PyASCIIObject (ASCII fast path), без UTF-8 cache и kind/maxchar полей. Одна non-BMP char (например emoji) поднимает kind всей строки до 4, что критично для memory profile логов с occasional emoji. См. Objects/unicodeobject.c, Include/cpython/unicodeobject.h.

Подробнее в уроках:

PurePath / PurePosixPath

pathlib PurePath
Термин

Pathlib (PEP 428, Python 3.4+) provides двухуровневую class hierarchy: `PurePath` (abstract — pure string-based path arithmetic, NO FS access) и `Path` (concrete — добавляет FS operations через `.exists()`, `.read_text()`, `.glob()`). Subclasses: `PurePosixPath` (forced POSIX `/` separator), `PureWindowsPath` (forced Windows `\\`). `Path` auto-selects platform-specific subclass (`PosixPath` on Linux/macOS, `WindowsPath` on Windows). API tour: `.parent` (directory), `.name` (filename), `.stem` (filename без suffix), `.suffix` (last suffix включая dot), `.suffixes` (all suffixes), `.parts` (tuple), `/` operator (concatenation), `.with_suffix(new)` (replace last suffix), `.with_name(new)`, `.with_stem(new)` (3.9+), `.relative_to(other)`. **Pitfall 34:** `/` operator with absolute right-side overrides parent (`PurePosixPath('/foo') / '/bar'` → `PurePosixPath('/bar')` per RFC 3986); use constructor `PurePosixPath('/foo', 'bar')` для multi-part. **Pitfall 22:** Pyodide MEMFS limited disk operations — browser challenges используют `PurePosixPath` для string-only path arithmetic (М09 урок 06 Pattern 3). Real disk operations — Run-on-Your-Machine callout (local Python). Cross-platform Production rule: используйте pathlib везде где не нужна performance — readable + immutable + introspectable. Cite Lib/pathlib.py + PEP 428.

Подробнее в уроках:

PyDictObject

PyDictObject
Термин

Внутренний C-тип Python dict в CPython. Структура: PyObject_HEAD + Py_ssize_t ma_used (число valid entries) + uint64_t ma_version_tag (PEP 509 для attribute caches) + PyDictKeysObject *ma_keys (compact PEP 468 layout: dk_indices + dk_entries) + PyObject **ma_values (для split-keys dict, иначе NULL). Lookup через lookdict() в Objects/dictobject.c: hash → probe в dk_indices → entry_idx → dk_entries[entry_idx]. Open addressing с perturbation probe: i = (5*i + 1 + perturb) & mask, perturb >>= PERTURB_SHIFT. Load factor ≤ USABLE_FRACTION = 2n/3; resize ×2 + rehash при превышении. Insertion order preserved (3.7+ language guarantee) — dk_entries dense and sequential. См. Objects/dictobject.c, talk Hettinger 'Modern Dictionaries' (PyCon 2017).

Подробнее в уроках:

PyGenObject

PyGenObject
Термин

C-структура, представляющая generator объект на уровне CPython runtime — обёртка вокруг саспенднутого stack frame. Generator function (функция с `yield` в теле) при вызове не исполняет тело — компилятор ставит флаг `CO_GENERATOR` (=0x20) на co_flags code object'а; CPython аллоцирует PyGenObject со свежим PyFrameObject. 5 ключевых полей (Include/cpython/genobject.h): gi_frame — saspended PyFrameObject (содержит локальные переменные, evaluation stack, instruction pointer f_lasti); gi_code — PyCodeObject с CO_GENERATOR flag; gi_running — bool reentrancy guard (защита от next() recursion из самого frame); gi_name — str для repr; gi_qualname — qualified name для tracebacks. Дополнительно: gi_yieldfrom (target subgenerator при yield from), gi_exc_state (exception machinery). Resume mechanism: `gen_send_ex` (Objects/genobject.c) проверяет primed-rule, push arg на evaluation stack, link frame в thread state, вызывает `_PyEval_EvalFrameEx`. Suspend: `YIELD_VALUE` opcode (Python/ceval.c) сохраняет f_stacktop + f_lasti, returns value из bytecode interpreter. Frame жив (heap-allocated) между yields — все локальные переменные persist. Memory profile (verified cpython-3.12.7): sys.getsizeof(generator) ≈ 176-200 байт constant независимо от количества yields; vs `[i*i for i in range(10**6)]` ≈ 8 MB list — соотношение ~45 000×. Generator expression `(expr for x in it)` — anonymous generator function, тот же PyGenObject. Cross-link M03 урок 03 — gen-expr IS generator function syntax sugar. См. Objects/genobject.c, Include/cpython/genobject.h, Python/ceval.c TARGET(YIELD_VALUE).

Подробнее в уроках:

PyListObject

PyListObject
Термин

Внутренний C-тип Python list в CPython. Структура: PyObject_VAR_HEAD (ob_refcnt + ob_type + ob_size = 24 байта на 64-bit) + PyObject **ob_item (указатель на отдельно-аллоцированный массив указателей PyObject*) + Py_ssize_t allocated (capacity ≥ ob_size). Lst[i] делается direct array access за O(1): `ob_item[i]`. List имеет capacity headroom для amortized O(1) append: при `ob_size < allocated` append просто пишет указатель в `ob_item[ob_size++]`. Иначе вызывается list_resize с geometric growth ~1.125x. Контраст с PyTupleObject: list имеет два allocations (header отдельно, ob_item массив отдельно), что позволяет realloc без invalidate'а указателя на header. См. Objects/listobject.c, Include/cpython/listobject.h.

Подробнее в уроках:

PyLong

PyLong
Термин

Внутренний C-тип для целых чисел в CPython. PyLong хранит число как массив 30-битных digit'ов (на 64-битных платформах): структура PyObject_HEAD (16 байт refcount + type pointer) + ob_size (8 байт; знак + |число digits|) + ob_digit[] (uint32 массив, использующий нижние 30 бит каждого элемента). Arbitrary precision: размер ob_digit растёт динамически при арифметике, поэтому Python int не переполняется. Базовый overhead — 24+ байт даже для нуля. Цена за безопасность от overflow — каждое целое heap-allocated. См. Objects/longobject.c, Include/cpython/longintrepr.h. 30-bit digit (вместо 32) выбран так, чтобы умножение двух digit'ов помещалось в uint64_t без overflow — это упрощает schoolbook/Karatsuba-умножение в long_mul.

Подробнее в уроках:

PyTupleObject

PyTupleObject
Термин

Внутренний C-тип Python tuple в CPython. Структура: PyObject_VAR_HEAD + PyObject *ob_item[1] (C99 flexible array member). При создании tuple размером N CPython аллоцирует один блок памяти sizeof(PyTupleObject) + (N-1) * sizeof(PyObject*) — header и ob_item в одном malloc'нутом блоке (vs list где они разделены). Преимущества single allocation: меньше allocator overhead, лучше cache locality для маленьких tuple. Tuple immutable: ob_size зафиксирован на all lifetime, нет capacity headroom. Поэтому tuple hashable (stable hash) и может быть dict key. Free-list cache для tuples ≤ 20 элементов в numfree[PyTuple_MAXSAVESIZE] экономит malloc/free overhead для частых маленьких tuple ('*args', dict.items, multi-return). См. Objects/tupleobject.c, Include/cpython/tupleobject.h.

Подробнее в уроках:

PyTypeObject

PyTypeObject
Термин

Внутренний C-тип CPython, представляющий класс на уровне runtime. Объявлен в Include/cpython/object.h как `struct _typeobject` (~70 полей). Каждый Python-class (built-in int/list/dict, user-defined) — runtime instance этой структуры. Ключевые поля: tp_name (имя класса, C-string), tp_basicsize (размер instance в байтах для memory allocation), tp_dict (PyDictObject со всеми class attributes/methods), tp_mro (PyTupleObject — method resolution order), tp_bases (tuple прямых баз), tp_init/tp_new/tp_dealloc (allocation lifecycle), tp_dictoffset (offset до instance __dict__ внутри instance memory layout), tp_call/tp_getattro/tp_setattro (slot wrappers protocol). type — its-own-metaclass: `type(type) is type`. См. Include/cpython/object.h, Objects/typeobject.c функция type_new_impl. Cross-link M02 урок 03 (instance __dict__ это PyDictObject — тот же hash table).

Подробнее в уроках:

Reference counting

Reference counting
Термин

Стратегия автоматического управления памятью CPython. Каждый PyObject имеет поле ob_refcnt (Py_ssize_t), хранящее число активных ссылок на объект. Каждое присваивание имени или передача в функцию инкрементирует счётчик через макрос Py_INCREF; каждый выход из scope, rebinding или явный del декрементирует через Py_DECREF. Когда счётчик доходит до 0, CPython вызывает __del__ (если определён) и освобождает память немедленно — это даёт детерминированную деаллокацию (в отличие от tracing GC). sys.getrefcount(x) возвращает refcount + 1 (сам аргумент функции — это +1 ссылка). Refcount-only стратегия не справляется с циклическими ссылками, поэтому CPython дополняет её generational garbage collector (модуль gc, Modules/gcmodule.c), который периодически обходит достижимые объекты и собирает циклы. См. Include/object.h макросы Py_INCREF/Py_DECREF.

Подробнее в уроках:

Type hint (PEP 585 / PEP 604)

Type hint (modern Python 3.13)
Термин

Modern Python 3.13 type-hint vocabulary — built-in generics из PEP 585 (Python 3.9, 2020) и union syntax из PEP 604 (Python 3.10, 2021). PEP 585 добавил `__class_getitem__` метод built-in типам (`list`, `dict`, `set`, `tuple`, `frozenset`, `type`), позволяющий писать `list[int]`, `dict[str, V]`, `tuple[T, ...]`, `set[T]`, `type[C]` напрямую — без import из typing модуля. Возвращает `types.GenericAlias` instance с `__origin__` (built-in type, например list) и `__args__` (кортеж parameter types). PEP 604 ввёл inline union syntax `X | Y` (заменяет старую форму `Union[X, Y]`) и `X | None` (заменяет `Optional[X]`); runtime — `types.UnionType` instance с `__args__=(int, NoneType)`, поддерживающий isinstance(x, int | None). Modern syntax invariant курса M07/M08: используются ТОЛЬКО PEP 585/604 формы — Wave 0 lint validate-no-deprecated-typing.cjs (Plan 67-01) блокирует 12 deprecated forms (List/Dict/Set/Tuple/Union/Optional/Callable/Iterable/Iterator/Sequence/Mapping/MutableMapping импортируемые из typing). Type hints в Python — **аннотации** (хранятся в `__annotations__` dict функций/классов), но Python interpreter их **не enforce'ит**: `def f(x: int)` спокойно вызывается с `f('hello')`. Type checking — отдельный static-analysis инструмент: mypy (reference impl), pyright (Microsoft), ty (Astral.sh). Cross-link M02 урок 06: `tuple[int, ...]` — typed extension паттерна 'immutable hashable handle'. Cross-link M07 урок 07: `mypy --strict file.py` — production hygiene. Cite: PEP 585 (peps.python.org/pep-0585), PEP 604 (peps.python.org/pep-0604), Lib/types.py GenericAlias + UnionType, Objects/genericaliasobject.c.

Подробнее в уроках:

TypedDict

TypedDict
Термин

Класс из typing модуля (`typing.TypedDict`) для типизации **dict-as-record** pattern. Введён PEP 589 (Python 3.8, 2018), расширен PEP 655 (Python 3.11, 2022) с Required/NotRequired per-key optionality control. Use case: typed контракт для JSON API responses, configs, message envelopes — pattern dict с известными ключами и типами значений. Example: `class User(TypedDict): id: int; name: str; email: str` + `alice: User = {'id': 1, 'name': 'alice', 'email': '[email protected]'}`. Critical observation: **runtime — обычный dict** (`type(alice) == dict`, `isinstance(alice, dict) == True`); никакого custom класса; никакого runtime overhead. TypedDict — **только** static type-checker механизм (mypy / pyright проверяют ключи и типы values статически). Совместим с json.loads (returns dict, type-cast'ится в TypedDict без runtime validation — production combine с Pydantic / marshmallow для validation). PEP 655 расширение — Required[X] / NotRequired[X] для per-key optionality control: до 3.11 был binary `total=True` (все required) или `total=False` (все optional); per-key позволяет mixed. Example: `class APIResponse(TypedDict): status: int; data: Required[dict]; error: NotRequired[str]; cached: NotRequired[bool]` — status и data обязательны, error и cached optional. Combinable с total=False. Это решает реальную проблему API typing — большинство responses имеют mixed required/optional fields. Альтернативные подходы: @dataclass (M04 урок 05) — full Python class с runtime support, но overhead instance creation; namedtuple — immutable but no per-field optionality; Pydantic BaseModel — runtime-validated. TypedDict — middle ground: typed для dev experience, dict для performance. Cross-link M02 урок 03 (PyDictObject — hash table internals). Cite: PEP 589 (peps.python.org/pep-0589), PEP 655 (peps.python.org/pep-0655), Lib/typing.py TypedDict + Required + NotRequired classes.

Подробнее в уроках:

Walrus operator (PEP 572)

Assignment expression (walrus operator)
Термин

Оператор присваивания-выражение `:=`, введён PEP 572 (Python 3.8+). Выполняет присваивание и одновременно возвращает значение — позволяет записать результат вычисления внутри условия / comprehension без отдельной строки. Использование: уменьшает дублирование вычислений (`while (chunk := f.read(8192)):`), упрощает чтение `if (m := pattern.match(line)) is not None:`. Ограничения: нельзя использовать на верхнем уровне выражения присваивания (`x := 5` синтаксическая ошибка — нужна обёртка `(x := 5)`); внутри comprehension scope — захватывает переменную в внешний scope (PEP 572 §«Scope of the target»).

Пример:
# Без walrus — двойной вызов
data = process()
if data:
    handle(data)

# С walrus — одна строка, одно вычисление
if (data := process()):
    handle(data)

# Comprehension использование (PEP 572 §scope)
result = [y for x in items if (y := transform(x)) is not None]
Подробнее в уроках:

yield from

`yield from` (PEP 380)
Термин

Синтаксис делегирования к подгенератору, введённый PEP 380 (Python 3.3, 2012). Форма: `yield from sub_gen` внутри generator function. Это НЕ синтаксический сахар для `for x in sub_gen: yield x` — это full proxy semantics: outer generator делегирует ВСЁ управление к sub_gen. Forwards: (1) yields — все значения из sub проксируются caller'у. (2) sends — outer.send(v) → sub.send(v); это критично для coroutines. (3) throws — outer.throw(E) → sub.throw(E); sub может catch через try/except. (4) closes — outer.close() → sub.close(); sub's try/finally блоки run для cleanup. Hand-rolled `for x in sub: yield x` форвардит ТОЛЬКО yields — теряет sends, mishandles throws (kills outer), не вызывает sub's finally (потенциальная утечка resources). Implementation: PyGenObject имеет поле gi_yieldfrom (pointer на текущий sub при yield from). gen_throw / gen_close в Objects/genobject.c проверяют это поле и проксируют операцию. Captures sub's StopIteration.value: `result = yield from sub()` присваивает return value sub'а к result. Use cases: (1) Chain composition — `def chain(*its): for it in its: yield from it` (Pythonic flatten, эквивалент itertools.chain). (2) Recursive tree-walker — `yield node['value']; for c in children: yield from walk(c)`. (3) Refactor extraction — длинную coroutine разбить на mini-flows и склеить. Это была foundation для asyncio coroutines в Python 3.4-3.5 до async/await (PEP 492). См. PEP 380 (peps.python.org/pep-0380), Objects/genobject.c gen_throw (~80 LoC) и gen_close (~50 LoC).

Подробнее в уроках:

Паттерны

@contextlib.contextmanager

`@contextmanager` decorator
Термин

Decorator из stdlib (`Lib/contextlib.py`), оборачивающий generator function в `_GeneratorContextManager` — один из самых elegant patterns Python. Превращает 5-строчный класс с __enter__/__exit__ в 3-строчную generator-функцию: `@contextmanager def cm(): setup; try: yield val; finally: teardown`. yield внутри generator — boundary между __enter__ (всё ДО yield, runs при context-manager.__enter__()) и __exit__ (всё ПОСЛЕ yield, runs при context-manager.__exit__()). Implementation: contextmanager(func) возвращает helper-closure, замыкающую func; при вызове helper(*args) создаётся _GeneratorContextManager instance. _GeneratorContextManager.__enter__ вызывает next(self.gen) — runs тело generator до первого yield, returns yielded value caller'у. _GeneratorContextManager.__exit__ на normal path вызывает next(self.gen) — runs тело после yield (включая finally block); на exception path — self.gen.throw(exc_type, exc_val, exc_tb) injects exception в yield point, finally блок ловит и runs cleanup. EDUCATIONAL CLIMAX Phase 66: @contextmanager синтезирует три primitives — closure (M03 урок 04, PyCellObject + LOAD_DEREF — helper замыкает func) + generator function (M05 урок 02, PyGenObject + CO_GENERATOR + YIELD_VALUE — функция с yield) + context-manager protocol (M06 урок 04, __enter__/__exit__ tri-arg). Three primitives — один elegant pattern. Pitfall 10: yield БЕЗ try/finally — teardown пропускается на exception path (самый частый bug; gen.throw injects exception, без finally exception пропагирует наверх по generator frame, код после yield не runs); каждый @contextmanager generator обязан иметь try/finally вокруг yield. Дополнительные contextlib рецепты: suppress(*exceptions) — idiomatic try/except/pass replacement; redirect_stdout(target) / redirect_stderr(target) — capture output; closing(thing) — wrap объекты с .close()-методом, но без __enter__/__exit__; ExitStack — variable-count resources с LIFO cleanup, stack.enter_context(cm) для dynamic acquisition. Forward-link Phase 67 pytest yield-fixtures используют точно этот pattern. Cite: Lib/contextlib.py — _GeneratorContextManager, contextmanager, suppress, redirect_stdout, ExitStack.

Подробнее в уроках:

@functools.wraps

`@functools.wraps`
Термин

Декоратор из stdlib (`Lib/functools.py`), копирующий metadata из оригинальной функции в wrapper — обязательная hygiene для любого production-grade декоратора. Применяется к wrapper'у: `@wraps(fn) def wrapper(...)`. Без него wrapper.__name__ возвращает 'wrapper' (локальное имя в исходнике), wrapper.__doc__ — None, inspect.signature — (*args, **kwargs); ломает introspection — pytest reports (10 декорированных тестов → 10 'wrapper FAILED'), Sphinx documentation, traceback formatter, IDE autocomplete. Implementation: wraps(fn) возвращает partial(update_wrapper, wrapped=fn) — это decorator-factory; при применении к wrapper'у вызывает update_wrapper(wrapper, fn). Что копирует: WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__annotations__', '__doc__') — 5 атрибутов через setattr; WRAPPER_UPDATES = ('__dict__',) — обновляет (merge'ит) wrapper.__dict__ из fn.__dict__ для custom attrs. Дополнительно устанавливает wrapper.__wrapped__ = fn (last) — для inspect.unwrap chain following: множественное декорирование @a @b @c def f → f.__wrapped__.__wrapped__.__wrapped__ → оригинал; inspect.signature(decorated) автоматически следует __wrapped__ для возврата signature оригинала. Низкоуровневый API — `update_wrapper(wrapper, wrapped, assigned=..., updated=...)` — прямой вызов без decorator-syntax; используется когда wrapper — instance класса (не function): `update_wrapper(self, fn)` в __init__ class-based decorator'а лечит Pitfall 4 (lost __name__ функции). Cite: Lib/functools.py — WRAPPER_ASSIGNMENTS, update_wrapper, wraps. Production rule: каждый production-декоратор обязан включать @wraps(fn) — это не optional, это обязательная hygiene. Cross-link M03 урок 04: @functools.lru_cache (параметризованный pattern, как @retry).

Подробнее в уроках:

Декоратор

Decorator (function/class)
Термин

Функция (или класс), принимающая функцию и возвращающая функцию (обычно — wrapper). Синтаксический сахар `@decorator` поверх `def f` — буквальный эквивалент `f = decorator(f)`: compiler сначала исполняет def f (создаёт function object), потом сразу `f = decorator(f)`. Имя f после декорирования связано с тем, что вернул decorator(f) — обычно closure-based wrapper или class-based instance. Closure-based pattern: nested def внутри def, замыкающая оригинальную функцию через PyCellObject (M03 урок 04 — wrapper.__closure__[0].cell_contents IS оригинал; cite Objects/cellobject.c, LOAD_DEREF в Python/ceval.c). Class-based pattern: `__init__(self, fn)` сохраняет fn, `__call__(self, *a, **kw)` вызывает; instance — wrapper, callable благодаря tp_call slot (M04 урок 02). Параметризованный декоратор (`@retry(max_attempts=3)`) требует three nested defs: factory(params) → real_decorator(fn) → wrapper(*a, **kw); каждый уровень — closure. Use cases: cross-cutting concerns (timing, retry, auth, logging, caching) — aspect-oriented programming идиоматично через `@`-syntax без дублирования boilerplate. Производственные примеры: @app.route (Flask), @app.get (FastAPI), @pytest.fixture, @functools.lru_cache, @dataclass, @property. Pitfall 1: wrapper без @functools.wraps теряет __name__/__doc__/__module__/__qualname__/__annotations__ (см. functools-wraps). Pitfall 4 для class-based: instance не имеет __name__ функции, нужен functools.update_wrapper(self, fn) в __init__. Декоратор — закономерное прикладное использование closure (M03), не новый primitive — это синтез existing primitives с aspect-oriented framing.

Подробнее в уроках:

Challenge Pattern 1/2/3/4

Code-challenge pattern taxonomy
Термин

Классификация кода-челленджей в python-course (RESEARCH Phase 65). Pattern 1 — pure stdlib transformation (input string → output string; e.g., regex parsing). Pattern 2 — algorithmic harness (input — структура данных, output — результат вычисления; e.g., `cProfile` introspection через `pstats`). Pattern 3 — capstone synthesis (multi-module skill — json + collections + statistics; production analytics). Pattern 4 — minimal greeting / first-Pyodide-run challenge (для M00 audience; introduces test harness convention). Каждый pattern имеет свой шаблон testCases (visible/hidden ratio, matchMode, timeoutMs). Cross-link: Plan 70-01 capstone — Pattern 3 instance.

Подробнее в уроках:

Copy-on-Write (pandas 2.0+)

Copy-on-Write semantics (pandas)
Термин

Pandas 2.0+ (April 2023) ввёл **Copy-on-Write (CoW)** opt-in (`pd.options.mode.copy_on_write = True`). Mechanism: все indexing operations (e.g., `df[mask]`, `df['col']`, `df.iloc[...]`) returns **lazy copy**; physical memory copy materializes только on first write. Под капотом — Arrow-backed memory + reference counting. **Эффекты:** (1) view-vs-copy ambiguity исчезает — все indexing предсказуемо; (2) `SettingWithCopyWarning` silently no-ops (chained assignment `df[mask]['col'] = value` modifies temporary copy, оригинал untouched); (3) explicit `df.loc[mask, 'col'] = value` остаётся правильным way mutating original df. **Production transition path:** opt-in pandas 2.x → audit + rewrite chained assignments → become-default pandas 3.0 (release date TBD). **Risk:** existing code, полагающийся на mutation through chained assignment, breaks silently под CoW — нужен audit. **Lesson takeaway:** запоминай `df.loc[mask, col] = value` (explicit, all-version-compatible) **always** — works ранее CoW; will continue работать после pandas 3.0 default switch. Cross-link к pre-CoW chained-assignment problem — root cause why CoW введён. Cite [pandas docs — Copy-on-Write user guide](https://pandas.pydata.org/docs/user_guide/copy_on_write.html).

Подробнее в уроках:

CSV-диалект

CSV dialect
Термин

В стандартной библиотеке Python модуль `csv` инкапсулирует все настройки парсинга/записи (delimiter, quotechar, lineterminator, quoting, escapechar, doublequote, skipinitialspace) в объект `Dialect`. Stdlib предоставляет три предустановленных dialect: `csv.excel` (default — запятая + `\r\n` + `QUOTE_MINIMAL`), `csv.unix_dialect` (запятая + `\n` + `QUOTE_ALL`), `csv.excel_tab` (TSV — `\t` + `\r\n`). Custom dialects регистрируются через `csv.register_dialect(name, **opts)`. Quoting константы: `QUOTE_MINIMAL` (default — quote только fields с delimiter/quotechar/newline), `QUOTE_ALL`, `QUOTE_NONNUMERIC` (auto-cast в float on read), `QUOTE_NONE` (escape via escapechar). Production rule — pin dialect explicit для consistency между producer и consumer; `csv.Sniffer` — heuristic для unknown formats (CLI tools, one-off ETL). Cross-course parallel: ClickHouse `format_csv_delimiter` setting + Spark `option('delimiter', ...)` — same dialect concept distributed. Cite Lib/csv.py + RFC 4180.

Подробнее в уроках:

Data vs non-data descriptor

Data descriptor
Термин

Различие, определяющее lookup precedence в Python attribute access. Data descriptor: имеет `__set__` или `__delete__` (или оба) в дополнение к `__get__`. Примеры: @property (всегда определяет __set__, даже если setter не задан — он raises AttributeError; но факт __set__ есть → property это data descriptor), custom typed-attribute classes (Positive, TypedAttr с __set__ для validation). Non-data descriptor: ТОЛЬКО __get__ (без __set__/__delete__). Примеры: @classmethod (returns method bound to class), @staticmethod (returns function as-is), обычные functions (когда attached к classу через def — становятся non-data descriptors). Lookup precedence (enforced в _PyObject_GenericGetAttrWithDict, Objects/object.c): (1) data descriptor в classes по MRO выигрывает, (2) instance __dict__, (3) non-data descriptor в classes по MRO. Это значит: @property нельзя 'обойти' прямой записью в obj.__dict__ (data desc всегда вызывается); но @classmethod можно 'затенить' через obj.method = lambda: ... (non-data desc проигрывает instance dict). Дизайн-выбор: property — runtime enforcement; classmethod — mockable through instance. См. Objects/typeobject.c type_getattro_impl, Objects/descrobject.c.

Подробнее в уроках:

Eager DataFrame evaluation (pandas)

Eager DataFrame evaluation
Термин

Pandas (2008+) использует **eager evaluation** — каждая operation (`df.filter(...)`, `df.groupby(...)`, `df.merge(...)`) вычисляется **немедленно** при invocation. Returns concrete DataFrame в памяти. **Trade-offs:** (+) interactive REPL friendly — `df.head()` immediately inspectable, debuggable стек traces (line numbers соответствуют user код); (+) no query planning overhead для одно-step operations; (-) no query optimization (predicate pushdown, projection pushdown, common subexpression elimination все невозможны); (-) intermediate results materialize в RAM (memory pressure для large datasets). **Cross-library memory model:** pandas default — `numpy.ndarray` backing для columns (cross-link M02 урок 01 PyListObject contiguous memory — same architectural primitive, no extra PyObject indirection); pandas 2.0+ Arrow-backed dtypes opt-in (`dtype_backend='pyarrow'`). **DataFrame architecture:** dict of Series; Series — labeled 1D ndarray + index. **Production positioning:** pandas — interactive Jupyter / REPL / quick scripts / small data <1GB. Production ETL workloads at medium scale — **dataframe-lazy** Polars ([dataframe-lazy] glossary entry); distributed scale — Spark / DataFusion. Cross-course: Spark M03 dataframes-spark-sql — distributed equivalents (DataFrame creation, joins, groupby). Cite [pandas docs — User Guide](https://pandas.pydata.org/docs/user_guide/index.html) + [pandas Internals](https://pandas.pydata.org/docs/development/internals.html).

Подробнее в уроках:

JSON streaming (JSONL)

JSON streaming / JSON Lines
Термин

JSONL (JSON Lines, a.k.a. NDJSON — Newline-Delimited JSON) — text format, где каждая `\n`-separated line — independent valid JSON object. В отличие от monolithic `[{...}, {...}]` JSON array, JSONL streamable — parser обрабатывает one line at time, constant memory per record. Stdlib pattern: `for line in buf: obj = json.loads(line.strip())` — leverages file iterator (cross-link M05 урок 02 — generator-like protocol `_io.TextIOWrapper.__next__`). Advanced — `json.JSONDecoder.raw_decode(s, idx)` returns `(obj, end_pos)` для multi-document JSON без newline separators. Production formats supporting JSONL: BigQuery `LOAD DATA`, ClickHouse `INSERT FORMAT JSONEachRow`, OpenAI fine-tuning datasets, AWS CloudWatch Logs ingest. **Three-layer bridge:** stdlib `json.loads(line)` (Python single-process) → Spark `spark.read.json(multiLine=False)` (distributed JVM cluster) → ClickHouse `JSONEachRow` (vectorized columnar OLAP). Same format, three execution layers. Cite Lib/json/decoder.py + RFC 8259.

Подробнее в уроках:

Lazy DataFrame evaluation (Polars)

Lazy DataFrame evaluation
Термин

Polars (2020+) supports **lazy evaluation** через LazyFrame API (`pl.scan_csv` / `pl.scan_parquet` returns LazyFrame; `pl.read_csv` — eager DataFrame). LazyFrame builds **query plan AST** — operations (`.filter`, `.select`, `.group_by`, `.agg`) добавляют AST nodes, **не выполняясь**. Computation triggered at terminal operation (`.collect()`, `.fetch(n)`, `.collect_schema()`). **Query optimizer rewrites plan перед execution:** (1) **predicate pushdown** — `filter` pushed к scan layer (для Parquet — use row-group min/max statistics для skip целых row groups); (2) **projection pushdown** — unused columns dropped к scan (читается только subset); (3) **common subexpression elimination** — repeated `pl.col(...) * 1.2` evaluated once; (4) **type coercion** — auto-cast где нужно. **Concept ladder lazy в Python:** (1) iteration-level (M05 урок 02 generator yield, PyGenObject — defer per-step), (2) expression-level (Polars LazyFrame — defer entire query), (3) distributed plan (Spark RDD lineage / DAG, DataFusion query plan — defer + parallelize). **Production positioning:** Polars (lazy mode) — production ETL single-machine medium data (~100GB ceiling); replaces pandas at scale post-2024. Cross-course: DataFusion M02 architecture (logical-plan optimizer parallel architecture к Polars — same Rust + Arrow DNA); DataFusion M06 query-optimization (pushdown rules explicitly exposed как optimizer rules); Spark M03 distributed equivalent (RDD lineage = lazy). Cite [Polars User Guide — Lazy API](https://docs.pola.rs/user-guide/lazy/) + [Optimizations](https://docs.pola.rs/user-guide/lazy/optimizations/).

Подробнее в уроках:

Mock object (unittest.mock.MagicMock)

Mock object (unittest.mock.MagicMock)
Термин

Stand-in object из stdlib `unittest.mock` модуль (`Lib/unittest/mock.py`), substituted на real object для **isolation** unit tests от external dependencies (DB connections, HTTP clients, time, random, file I/O). Mocks делают tests **fast** (no network), **deterministic** (no flaky external state), **side-effect-free** (no real emails sent / real DB rows mutated). Verify **interaction contract** между code и dependency — не duplicate behavior, а check call patterns. **`MagicMock`** — default mock class: callable + auto-implemented magic methods (`__call__`, `__getattr__`, `__iter__`, `__enter__`/`__exit__`, comparison) — drop-in replacement любого object including context managers и iterables. **3 ключевые capabilities:** (1) **Auto-attribute access** — `mock.deeply.nested.attr` works any depth, returns chain of MagicMock instances. (2) **Configurable behavior** — `MagicMock(return_value=42)` (mock() returns 42), `MagicMock(side_effect=ValueError('fail'))` (raises Exc), `MagicMock(side_effect=lambda x: x*2)` (function call). (3) **Call tracking** — `.called` (bool), `.call_count` (int), `.call_args` (last call), `.call_args_list` (all calls). Assertions: `.assert_called_with(args, kwargs)` (last call equality), `.assert_called_once()` (exactly one call), `.assert_not_called()` (zero calls). **`patch('module.attribute')`** — context-manager / decorator для temporary attribute replacement. **`patch.object(obj, 'attr', ...)`** (Pitfall 13) — patches attribute on already-imported instance/class — preferred when target в scope. Cross-link `descriptor-protocol` (M04 — `__getattr__` mock attribute resolution использует descriptor lookup). **Comparison к monkeypatch:** patch returns MagicMock (rich behavior verification), monkeypatch.setattr replaces с arbitrary value (simpler). Cite: [Lib/unittest/mock.py](https://github.com/python/cpython/blob/3.13/Lib/unittest/mock.py) — MagicMock + _patch.__enter__/__exit__; pytest 8 docs — monkeypatching variants (docs.pytest.org).

Подробнее в уроках:

monkeypatch (pytest fixture)

monkeypatch fixture
Термин

Built-in pytest fixture для **temporarily** mutating attributes / environment variables / sys.path / CWD во время теста, с **автоматическим undo** после test exit. Function-scoped (один instance per test function), pytest tracks все changes в LIFO undo stack — после test completion (success / fail / error) reverses все mutations. Это **isolation guarantee** — следующий test не видит leftover state. **API:** `monkeypatch.setattr('module.attr', value)` — set attribute by string path; `monkeypatch.setattr(obj, 'attr', value)` — set on instance; `monkeypatch.delattr('module.attr')` — delete; `monkeypatch.setenv('NAME', 'value')` — set env var; `monkeypatch.delenv('NAME')` — delete env var; `monkeypatch.syspath_prepend('/path')` — prepend sys.path; `monkeypatch.chdir('/path')` — change CWD. **Pitfall 17 (ScopeMismatch):** `monkeypatch` fixture — function-scoped. Cannot use внутри `@pytest.fixture(scope='session')` (session = broader). Pytest enforces rule: fixture scope ≥ scope of fixtures it requests. Session fixture requesting function-scoped monkeypatch → pytest raises `ScopeMismatch` at collection time. **Workaround:** `pytest.MonkeyPatch()` (uppercase, class — NOT fixture) — instantiate directly inside session fixture: `mp = pytest.MonkeyPatch(); mp.setenv('X', 'val'); yield resource; mp.undo()`. Identical API (setattr/setenv/etc), но **manual** lifetime control via `mp.undo()` в teardown. **Comparison к patch():** `unittest.mock.patch('module.attr')` — replaces attribute с MagicMock instance; rich behavior verification (`called`, `call_count`, `assert_called_with`). `monkeypatch.setattr` — replaces с **arbitrary** value (not necessarily mock) — simpler для env vars / config. Use mock when need behavior verification; monkeypatch when need attribute / env replacement. Cross-link `closure` (M03 урок 04 — env var capture pattern). Cite: pytest 8 docs — monkeypatching (docs.pytest.org/en/stable/how-to/monkeypatch.html).

Подробнее в уроках:

Mutable default argument trap

Mutable default argument trap
Термин

Pitfall: дефолтное значение параметра функции evaluated **один раз** at function-definition time и хранится в `func.__defaults__` tuple. Если default — mutable (list, dict, set), все вызовы без явного аргумента получают **один и тот же** объект, накапливая мутации. Пример: `def f(x, lst=[]): lst.append(x); return lst` — после `f(1); f(2)` второй вызов вернёт `[1, 2]`, не `[2]`. Корень: PyFunctionObject хранит default-tuple в func_defaults (Objects/funcobject.c), evaluated при executing `def`-statement. Каноничное решение — sentinel pattern: `def f(x, lst=None): if lst is None: lst = []; ...` — сравнение с `is None` вместо `== None` (identity check, None — singleton). Альтернативный sentinel: `_MISSING = object()` для случаев, где None — валидное значение. См. PEP 8, Python documentation 'Default argument values' note.

Подробнее в уроках:

Protocol (structural subtyping)

Protocol — structural subtyping
Термин

Класс из typing модуля (`typing.Protocol`) реализующий **structural subtyping** — typed duck-typing. Введён PEP 544 (Python 3.8, 2018). Объект совместим с Protocol классом если у него есть **нужные методы / атрибуты** — никакого inheritance не требуется. Example: `class Drawable(Protocol): def draw(self) -> str: ...` — любой класс с методом `draw() -> str` (Circle, Square, etc.) structurally compatible, mypy approve'ит passing в `def render(item: Drawable)`. Это **fundamental** отличие от ABC (abstract base class — nominal subtyping, M04 урок 04 cross-link): ABC требует explicit `class Foo(MyABC):` + реализации abstractmethod (verified runtime — `Foo()` raises TypeError если abstract method missing); Protocol — duck-typing с типами (verified static, mypy structural compat check). Use cases: framework принимает arbitrary objects от users без forced inheritance. Pitfall 15 — `isinstance(obj, MyProtocol)` raises TypeError по default; добавить `@runtime_checkable` декоратор для opt-in. После opt-in — runtime check проверяет ТОЛЬКО method existence (не signature accuracy), не для data attributes (Python ≤ 3.12). Performance cost: runtime-checkable Protocol slower nominal isinstance (итерация по required attrs). 90% production-кода — Protocol достаточно (не forced inheritance). Standard library примеры: `collections.abc.*` — гибрид (formal ABCs but with structural-like behavior через `__subclasshook__`); `typing.Iterable`, `typing.Sized`, `typing.Container` — predefined Protocols. Cross-link M04 урок 04: descriptors / @property nominal hierarchy через ABC; M07 урок 03 fills structural side. Cite: PEP 544 (peps.python.org/pep-0544), Lib/typing.py Protocol class.

Подробнее в уроках:

pytest fixture

pytest fixture
Термин

Decorator-based dependency injection mechanism в pytest для setup/teardown shared test environment'а. Function декорированная `@pytest.fixture` регистрируется как fixture; pytest **автоматически** инжектит fixture в test function, если test function запрашивает её через parameter name. Это inverse of `unittest.setUp/tearDown` — declarative dependency injection вместо overriding methods. **Two styles:** (1) **Return-style** — `@pytest.fixture def alice(): return User('alice')` — простой setup без teardown. (2) **Yield-style** — `@pytest.fixture def db(): conn = open(); try: yield conn; finally: conn.close()` — setup + teardown через yield boundary. **Climax cross-link M06 урок 05:** yield-style fixtures используют **тот же** pattern, что `@contextlib.contextmanager` — pytest's `_pytest/fixtures.py:resolve_fixture_function` reuses `_GeneratorContextManager`-like handler. yield служит boundary между `__enter__` (setup) и `__exit__` (teardown в try/finally). Synthesis chain: closure (M03 урок 04) + generator (M05 урок 02) + context-manager protocol (M06 урок 04) → @contextmanager (M06 урок 05) → @pytest.fixture(yield-style) (M08 урок 02). **Scope hierarchy** (Pitfall 16): `function` (default — N invocations) / `class` (per Test* class) / `module` (per *.py file) / `package` (per Python package) / `session` (one per pytest invocation). Broader scope — cheaper, but shared mutable state risk. Match scope с test independence. **Fixture dependencies:** fixtures sами могут request other fixtures как parameters; pytest resolves graph automatically. Rule: **fixture scope ≥ scope of fixtures it requests** (else `ScopeMismatch`). **Auto-discovery via conftest.py:** fixtures defined в `tests/conftest.py` propagate recursively во все test files под directory — no explicit import needed. Cross-link `context-manager-protocol` (M06 урок 04). Cite: pytest 8 docs — fixtures (docs.pytest.org), [_pytest/fixtures.py](https://github.com/pytest-dev/pytest/blob/main/src/_pytest/fixtures.py), [Lib/contextlib.py](https://github.com/python/cpython/blob/3.13/Lib/contextlib.py).

Подробнее в уроках:

pytest.mark.parametrize

pytest.mark.parametrize
Термин

Decorator из pytest для **data-driven testing**: один test function исполняется **много раз** с разными inputs из таблицы. Не копирование тестов — таблица test cases в одном месте: компактный код + readable failure logs. **Syntax:** `@pytest.mark.parametrize('argnames', argvalues, ids=..., indirect=..., scope=...)`. `argnames` — comma-separated string ('a,b,expected') или list. `argvalues` — list of tuples (multi-arg) или list of values (single-arg). pytest для каждого tuple генерирует отдельный test invocation с собственным name. **Default IDs** auto-generated из values — `test_add[2-3-5]`. **Custom `ids=['positive', 'zero', 'negative']`** дают readable names — `test_add[positive]` — failure logs read as specification. Production rule: always use `ids=` для long strings / complex objects. **`pytest.param(value, marks=..., id='...')`** — обёртка для per-row marks: skip / xfail / custom marker. Combine с `id='...'` для readability. Например `pytest.param('overflow_999...', None, marks=pytest.mark.xfail(reason='overflow case'), id='overflow')`. **Stacked decorators:** `@parametrize('x', [1,2]) @parametrize('y', [10,20])` дают **Cartesian product** (4 invocations: combinations всех axes). Use case: matrix testing input × Python version × OS. **Parallel framing** — `testCases` array в browser function-call mode (testRunner.ts:70-77 buildPyHarness) IS parametrize table — same shape, разные surfaces: `id` ↔ `ids[i]`, `input` ↔ argument tuple, `expectedOutput` ↔ expected, `matchMode='exact'/'contains'` ↔ assert variant. Browser challenges train pytest mental model. Cross-link `decorator-pattern` (M06). Cite: pytest 8 docs — parametrize (docs.pytest.org), [_pytest/python.py:Metafunc.parametrize](https://github.com/pytest-dev/pytest/blob/main/src/_pytest/python.py).

Подробнее в уроках:

Run on Your Machine

Run-on-Your-Machine callout
Термин

Convention learning-platform: блок `<Callout type="action">` в MDX-уроках, обозначающий упражнение, которое студент должен запустить локально (не в Pyodide). Используется когда пример требует stdlib / 3rd-party библиотек, недоступных в WASM-runtime (например, `psutil`, `socket`, `multiprocessing.Pool`, `subprocess`). Validator `validate-run-on-your-machine.cjs` проверяет, что в каждом курсе есть ≥20 callouts cumulative — pedagogical bridge от concept-only Pyodide к production tooling. Pattern enforced Phase 65-69.

Подробнее в уроках:

Type narrowing

Type narrowing (PEP 647 TypeGuard / PEP 742 TypeIs)
Термин

Механизм type checker (mypy / pyright) 'сужать' union types к specific type внутри branch'а. Без narrowing union types бесполезны: если функция возвращает `int | None`, mypy не позволит вызвать `x.bit_length()` без narrow'инга. **Automatic narrowing** patterns: `if x is None: return; ...` (после return — `x: int`, None excluded из union); `isinstance(x, T)` (внутри if body — `x: T`); `assert isinstance(x, T)` (narrowing + runtime check; pitfall — стирается с `python -O` flag); `==`/`!=` со constants; `match` patterns (PEP 634, Python 3.10+). PEP 604 unions поддерживают `isinstance(x, int | str)` runtime — combines два type checks. **Custom narrowing** через `TypeGuard[T]` (PEP 647, Python 3.10) — function с return type `TypeGuard[T]` сигналит mypy: True branch → `x: T`. Example: `def is_str_list(items: list[object]) -> TypeGuard[list[str]]: return all(isinstance(x, str) for x in items)` — без TypeGuard mypy не может вывести post-True narrowing. Asymmetric: True branch narrows к T, False branch unchanged. Runtime — обычный bool. **`TypeIs[T]`** (PEP 742, Python 3.13) — improved TypeGuard с symmetric narrowing: True → T, False → `X - T` (T removed из union). Closer к natural isinstance semantics. Forward-note курса M07 не использует (Pyodide ships 3.12; v2 курса prefer TypeIs). `assert_type(x, T)` (PEP 749, Python 3.11+) — mypy hint для debugging type inference, runtime no-op. Production rule: chain narrows для nullable/external input — explicit if isinstance + early return — mypy-friendly defensive programming. Pitfall: `python -O` strips assert — для production validation `if not isinstance(...): raise TypeError(...)` (никогда stripped). Cite: PEP 647 (peps.python.org/pep-0647), PEP 742 (peps.python.org/pep-0742), Lib/typing.py TypeGuard + TypeIs.

Подробнее в уроках:

Production-инструменты

Иерархия имён логгеров

Logger name hierarchy
Термин

Имя логгера (`logging.getLogger("a.b.c")`) формирует dotted-path иерархию: `a.b.c` — child of `a.b` — child of `a` — child of root. Уровень логирования и handlers наследуются через `logger.propagate=True` (default): сообщение поднимается вверх по иерархии до root, applying handlers на каждом уровне (если `propagate` не отключён). Convention: `logger = logging.getLogger(__name__)` в каждом модуле — `__name__` = dotted module path → автоматически отражает структуру package. Production pattern: настроить root logger с JSON-handler, включить `propagate=True` в child loggers — single point of configuration через `dictConfig`. Cross-link: M11 урок 01 (Logger / Handler / Formatter / Filter).

Пример:
import logging
logger = logging.getLogger("myapp.db.queries")
# myapp.db.queries → myapp.db → myapp → root
logger.setLevel(logging.DEBUG)
# Handlers root logger applies к всем нижестоящим, если propagate=True
Подробнее в уроках:

Bytecode opcode

Bytecode opcode (CPython)
Термин

Python bytecode — sequence of (opcode, argument) pairs executed by CPython interpreter loop (`Python/ceval.c`). Каждый opcode — single-byte instruction, argument — usually small int (index в local variable table, constant table, or jump offset). Stdlib `dis` модуль предоставляет introspection: `dis.dis(code_obj)` (prints to stdout — quick CLI), `dis.get_instructions(code)` (iterator of `Instruction` namedtuples — programmatic analysis, used in Pattern 4 `py-m12-04-code-1`), `dis.Bytecode(code).info()` (mid-level — programmatic + pretty print). **Common opcodes** (Python 3.11+): `RESUME` (function entry / generator resume marker — 3.11+ added); `LOAD_FAST n` (load local variable by slot n); `LOAD_CONST k` (load constant from `co_consts[k]` — literals); `LOAD_GLOBAL` (load global / builtin — `print`, module-level vars); `STORE_FAST n` (store top-of-stack to local slot n); `BINARY_OP op` (3.11+ unified arithmetic/comparison — was `BINARY_ADD`/`BINARY_SUBTRACT`/etc separately); `CALL n` (3.11+ unified function call с n args); `RETURN_VALUE` (pop top-of-stack, return); `LIST_APPEND` (mutate intermediate list — emitted in list comprehensions); `YIELD_VALUE` (yield top-of-stack — emitted in generator expressions / `yield` statements); `GET_ITER` + `FOR_ITER` (iterator protocol — `for ... in ...:` loop). **Generator vs list comp distinction visible in bytecode:** `[x*2 for x in range(3)]` emits `LIST_APPEND` per iteration (memory O(n) — full list materialized); `(x*2 for x in range(3))` emits `YIELD_VALUE` (memory O(1) — lazy iteration via PyGenObject machinery, cross-link M05 урок 02). **PEP 659 — specialized adaptive interpreter** (Python 3.11+) — opcodes могут rewrite themselves в runtime для type-specific paths (`BINARY_OP` → `BINARY_OP_MULTIPLY_INT` после type-feedback). Это даёт ~10-30% speedup для tight loops, но имеет side effect для `dis` output: opcode names version-sensitive (Pitfall 40). **Решение для testCases:** `matchMode='contains'` — assert presence of generic opcode ('LIST_APPEND', 'YIELD_VALUE', 'BINARY_OP') — robust к version drift / specialization. **Constant folding caveat** (3.13+): literal-only expressions (`1+2`) folded compiler'ом в `RETURN_CONST 3` — НЕ emit BINARY_OP; testCases используют variable references. **Pragmatic NOT D-07** — observable through public dis API; не deep-diving в `PyCodeObject` struct (M02-M03 territory). Cross-course → Spark [02 catalyst-tungsten](/spark-internals/06-catalyst-tungsten/) — Catalyst optimizer + Tungsten code-generation produces JVM bytecode для optimized query plan; same idea (compile high-level expression → low-level instructions). Cite [docs.python.org/3/library/dis.html](https://docs.python.org/3/library/dis.html) + [PEP 659](https://peps.python.org/pep-0659/).

Подробнее в уроках:

dictConfig schema

dictConfig schema (PEP 391)
Термин

logging.config.dictConfig schema — Python dict matching PEP 391 (Dictionary-Based Configuration For Logging, 2009) versioning convention. Required key: `version: 1` (loader проверяет `if config.get("version") != 1: raise ValueError`; currently только value 1 supported, allows future schema evolution без breaking changes). Optional keys: `disable_existing_loggers` (default True — replace mode), `incremental` (partial update), `formatters` (dict of named formatter specs), `handlers` (dict of named handler specs — class string `"logging.handlers.RotatingFileHandler"` или factory `"()"` callable + kwargs), `loggers` (dict of logger configs — keys = dotted names, `""` empty-string key = root), `root` (alternative root config), `filters`. Special syntactic markers: `"class"` — fully-qualified class name imported by dictConfig; `"()"` — callable factory (alternative class); `"ext://sys.stderr"` — extension protocol resolved at config time; `"cfg://handlers.console"` — cross-reference внутри config. **Status:** modern replacement для legacy fileConfig (INI-based, Python 2.x carryover, kept для backward-compat only). dictConfig source-agnostic — dict from json.loads / yaml.safe_load (NOT stdlib) / tomllib.loads (Python 3.11+, M13 урок 01) / Python literal. **Pyodide constraint:** challenge `py-m11-03-code-1` parses JSON dictConfig schema (stdlib `json`); YAML — Run-on-Your-Machine only (`pyyaml` НЕ stdlib, micropip FORBIDDEN per Phase 69 Wave 0). Cite [docs.python.org/3/library/logging.config.html#dictionary-schema-details](https://docs.python.org/3/library/logging.config.html#dictionary-schema-details) + [PEP 391](https://peps.python.org/pep-0391/).

Подробнее в уроках:

GIL (Global Interpreter Lock)

GIL (Global Interpreter Lock)
Термин

Global Interpreter Lock — мьютекс, защищающий CPython interpreter state. **Только один Python thread** может execute Python bytecode at any time. GIL прозрачен для programmer но имеет **observable consequences**: (1) threading **НЕ ускоряет** pure-Python CPU loop — все threads serialized via GIL; (2) GIL released **периодически** — interpreter switches threads every N bytecodes (default ~100, configurable via `sys.setswitchinterval(0.005)` — 5ms default); (3) GIL released **on I/O syscalls** — `socket.recv`, `file.read`, `time.sleep`, `select.select`, `os.read` — anything that blocks on kernel; (4) GIL released **на некоторых C-extensions** — операции release GIL via `Py_BEGIN_ALLOW_THREADS` / `Py_END_ALLOW_THREADS` macros (e.g., NumPy ndarray ops, Cython `with nogil:` blocks, ctypes calls в general); (5) GIL **NOT released** для most pure-Python operations (list/dict/string ops — work под GIL). **Pitfall 42** — programmer думает «threading parallelize my_compute()» — wrong если my_compute() pure Python CPU. Правильное решение: **multiprocessing** (`concurrent.futures.ProcessPoolExecutor` — separate processes own GIL → real CPU parallelism) или native code (Cython, C-extension). **Decision rule:** I/O-bound + ≤100 concurrent → threading; I/O-bound + 1000+ → asyncio (single-threaded event loop, ~10KB per coroutine vs ~1MB per OS thread); CPU-bound single machine → multiprocessing; CPU-bound big data → distributed (Spark / DataFusion). **PEP 703 — Making the Global Interpreter Lock Optional in CPython** (accepted 2023) — opt-in `--disable-gil` build flag в Python 3.13+; experimental, mainstream production usage — несколько лет work. Будущая direction но не настоящее. **Cross-course → Spark** [01/02 driver-executor-model](/spark-course/01-spark-foundations/02-driver-executor-model/) — Spark распределяет CPU work через separate JVM workers именно потому что Python GIL не позволяет threading-based parallelism. **Cross-course → DataFusion** [02/06 crate-architecture](/datafusion-course/02-architecture/06-crate-architecture/) — Rust no-GIL → real thread parallelism (pre-PEP 703 архитектура без single-thread limit). Cite [Python GIL FAQ](https://wiki.python.org/moin/GlobalInterpreterLock) + [PEP 703](https://peps.python.org/pep-0703/) + [docs.python.org/3/library/concurrent.futures.html](https://docs.python.org/3/library/concurrent.futures.html).

Подробнее в уроках:

Log formatter (logging.Formatter)

Log formatter
Термин

logging.Formatter — один из 4 building blocks stdlib logging (вместе с Logger / Handler / Filter; PEP 282). Renders LogRecord к **string** для writing handler'ом. Базовый класс через `format(record)` метод; default использует format string `%(asctime)s [%(levelname)s] %(name)s: %(message)s` (но любой `%(LogRecord_attribute)s` substitution работает). **Standard LogRecord attributes доступные в format string:** `name` (logger name), `levelname` ('INFO'/'WARNING'/...), `levelno` (10/20/...), `pathname`/`filename`/`module`/`funcName`/`lineno` (call site), `created` (Unix timestamp float), `msecs` (millisecond fractional), `asctime` (rendered datetime), `threadName`/`processName`, `message` (formatted msg). Full list — [docs.python.org/3/library/logging.html#logrecord-attributes](https://docs.python.org/3/library/logging.html#logrecord-attributes). **Custom subclass** для structured output (урок 02): `class JsonFormatter(logging.Formatter): def format(self, record): return json.dumps({'time': ..., 'level': record.levelname, 'msg': record.getMessage(), ...})`. **Key methods:** `format(record)` — main entry-point; `formatTime(record, datefmt)` — render asctime; `formatException(exc_info)` — render multi-line traceback (use `record.exc_info` если есть); `formatStack(stack_info)`. **Production pattern:** для local dev — text format; для production — JSON formatter (queryable в ClickHouse `system.text_log` / Loki / Datadog Logs / Elasticsearch). **`extra={}` integration** — `logger.info('msg', extra={'k': v})` injects attribute on LogRecord; Custom Formatter inspects через `record.__dict__.items()` minus standard attribute set (cross-link M07 урок 04 dataclass introspection — same pattern что `dataclasses.fields(obj)`). Cite [docs.python.org/3/library/logging.html#formatter-objects](https://docs.python.org/3/library/logging.html#formatter-objects).

Подробнее в уроках:

Log handler (logging.Handler)

Log handler
Термин

logging.Handler — один из 4 building blocks stdlib logging model (вместе с Logger / Formatter / Filter; PEP 282 design). Subclass routes LogRecord к destination после level check. **Stdlib subclasses** (subset; full в [logging.handlers](https://docs.python.org/3/library/logging.handlers.html)): StreamHandler (sys.stderr default; универсальный для console/Docker stdout); FileHandler (pure disk write — single file, no rotation); RotatingFileHandler (size-based rotation — `maxBytes` + `backupCount`; total disk = maxBytes × (backupCount+1)); TimedRotatingFileHandler (time-based — `when=` 'midnight'/'H'/'D'/'W0..W6' + `interval=`; daily log convention); SocketHandler (network destination — TCP/UDP); SysLogHandler (Unix syslog daemon); SMTPHandler (email alerts — careful — email rate limits!); MemoryHandler (in-memory buffer + flush к target handler — useful для batch writes); QueueHandler / QueueListener (decoupled producer/consumer threads — async logging primitives, Python 3.2+); HTTPHandler (POST к HTTP endpoint). **Key methods (subclass override):** `emit(record)` — actual write/send; `setLevel(level)` — handler-level filter (separate от Logger-level); `addFilter(filter)` / `removeFilter(filter)`; `setFormatter(formatter)` — bind Formatter. **Configuration via dictConfig (PEP 391):** `'class': 'logging.handlers.RotatingFileHandler', 'filename': '/var/log/app.log', 'maxBytes': 10485760, 'backupCount': 5`. **Pyodide constraint** (Phase 64 carrying): real disk write требует filesystem; Pyodide MEMFS limited (Pitfall 22) — RotatingFileHandler в browser challenge не сможет rotate реальные файлы; используйте StreamHandler(io.StringIO()) для browser-runnable testing. Cite [docs.python.org/3/library/logging.html#handler-objects](https://docs.python.org/3/library/logging.html#handler-objects) + [docs.python.org/3/library/logging.handlers.html](https://docs.python.org/3/library/logging.handlers.html).

Подробнее в уроках:

Log propagation (logger.propagate)

Log propagation
Термин

logging propagation — by-default behavior где LogRecord, emitted child logger, **propagates up** по hierarchy tree к each ancestor logger (вплоть до root) — каждый ancestor's handlers тоже его обрабатывают (если accept по level). Hierarchy формируется dotted names: `getLogger('app.db.query')` — child `getLogger('app.db')` — child `getLogger('app')` — child root logger (`logging.getLogger()`). Поток: child emit → child handlers (если есть) → propagate up → parent handlers → ... → root handlers. **`logger.propagate = False`** stops up-traversal — useful когда child logger имеет свой dedicated handler и не хочет дубликат от root; example — `app.audit` пишет ТОЛЬКО в audit-file (own FileHandler), не в general application log via root StreamHandler. **Subtle pitfall (related Pitfall 36 carrying):** duplicate handler registration через propagation chain — если root и child оба имеют StreamHandler, log line emit'ится дважды; either disable propagation (`logger.propagate = False`) или конфигурируйте только root (most common pattern). **Production rule:** обычно root configured один раз (через basicConfig или dictConfig), все module loggers (`getLogger(__name__)`) propagate к нему naturally; override `propagate = False` только для специальных routing cases (audit log, structured-only logger, separate destination). **dictConfig schema** (PEP 391): `'loggers': {'app.audit': {'level': 'INFO', 'handlers': ['audit_file'], 'propagate': false}}`. Cite [docs.python.org/3/library/logging.html#logger.propagate](https://docs.python.org/3/library/logging.html#logger.propagate) + [docs.python.org/3/library/logging.html#logger-objects](https://docs.python.org/3/library/logging.html#logger-objects).

Подробнее в уроках:

LogRecord extra

LogRecord `extra` parameter
Термин

Параметр `extra` в `logger.info(msg, extra={...})` (Python stdlib `logging`). Словарь, ключи которого добавляются как атрибуты к создаваемому `LogRecord` объекту — доступны в format strings (`%(custom_field)s`) и в structured-logging обработчиках (JSON formatter сериализует все extra-ключи). Ограничение: ключи не должны конфликтовать с reserved attributes `LogRecord` (`message`, `levelname`, `pathname`, etc.) — конфликт вызывает `KeyError` в логировании. Production pattern: correlation IDs (request_id, trace_id), tenant_id, user_id передаются через extra → JSON output → ingested ELK / Loki.

Пример:
import logging
logger = logging.getLogger(__name__)
logger.info("user login", extra={"user_id": 42, "tenant": "acme"})
# JSON formatter (M11 урок 02) сериализует:
# {"msg": "user login", "user_id": 42, "tenant": "acme", ...}
Подробнее в уроках:

psutil — process introspection

psutil.Process
Термин

Сторонняя cross-platform библиотека для system + process monitoring. `psutil.Process()` (current PID) или `psutil.Process(pid)` экспонирует CPU usage, memory (RSS / VMS / USS), open files, network connections, threads, child processes. `Process.memory_info().rss` — Resident Set Size в байтах (физическая память, занимаемая процессом — комплементарна к `tracemalloc` Python-heap трекингу). Production use: monitoring loop собирает RSS / CPU% и экспортирует в Prometheus (Counter / Gauge); alerts на memory leak (RSS monotonically растёт). Pyodide-limitation: НЕ работает в WASM (требует OS syscalls); пометка Run-on-Your-Machine. Cross-link: M12 урок 03 (tracemalloc Python-heap; psutil — process-level RSS).

Пример:
# Run on your machine — pip install psutil
import psutil, os
p = psutil.Process(os.getpid())
print(f"RSS: {p.memory_info().rss / 1024 / 1024:.1f} MB")
print(f"CPU%: {p.cpu_percent(interval=1.0):.1f}")
Подробнее в уроках:

RotatingFileHandler

logging.handlers.RotatingFileHandler
Термин

Handler из stdlib `logging.handlers`, ротирующий лог-файлы по размеру. Параметры: `maxBytes` (rollover порог в байтах) + `backupCount` (число backup файлов: `app.log.1`, `app.log.2`, ...). При достижении `maxBytes` текущий `app.log` переименовывается в `app.log.1`, старые файлы сдвигаются (старейший удаляется). Альтернатива — `TimedRotatingFileHandler` (rollover по времени: midnight / hourly / weekly). Production caveat: ротация выполняется в потоке логирования (sync I/O — может блокировать); для high-throughput сервисов используется `QueueHandler` + `QueueListener` чтобы вынести rollover в фоновый поток. Cross-link: M11 урок 03 (`dictConfig` пример с `RotatingFileHandler`).

Пример:
from logging.handlers import RotatingFileHandler
h = RotatingFileHandler("app.log", maxBytes=10_000_000, backupCount=5)
# 10 MB → rollover; хранит 5 предыдущих файлов
# Итого до 60 MB логов на диске
Подробнее в уроках:

Данные

Arrow IPC + C Data Interface

Apache Arrow IPC and C Data Interface
Термин

Apache Arrow — universal columnar in-memory format (since 2016). Состоит из (1) **memory layout spec** — fixed-width primitives contiguously, variable-length values + offsets buffer, separate null bitmap (cross-link M02 урок 01 PyListObject contiguous memory — extension cross-library); (2) **C Data Interface** — ABI-stable C struct (`ArrowSchema`, `ArrowArray`, `ArrowDeviceArray`) + reference counting — in-RAM handshake между libraries (pandas/Polars/DuckDB/Spark/DataFusion) без copy; (3) **IPC format** — bytes-on-wire equivalent для disk persistence или network transfer (Arrow Flight gRPC). PEP 749 standardises Python-level dunder methods (`__arrow_c_array__` / `__arrow_c_stream__` / `__arrow_c_schema__`) returning PyCapsule wrapping C Data Interface struct. **Production status (2026):** pandas 2.2+ producer; Polars 1.0+ producer + consumer; PyArrow 15+ full support; DuckDB 0.10+ Arrow-compatible result format. **Critical insight для DE:** zero-copy interop saves CPU + memory bandwidth для multi-library pipelines (pre-Arrow model — serialize/deserialize cycle per handoff = CPU + 2x memory). Cross-course: Storage Formats M07 (7 lessons Arrow deep dive — memory layout, type system, IPC format, Feather, Flight protocol, ecosystem); DataFusion M01 Arrow foundation (Rust FFI compatibility); Spark M11 Arrow Module + M06/03 Pandas UDFs. Cite [Apache Arrow Format spec](https://arrow.apache.org/docs/format/) + [PEP 749](https://peps.python.org/pep-0749/) + [PyArrow docs](https://arrow.apache.org/docs/python/).

Подробнее в уроках:

PyArrow zero-copy

PyArrow zero-copy interop
Термин

Передача Arrow-формат данных между Python библиотеками (pandas / Polars / DuckDB / PyArrow) без сериализации / десериализации. Реализация: C Data Interface (ABI-stable C struct `ArrowArray` + `ArrowSchema`) + PyCapsule wrapper (PEP 749, Python 3.12+). pandas 2.2+ → `df.__arrow_c_stream__()` возвращает Arrow stream; Polars 1.0+ принимает `__arrow_c_array__` как input. Преимущество vs CPython pickle / Apache Avro: ноль копий памяти buffer — receiver ссылается на тот же memory block через reference counting. Cross-course Storage Formats M07 разворачивает Arrow memory model + IPC format подробнее. Cross-link: M10 урок 03 (PyArrow concept).

Пример:
import pyarrow as pa, pandas as pd
ser = pd.Series([1, 2, 3])
arr = pa.array(ser)         # zero-copy: ser buffer reused
# Полное копирование произошло бы при .to_numpy().tolist()
Подробнее в уроках:

Инструментарий

Build backend (PEP 517)

Build backend (PEP 517)
Термин

Build backend — Python tool that builds wheels (.whl) и source distributions (sdist .tar.gz) из pyproject.toml. Specified в `[build-system].build-backend` table (PEP 517 — build-system independence, 2017). Frontend tools (pip / uv / build / poetry) invoke backend через standardized PEP 517 protocol — `build_wheel(wheel_dir, config_settings)`, `build_sdist(sdist_dir)`, опц. `build_editable(wheel_dir)` (PEP 660). **Common backends (2026):** `setuptools.build_meta` (legacy default; mature; complex API; default fallback для pip ≥21.3), `hatchling.build` (modern; fast; PEP 621 native; **recommended new projects** per packaging.python.org; from PyPA), `poetry.core.masonry.api` (Poetry-managed projects; pre-2.0 не понимал PEP 621, 2.0+ understands `[project]`), `flit_core.buildapi` (simple pure-Python projects; minimal config), `pdm.backend` (PDM projects), `maturin` (Rust extensions через [pyo3](https://pyo3.rs/) — генерирует platform-specific wheels с native code). **Decision:** новый pure-Python project → hatchling.build; existing setuptools project → migration optional; Rust extension → maturin. Backends реализуют PEP 517 protocol — frontends не должны знать setuptools-specifics; вся communication через ABI-stable build_wheel/build_sdist functions. **Cross-link M13 урок 01.** Cite [peps.python.org/pep-0517](https://peps.python.org/pep-0517/) + [hatch.pypa.io](https://hatch.pypa.io/) + [packaging.python.org/en/latest/key_projects/](https://packaging.python.org/en/latest/key_projects/).

Подробнее в уроках:

Deterministic profiler

Deterministic profiler (cProfile)
Термин

Deterministic profiler — profiler который instruments **every** function call/return через CPython hook (`sys.setprofile`). Captures exact `ncalls` (call count) + `tottime` (total time inside function без subcalls) + `cumtime` (cumulative time с subcalls). Stdlib `cProfile` — deterministic, написан в C для low-but-significant overhead (~30% slowdown). API: `cProfile.run('expr')` для quick CLI usage; `cProfile.Profile()` context-manager (cross-link M06 урок 04 protocol — `__enter__`/`__exit__`) для wrap selective regions. Output via `pstats.Stats(profile_data).sort_stats('cumulative').print_stats(20)` — output columns `ncalls / tottime / percall / cumtime / percall / filename:lineno(function)`. **Sort options:** `'cumulative'` (default top-down — slow chains), `'tottime'` (bottom-up — leaf hotspots), `'ncalls'` (called too often), `'name'` (alphabetic). **Contrast — sampling profilers** (py-spy, austin) — periodic stack dumps (~100 Hz default), <2% overhead, **production-safe**, attach к running process via /proc Linux **без code modification**. Decision rule: dev / pre-prod analysis (точные numbers) → cProfile; production diagnostics (low overhead + no code change) → py-spy. **Pyodide constraint** (Pitfall 38) — cProfile timing data unreliable в browser WASM event-loop interleaving; challenges (Pattern 2 `py-m12-02-code-1`) **парсят pre-captured pstats text** через regex (pure stdlib `re`), не запускают live cProfile invocations. Real cProfile run → Run-on-Your-Machine. **Observer effect:** cProfile overhead distorts results значительно для low-overhead functions (1µs functions могут показаться 5µs из-за hook cost) — для tight loops использовать `timeit` (минимальный overhead). Cross-course → Spark UI deterministic JVM profiler (off в production) vs sampling JFR / async-profiler (production) — same architectural split. Cite [docs.python.org/3/library/profile.html](https://docs.python.org/3/library/profile.html) + [docs.python.org/3/library/pstats.html](https://docs.python.org/3/library/pstats.html).

Подробнее в уроках:

Lock file

Dependency lock file
Термин

Lock file — precise dependency snapshot пинит exact versions для reproducible installs across machines/CI. **Three flavors (2026):** (1) `poetry.lock` (Poetry projects; complete dependency tree включая transitive paths; SHA256 hashes для verification; per-package metadata; tooling-friendly TOML; generated `poetry lock`, consumed `poetry install`); (2) `uv.lock` (uv projects; pubgrub solution snapshot; cross-tool standard candidate per Astral; generated `uv lock`, consumed `uv sync`); (3) `requirements.txt frozen` (pip + pip-tools; flat list `pkg==1.2.3`; нет dep tree information; generated `pip freeze`; rich variant via [pip-compile](https://pip-tools.readthedocs.io/) с transitive comments). **Reproducibility:** все три обеспечивают exact-version pinning, но poetry.lock / uv.lock дополнительно verifiable (hash check) + introspectable. PEP 665 (rejected 2021) предлагал стандартный lock format — отклонён, экосистема остаётся per-tool. **Recommend:** ВСЕГДА commit lock files в git для applications (NOT для libraries — даёт пользователям flexibility). Modern speed-critical → uv.lock; Poetry projects → poetry.lock; pip-only legacy → requirements.txt + pip-tools. **Cross-link M13 урок 04 + Spark Phase 12 cicd-lifecycle (CI deps pinning + Maven dependency mgmt parallel) + DataFusion 09 ecosystem (Cargo.lock parallel — Rust crates ecosystem).** Cite [docs.astral.sh/uv/concepts/lockfile](https://docs.astral.sh/uv/concepts/lockfile/) + [python-poetry.org/docs/cli/#lock](https://python-poetry.org/docs/cli/#lock) + [pip-tools docs](https://pip-tools.readthedocs.io/).

Подробнее в уроках:

mypy strict

mypy --strict mode
Термин

Режим mypy, активирующий все опциональные strictness-флаги: `--disallow-untyped-defs` (запрет def без annotation), `--disallow-any-explicit` (Any должен быть explicit), `--warn-return-any`, `--no-implicit-optional`, `--check-untyped-defs`, etc. Включается через `[tool.mypy] strict = true` в `pyproject.toml` или `--strict` CLI флаг. Production-recommended baseline для new modules; для legacy code — incremental adoption через per-module override `[[tool.mypy.overrides]] module = "legacy.*" strict = false`. Cross-course bridge: M07 урок 07 — Run-on-Your-Machine callout с pyproject.toml + mypy install.

Пример:
# pyproject.toml
[tool.mypy]
strict = true
python_version = "3.13"

# CLI
mypy --strict src/
Подробнее в уроках:

prometheus_client

prometheus_client (Python)
Термин

Официальная Python-библиотека для экспорта метрик в Prometheus формате. Четыре типа метрик: `Counter` (monotonic — request count, error count), `Gauge` (instantaneous — queue size, memory usage), `Histogram` (bucketed observations — latency), `Summary` (quantiles — p50/p95/p99). HTTP endpoint `/metrics` через `start_http_server(8000)` (built-in `http.server` — для production использовать ASGI-обёртку). Cross-course Spark M14 — Prometheus + Grafana monitoring stack для Spark cluster. Cross-link: M11 урок 04 (3 pillars observability — metrics pillar).

Пример:
from prometheus_client import Counter, start_http_server

requests = Counter("http_requests_total", "Total HTTP requests", ["method"])
start_http_server(8000)   # /metrics endpoint

requests.labels(method="GET").inc()
Подробнее в уроках:

pyproject.toml (PEP 621)

pyproject.toml — declarative project metadata (PEP 621)
Термин

pyproject.toml — declarative Python project metadata file standardized в PEP 621 (2020). Replaces legacy `setup.py` (executable, security risk install-time) + `setup.cfg` (declarative но setuptools-specific) — единственный manifest format для modern Python projects. **Two main tables:** (1) **`[build-system]`** (PEP 518, 2016) — `requires: list[str]` (build dependencies — installed в isolated venv frontend'ом) + `build-backend: str` (dotted path к backend module — hatchling.build / setuptools.build_meta / poetry.core.masonry.api / flit_core.buildapi / pdm.backend / maturin); (2) **`[project]`** (PEP 621) — unified metadata: `name` / `version` / `description` / `readme` / `requires-python` / `dependencies` / `optional-dependencies` / `dynamic` / `authors` / `maintainers` / `license` / `keywords` / `classifiers` / `urls` / `scripts` / `gui-scripts` / `entry-points`. **PEP 735** (2024) added **`[dependency-groups]`** — modern dev-deps grouping (replaces `[project.optional-dependencies]` для dev tools; не публикуется в wheel metadata; supports composition `include-group`; cross-tool support pip ≥24.1, uv, Poetry 2.0+). **Parsed via `tomllib`** (Python 3.11+ stdlib, PEP 680, **read-only** — для записи использовать third-party `tomli-w`; Pitfall 45). **Pitfall 44 — Poetry pre-2.0 `[tool.poetry]` proprietary table; Poetry 2.0+ supports `[project]` standard.** **Cross-link M07 урок 04** — pyproject.toml parsed via tomllib returns dict — accessed like dataclass field access. Cite [peps.python.org/pep-0517](https://peps.python.org/pep-0517/) + [pep-0518](https://peps.python.org/pep-0518/) + [pep-0621](https://peps.python.org/pep-0621/) + [pep-0680](https://peps.python.org/pep-0680/) + [pep-0735](https://peps.python.org/pep-0735/) + [packaging.python.org/en/latest/guides/writing-pyproject-toml/](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/).

Подробнее в уроках:

pytest fixture scope

pytest fixture scope
Термин

Параметр `scope` в `@pytest.fixture(scope=...)` определяет lifecycle fixture'а: `function` (default; пересоздаётся для каждого test), `class` (один раз на test class), `module` (один раз на test файл), `package` (один раз на pytest package), `session` (один раз на pytest session — все tests). Fixture с большим scope живёт дольше — экономия на setup cost (DB connection, large file load). Trade-off: shared state между тестами риск flakiness — больший scope требует careful test isolation (no mutating shared fixture). Cross-link: M08 урок 02 (climax cross-link M06 урок 05 context manager protocol).

Пример:
import pytest

@pytest.fixture(scope="session")
def db_conn():
    conn = create_connection()
    yield conn
    conn.close()

@pytest.fixture(scope="function")
def temp_table(db_conn):
    # один conn на session, но fresh table per-test
    ...
Подробнее в уроках:

sdist vs wheel (PEP 427 / 517)

sdist vs wheel distribution formats
Термин

Two PyPI distribution formats. **sdist** (`.tar.gz`) — **source distribution**; archive исходников + pyproject.toml + README; install **fall back к manual build** (pip создаёт isolated venv, ставит `[build-system].requires`, вызывает `build_wheel(...)`); slower (compile time для C extensions); требует build toolchain (gcc, headers); larger archive. Filename convention `{pkg}-{version}.tar.gz`. **wheel** (`.whl`, [PEP 427](https://peps.python.org/pep-0427/), 2012) — **pre-built binary**; zip archive containing `{pkg}/` (directly copyable в site-packages) + `{pkg}-{version}.dist-info/` (METADATA + RECORD + WHEEL); install — pure copy без compile/subprocess; **на порядок быстрее** sdist install (особенно для C extensions); per-platform / per-Python-version artifacts. **Wheel filename anatomy:** `{pkg}-{version}-{python_tag}-{abi_tag}-{platform_tag}.whl` — example `pandas-2.1.4-cp312-cp312-manylinux_2_17_x86_64.whl`: `pandas` (name), `2.1.4` (version), `cp312` (Python tag — CPython 3.12), `cp312` (ABI tag — usually = Python tag для CPython; some C-extensions ABI-stable → `abi3`), `manylinux_2_17_x86_64` (platform tag — compatible glibc 2.17+). **Universal wheels** `pkg-1.0-py3-none-any.whl`: `py3` (any Python 3) + `none` (no specific ABI) + `any` (any platform). **manylinux ABI compatibility** ([PEP 600](https://peps.python.org/pep-0600/), 2020) — manylinux_2_17/2_28/2_34 баseline glibc versions; Alpine Linux uses musl libc → `musllinux_1_1_x86_64` tag (PEP 656, 2021). **Pitfall 48 — wheel filename mismatch** (cp310 wheel manually installed on Python 3.12 → ImportError shared object; modern pip handles automatically). **Recommend:** ship обе sdist + wheel(s); pure-Python — sdist + один universal wheel; C-extensions — sdist + per-platform wheels matrix через [cibuildwheel](https://cibuildwheel.pypa.io/). **Build via `python -m build`** (replaces legacy `python setup.py sdist bdist_wheel`); **upload via `twine upload dist/*`** к PyPI / TestPyPI. Cite [packaging.python.org/en/latest/specifications/binary-distribution-format/](https://packaging.python.org/en/latest/specifications/binary-distribution-format/) + [PEP 427](https://peps.python.org/pep-0427/) + [PEP 600](https://peps.python.org/pep-0600/).

Подробнее в уроках:

structlog

structlog (3rd-party)
Термин

Сторонняя библиотека structured logging, альтернатива stdlib `logging` + `python-json-logger`. Преимущества: declarative pipeline processors (`add_logger_name`, `add_log_level`, `TimeStamper`, `JSONRenderer`); thread-local + async-context bind (`structlog.contextvars.bind_contextvars(request_id=...)` — корелляция логов в async-handlers без передачи extra параметров); native ContextVar-aware propagation (Python 3.7+). Production-ready alternative для FastAPI / Starlette / async services; сохраняет совместимость с stdlib `logging` через `structlog.stdlib.LoggerFactory`. Cross-link: M11 урок 02 (Run-on-Your-Machine — pip install structlog).

Пример:
import structlog
log = structlog.get_logger()
log.info("user_login", user_id=42, tenant="acme")
# JSON output: {"event": "user_login", "user_id": 42, "tenant": "acme", ...}
Подробнее в уроках:

tracemalloc snapshot

tracemalloc snapshot (PEP 454)
Термин

tracemalloc.take_snapshot() — capture current allocation state with traceback per allocation site (set by `tracemalloc.start(N)` где N — frames per traceback, default 1). Stdlib `tracemalloc` ([PEP 454](https://peps.python.org/pep-0454/), Python 3.4+) — memory profiling primitive — instruments allocator hook + records pointer + size + traceback для каждой allocation. **Snapshot API:** `snapshot.statistics(key_type)` — group by key (`'lineno'` — source line, `'filename'` — source file, `'traceback'` — full traceback) — returns `Statistic` objects sorted by total size. `snapshot.compare_to(other_snapshot, key_type='lineno')` — **diff** двух snapshots, returns `Statistic` objects с `size_diff` + `count_diff` + `traceback`. Это и есть **leak detection** workflow: (1) `tracemalloc.start(N)` (включить tracking — overhead per allocation: ~30% slowdown N=1, до 50%+ N=25); (2) `snap_baseline = tracemalloc.take_snapshot()`; (3) run suspicious workload (idempotent — должен НЕ накапливать state); (4) `snap_after = tracemalloc.take_snapshot()`; (5) `diff = snap_after.compare_to(snap_baseline, 'lineno')` — top growers per line; (6) `tracemalloc.stop()` — выключить tracking (Pitfall 39 — production process тормозит до restart если забыли stop). Production wraps в `try/finally` или DIY context-manager (cross-link M06 урок 04 protocol — `__enter__`/`__exit__` гарантирует cleanup даже при exception). **Comparison vs sys.getsizeof:** `sys.getsizeof(obj)` — per-object (single call, без traceback); `tracemalloc` — per-allocation site (granular, leak detection origin). **Comparison vs gc.get_objects():** `gc.get_objects()` — list of all currently-alive objects (type-based introspection — «сколько Foo instances right now?»); together they give full picture: «leak'ит **что** + **откуда**». **Pyodide constraint:** bounded examples OK (small dict/list snapshots — ~10ms overhead в browser); **production-scale snapshots** (1GB+ heap) — too slow для browser; T-69-23 disposition — accept; bounded examples только в lesson MDX prose, real production-scale → Run-on-Your-Machine. **Comparison vs memray:** `memray` (Bloomberg, 2022) — native C-level instrumentation, lower overhead, structured output (flame graphs HTML, allocator breakdown), **tracks C-extension allocations что tracemalloc НЕ делает** (only Python allocations). Production-scale memory analysis → memray; dev quick diagnostics → tracemalloc (stdlib, no-install). **Cross-course → Spark** [01/07 memory-management](/spark-internals/05-memory-storage-internals/01-memory-management/) — distributed equivalent: Spark UI Storage tab показывает RDD/DataFrame caching memory growth across stages — analogous к tracemalloc.compare_to. **Cross-course → DataFusion** [02/07 memory-management](/datafusion-course/02-architecture/07-memory-management/) — Rust's memory tracking primitives (MemoryConsumer trait, MemoryReservation) — explicit tracking analogous; Rust no-GC requires explicit reservation patterns. Cite [docs.python.org/3/library/tracemalloc.html](https://docs.python.org/3/library/tracemalloc.html) + [PEP 454](https://peps.python.org/pep-0454/).

Подробнее в уроках:

uv (Astral)

uv (Astral package manager)
Термин

Rust-based замена pip / pip-tools / virtualenv / pyenv от Astral Inc. (создатели Ruff). Установка пакетов в 10-100x быстрее pip за счёт parallel download + global cache + Rust-native dependency resolver (PubGrub algorithm). Совместим с PEP 517 / 518 / 621 (читает `pyproject.toml`); производит `uv.lock` файл (cross-platform reproducible builds; формат — human-readable TOML). Стабильный с октября 2024 (uv 0.4+); рекомендован Astral для новых проектов вместо rye / poetry / pdm. Cross-course Spark M14 — CI/CD pipeline pattern с lock-файлом.

Пример:
uv venv .venv
source .venv/bin/activate
uv pip install 'fastapi>=0.110'
uv lock                          # generate uv.lock
uv sync                          # reproduce env from uv.lock
Подробнее в уроках: