JuniorPython Developer > Основы Python > Типы данных
Короткий ответ list — изменяемая последовательность для данных, которые меняются по ходу работы программы; tuple — неизменяемая последовательность, подходящая для фиксированных наборов значений и в качестве ключей словаря. Как это работает подробнее list реализован как динамический массив ссылок, поддерживающий append, insert, удаление элементов — объект можно изменять после создания. tuple хранит тот же набор ссылок, но без методов изменения состава; после создания кортеж нельзя дополнить или сократить. Пример кода Что использовать на практике Практика. tuple удобен для возврата нескольких значений из функции (координаты, пара ключ-значение), для неизменяемых записей и как элемент set/ключ dict, поскольку он хешируем (если хешируемы все его элементы). list используют для коллекций, которые растут, сортируются или фильтруются в процессе работы. Подводные камни Риски. Путают неизменяемость кортежа с неизменяемостью его содержимого: tuple с вложенным list внутри всё равно позволяет изменить этот list, хотя сам
data-typeslist
JuniorPython Developer > Основы Python > Коллекции и структуры данных
Короткий ответ List comprehension [x for x in it] сразу вычисляет и хранит в памяти весь список, а generator expression (x for x in it) создаёт ленивый итератор, который вычисляет элементы по одному при обращении — выбор зависит от того, нужен ли полный список сразу или достаточно пройти по данным один раз. Как это работает подробнее List comprehension выполняет цикл немедленно и собирает результаты в новый объект list в памяти. Generator expression возвращает объект-генератор без вычислений "внутри"; каждое значение вычисляется лениво при вызове next() (явном или через for/sum/list и т.п.), и после одного полного прохода генератор исчерпывается. Пример кода Что использовать на практике Практика. Для больших или потенциально бесконечных источников данных (построчное чтение файла, поток записей из БД) генератор экономит память, так как не держит все элементы одновременно. Если результат нужно индексировать, проходить несколько раз, получить len() или передать как JSON — нужен конкретный список, то есть list co
collectionscomprehensions
MiddleData Analyst > SQL и данные > SQL
Короткий ответ QUALIFY позволяет фильтровать строки прямо по значению оконной функции в том же SELECT, где она вычислена, тогда как в PostgreSQL (где QUALIFY не поддерживается) для этого нужно обернуть оконную функцию в подзапрос или CTE и фильтровать уже внешним WHERE, потому что WHERE не может напрямую ссылаться на оконные функции, вычисленные в том же уровне запроса. Как это работает подробнее логический порядок выполнения запроса — оконные функции вычисляются после WHERE, но до финальной проекции SELECT; QUALIFY — это дополнительный этап фильтрации именно после вычисления оконных функций, аналогичный тому, как HAVING работает после GROUP BY. В PostgreSQL такого отдельного этапа нет, поэтому оконную функцию нужно материализовать в подзапросе/CTE, чтобы потом сослаться на неё в обычном WHERE. Пример кода Что использовать на практике Практика. QUALIFY делает запрос короче и нагляднее там, где он поддерживается; в PostgreSQL эквивалентная логика требует дополнительного уровня вложенности, что не хуже по произ
bigqueryclickhouse
MiddleDevOps Engineer > Контейнеры и доставка > Kubernetes и оркестрация
Короткий ответ Role и RoleBinding ограничены одним namespace и дают права только на ресурсы внутри него; ClusterRole определяет права, применимые на уровне всего кластера (включая кластерные ресурсы вроде Node), но может быть связан как ClusterRoleBinding (права во всём кластере), так и RoleBinding (права только в конкретном namespace, хотя сам набор прав переиспользуемый). Как это работает подробнее RBAC в Kubernetes состоит из двух частей — определение прав (Role/ClusterRole, набор правил "что можно делать с какими ресурсами") и привязка этих прав к субъекту (RoleBinding/ClusterRoleBinding, "кому выданы эти права и где"). ClusterRole часто используют для переиспользуемых наборов прав (например, "read-only доступ к Pod и Service"), которые затем привязываются к разным namespace через отдельные RoleBinding, чтобы не дублировать одинаковые правила. Пример кода Что использовать на практике Практика. для прав, которые должны действовать везде одинаково и затрагивают кластерные ресурсы (Node, PersistentVolume, са
authorizationkubernetes
MiddlePython Developer > Основы Python > SQLAlchemy
Короткий ответ flush() отправляет накопленные изменения в БД в рамках текущей транзакции, делая их видимыми для последующих запросов этой же транзакции (например, чтобы получить сгенерированный id), но не фиксирует их навсегда; commit() выполняет flush неявно и затем фиксирует транзакцию, делая изменения постоянными и видимыми другим транзакциям. Как это работает подробнее SQLAlchemy Session накапливает изменения объектов в памяти (unit of work) и не отправляет их в БД немедленно при каждом session.add(); flush синхронизирует состояние объектов с БД, но до commit всё это можно откатить через rollback(). Пример кода Что использовать на практике Практика. Явный flush() нужен, когда в рамках одной транзакции нужно получить автоматически сгенерированный PK нового объекта до завершения всей бизнес-операции; в большинстве сценариев достаточно одного commit() в конце. Подводные камни Ошибка. Вызывают commit() слишком часто внутри одной логической операции, фиксируя промежуточные состояния, которые должны быть атомар
ormpostgresql
JuniorJava Developer > Java Core > Строки
Короткий ответ Все три класса работают со строками, но различаются неизменяемостью и потокобезопасностью. String неизменяем: любой «изменяющий» метод создаёт новую строку. StringBuilder и StringBuffer изменяемы: они модифицируют внутренний буфер через append, insert, replace, не создавая новые объекты. Методы StringBuffer объявлены synchronized, поэтому он потокобезопасен, но медленнее StringBuilder. Как это работает подробнее StringBuffer существует с Java 1.0, его методы синхронизированы; StringBuilder появился в Java 5 как несинхронизированный аналог. Вне циклов компилятор сам превращает конкатенацию через + в вызовы StringBuilder, но внутри цикла это не спасает от множества промежуточных объектов. String — неизменяемый, подходит для строк, которые не меняются; переиспользуется в пуле. StringBuilder — изменяемый, без синхронизации, самый быстрый в однопоточном коде; появился в Java 5. StringBuffer — изменяемый, методы synchronized, потокобезопасный, но медленнее; существует с Java 1.0. Компилятор — простая
immutabilityjava
MiddlePython Developer > Основы Python > Многопоточность и асинхронность
Короткий ответ Threading выполняет потоки в одном процессе: они разделяют память и легко обмениваются данными, но для CPU-bound задач ограничены GIL. Multiprocessing запускает отдельные процессы со своей памятью и интерпретатором — они не ограничены GIL и действительно параллельно исполняются на разных ядрах. Как это работает подробнее Выбор между модулями — классический компромисс между лёгкостью и общим доступом к памяти (потоки) и изоляцией с настоящим параллелизмом (процессы). Потоки. Живут внутри одного процесса, создаются быстро, легко обмениваются данными через общую память, но требуют синхронизации блокировками и очередями. Процессы. Каждый имеет собственную память и свой интерпретатор, не ограничен GIL и может исполняться на отдельном ядре, однако создаётся тяжелее. Изоляция. Падение одного процесса не рушит остальные, но обмен данными между ними сложнее: очереди, pipe или общая память. Критерий выбора. Потоки предпочтительны для ввода-вывода, процессы — для вычислительных задач, которым нужны все яд
gilmultiprocessing
MiddlePython Developer > Основы Python > FastAPI и Pydantic
Короткий ответ requests.get — синхронный блокирующий вызов; выполняясь внутри async def, он останавливает весь event loop на время сетевого запроса, замораживая обработку всех остальных конкурентных запросов приложения в этом процессе; решение — использовать асинхронный HTTP-клиент (httpx.AsyncClient) с await, либо вынести вызов в threadpool. Как это работает подробнее Event loop asyncio однопоточно переключается между корутинами в точках await. Вызов обычной блокирующей функции без await — это обычный синхронный Python-код, который выполняется от начала до конца, не отдавая управление обратно event loop, то есть другие корутины не могут продолжить выполнение в это время. Пример кода Что использовать на практике Практика. Правильное исправление — заменить requests на httpx.AsyncClient (или aiohttp) и использовать await client.get(...). Если библиотека принципиально синхронная и без асинхронной альтернативы, можно вызвать её через await run_in_threadpool(requests.get, url) (Starlette) или loop.run_in_executor,
asynciofastapi
JuniorDevOps Engineer > Контейнеры и доставка > CI/CD и управление релизами
Короткий ответ По умолчанию джобы выполняются по порядку стадий (`build` → `test` → `deploy`), ожидая завершения всей предыдущей стадии; `needs` позволяет явно указать зависимость от конкретной джобы (а не от всей стадии), благодаря чему джоба может начаться раньше, не дожидаясь остальных джоб своей логической стадии. Как это работает подробнее без `needs` GitLab CI выполняет джобы стадии `test` только после того, как завершатся все джобы стадии `build`, и так далее по порядку `stages`. Указав `needs: [unit_tests]` у джобы деплоя, можно разрешить ей стартовать сразу после конкретной джобы, даже если другие джобы той же стадии (например, `lint`) ещё выполняются — это называется DAG (direct acyclic graph) pipeline. Пример кода Что использовать на практике На практике. `needs` ускоряет длинные пайплайны за счёт параллелизации независимых веток работы, но требует аккуратности — если забыть указать зависимость от нужного артефакта, джоба может запуститься раньше, чем он будет готов. Пример. Ожидаемое поведение: `d
cicd-and-release-managementdevops
MiddlePerformance Marketer > Google Ads > Специфика рекламных площадок и каналов
Короткий ответ Нужно последовательно проверить изменения в аукционной конкуренции (Auction Insights), динамику показателей качества и позиции, техническое состояние трекинга конверсий и посадочной страницы, а также возможные сезонные факторы — рост CPA редко имеет одну причину без сопоставления этих срезов. Как это работает подробнее CPA = расход / число конверсий, поэтому рост CPA может быть вызван либо ростом CPC при неизменной конверсии, либо падением коэффициента конверсии при неизменном CPC, либо обоими факторами одновременно; разделение этих двух составляющих — первый шаг диагностики, так как причины и решения для них разные. Что использовать на практике На практике. если выросла CPC — смотрят Auction Insights на появление новых конкурентов и динамику Quality Score; если упала конверсия при стабильном CPC — проверяют техническую исправность тега конверсии (например, через отчёт «Диагностика»), изменения на посадочной странице и соответствие трафика по устройствам историческим паттернам; также стоит искл
auction-insightsconversion-rate