Почему это важно
При распаковке head, sep, tail проверяйте sep. Пустой sep означает, что разделитель не найден; исходная строка при этом может оказаться в head или tail, в зависимости от выбранного метода.
Please open Telegram to view this post
VIEW IN TELEGRAM
1. В DEFAULT записано timeout="30". Секция api существует, но своих параметров у неё нет.
2. При чтении из api доступны значения DEFAULT. Поэтому первый getint берёт timeout из DEFAULT и преобразует строку "30" в целое число 30.
3. fallback используется, если параметр не найден. Явно переданное fallback=5 не переопределяет значение из DEFAULT.
4. Параметра retries нет ни в api, ни в DEFAULT. Второй getint возвращает 5. Код печатает две строки:
30
5
Если нужно изменить унаследованный timeout для api, задайте его в самой секции. fallback задаёт значение на случай отсутствия параметра. В этом примере используется стандартный ConfigParser без пользовательских преобразователей.
1. Декоратор singledispatch превращает route в функцию с несколькими реализациями. Исходная реализация зарегистрирована для object и возвращает "base". Она используется, если для типа первого аргумента не найден более подходящий обработчик.
2.
3. В route("7", 7) первый аргумент — строка. Обработчик для str не зарегистрирован, поэтому вызывается исходная реализация и возвращает "base".
4. В route(7, "7") первый аргумент имеет тип int. Здесь выбирается зарегистрированная реализация, которая возвращает "int". Поэтому print выводит base int.
У обычной функции с singledispatch выбор зависит только от типа первого аргумента. Второй аргумент передаётся выбранному обработчику, но в выборе не участвует. Имя hint здесь — обычное имя параметра.
1. DictReader берёт имена полей из первой строки: id, status, status. Следующая строка содержит три строковых значения: "7", "new", "done".
2. В CPython словарь для строки создаётся через dict(zip(fieldnames, row)). Ключ status встречается дважды. Второе присваивание сохраняет "done" поверх "new".
3. Поэтому вывод — done 2. В словаре два разных ключа, id и status. Ответ new 2 получился бы при сохранении первого значения, а done 3 — при подсчёте столбцов вместо ключей. ValueError при таком повторе не возникает.
При импорте чужого CSV проверяйте уникальность заголовков до преобразования в словарь. Если повторяющиеся столбцы нужны, читайте строки через csv.reader и сохраняйте их позиции. Отдельная ловушка: при короткой строке недостающее значение последнего status может заменить предыдущее на None.
✍1
1. Пустой список в parse_args([]) означает, что ни --limit, ни --rate не переданы. Аргументы запуска самого скрипта здесь не читаются.
2. Значение default="08" — строка. argparse пропускает её через type=int и получает число 8. Первый print выводит 8 int, без начального нуля.
3. Значение default=8.5 уже имеет тип float. Для нестрокового default преобразователь не вызывается. Вторая строка — 8.5 float.
Правильный вариант: 8 int | 8.5 float. Вариант со str пропускает преобразование строки. Два int получились бы при преобразовании обоих defaults, которого здесь нет. ValueError тоже не возникает: строка "08" допустима для int, а float вообще не передают конвертеру.
Если ожидается int, задавайте числовой default нужного типа. type=int проверяет переданные CLI-значения и строковые defaults, но не гарантирует тип любого программно заданного значения по умолчанию.
1. В словаре TopologicalSorter значения — предшественники узла. Для build нужен test, а для test нужен build. Ни один из них не готов к запуску.
2. У lint нет предшественников. prepare() обнаруживает цикл и выбрасывает CycleError, который код перехватывает.
3. После такой ошибки разрешено вызвать get_ready(). Независимый lint остаётся доступным, поэтому вывод — ('lint',). Единственная готовая вершина делает порядок однозначным.
Пустой кортеж означал бы, что готовых узлов нет, хотя lint готов к запуску. Кортеж из всех трёх узлов нарушил бы зависимости. Повторного CycleError в get_ready() здесь нет: проверка цикла уже произошла в prepare().
Это позволяет выполнить независимую часть сборки или конвейера, пока циклическая часть заблокирована. Перехват ошибки не исправляет граф. Когда lint будет отмечен через done(), build и test всё равно не станут готовы.
1. bind("eu") сопоставляет строку "eu" параметру region. Функция fetch при этом не выполняется. Объект BoundArguments описывает вызов.
2. В arguments сначала попадают только явно связанные аргументы. Поэтому первый print выводит {'region': 'eu'}. Значение timeout=5 пока пропущено.
3. apply_defaults() добавляет недостающие значения по умолчанию. Для timeout это 5, для **options — пустой словарь. Второй print выводит {'region': 'eu', 'timeout': 5, 'options': {}}.
Верный ответ — первый вариант. Во втором потерян пустой словарь options. Третий игнорирует apply_defaults(). TypeError не возникает: обязательный region передан, timeout имеет значение по умолчанию, а **options может быть пустым.
Различие полезно в декораторах и логировании. До apply_defaults() видно, что передал вызывающий код. После него можно обрабатывать все аргументы вызова, включая значения по умолчанию. Явно переданные значения при этом сохраняются.
1. Здесь явно импортирован posixpath, поэтому обе строки разбираются по правилам POSIX независимо от ОС запуска.
2. commonprefix() сравнивает строки посимвольно. Вторая строка начинается с первой целиком, поэтому результат — /srv/config.
3. commonpath() сравнивает компоненты. После общего /srv идут разные имена: config и config-old. Общий путь — /srv.
Правильный вариант: /srv/config | /srv. Два /srv означали бы сравнение компонентов в обоих вызовах. Два /srv/config — посимвольное сравнение в обоих. ValueError здесь нет: список непустой, оба пути абсолютные.
Строковый префикс не доказывает, что файл находится внутри каталога: имя config-old тоже начинается с config. commonpath учитывает границы компонентов и различает эти имена. Это лексическая операция, она не разрешает символические ссылки и сама по себе не решает гонки при доступе к файловой системе.
1. asyncio.timeout(0) назначает отмену на ближайшую итерацию цикла событий. Event создан без установленного флага, и никто не вызовет set(). Поэтому wait() приостанавливает текущую задачу.
2. Тайм-аут отменяет эту задачу. В точке await возникает asyncio.CancelledError. Внутренний except TimeoutError его не перехватывает, строка inside не печатается.
3. При выходе из async with менеджер timeout преобразует свою отмену в TimeoutError. Внешний обработчик печатает outside. Затем выполнение продолжается и печатает done.
Правильный вариант: outside | done. Вариант inside | done предполагает, что TimeoutError попадёт во внутренний обработчик ещё до преобразования отмены в это исключение. Обе метки одновременно тоже не печатаются. Только done потребовало бы завершения ожидания без тайм-аута, а событие никто не устанавливает.
Обработчик TimeoutError размещайте снаружи нужного timeout-контекста. Не поглощайте CancelledError внутри операции: механизм тайм-аута использует отмену. В этом примере нет задержки sleep и зависимости от скорости компьютера.
1. Job("Night Build") вызывает сгенерированный __init__, затем __post_init__. В первый раз slug становится "night-build". Следующая строка вручную заменяет его на "manual".
2. replace(old, name="Quick Fix") создаёт новый Job через __init__. Поле slug помечено init=False и из old не копируется.
3. У нового объекта снова вызывается __post_init__. Именно наш метод вычисляет slug из нового name и получает "quick-fix". Исходный объект не меняется. Вывод — manual quick-fix.
Вариант manual manual предполагал бы копирование slug. Вариант night-build quick-fix не учитывает ручное изменение old.slug. ValueError возник бы при попытке передать slug в changes, например dc.replace(old, slug="forced"), но здесь меняется допустимое поле name.
Для вычисляемых полей учитывайте повторный вызов __post_init__ при replace. Само init=False не задаёт формулу пересчёта. В этой задаче она явно написана в методе, а ручная правка вычисляемого поля не переносится в новый объект.
1. У экземпляра ReadyJob есть метод __await__. При его вызове создаётся корутина finish и возвращается её итератор. Так объект поддерживает протокол awaitable: его можно ожидать через await.
2. В Python 3.14
3. finish возвращает строку index-ready. Она становится результатом ожидания, затем результатом
Почему это важно
Если библиотека возвращает собственный awaitable, в Python 3.14 его можно передать напрямую в точку входа. Не нужно добавлять корутину-обёртку только ради типа аргумента. Но
Код проверен в CPython 3.14.4.