Что выведет код?
Anonymous Quiz
42%
[[0, 1, 0], [0, 0, 0], [0, 0, 0]]
33%
[[0, 1, 0], [0, 1, 0], [0, 1, 0]]
12%
[[0, 0, 0], [1, 0, 0], [0, 0, 0]]
14%
Error
This media is not supported in your browser
VIEW IN TELEGRAM
❌Python: Никогда не делай так!!!
НИКОГДА НЕ ИСПОЛЬЗУЙ МУТАБЕЛЬНЫЕ ДЕФОЛТЫ: не используй изменяемые объекты (например, списки или словари) как значения по умолчанию в аргументах функции.
Каждый вызов функции будет делить один и тот же объект, и ты получишь «призрачные» данные, которые появляются из ниоткуда. Это одна из самых коварных ловушек Python.
Всегда используй None и создавай новый объект внутри функции. Подписывайся, больше фишек каждый день !
НИКОГДА НЕ ИСПОЛЬЗУЙ МУТАБЕЛЬНЫЕ ДЕФОЛТЫ: не используй изменяемые объекты (например, списки или словари) как значения по умолчанию в аргументах функции.
Каждый вызов функции будет делить один и тот же объект, и ты получишь «призрачные» данные, которые появляются из ниоткуда. Это одна из самых коварных ловушек Python.
Всегда используй None и создавай новый объект внутри функции. Подписывайся, больше фишек каждый день !
Плохо — список живёт между вызовами
def add_item(item, bucket=[]):
bucket.append(item)
return bucket
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] — неожиданно!
# Правильно
def add_item(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
print(add_item(1)) # [1]
print(add_item(2)) # [2]
Вопрос с собеседования
Что выведет этот код и почему?
Попробуй сначала сам ответить, а потом смотри разбор.
Что происходит по шагам:
Переменная a ссылается на список [1, 2, 3].
b = a
Теперь b ссылается на тот же самый список, что и a.
Не копия, а один и тот же объект в памяти.
a += [4, 5]
Важно: для списков += работает как изменение объекта на месте:
это примерно то же самое, что:
a.extend([4, 5])
То есть в существующий список, на который ссылаются и a, и b, добавляются элементы 4 и 5.
Поэтому:
Оба указывают на один изменённый список.
Часть 2. Кортежи
a = (1, 2, 3)
b = a
a += (4, 5)
print(a)
print(b)
Кортежи неизменяемы, и здесь начинается магия.
a = (1, 2, 3)
a ссылается на кортеж (1, 2, 3).
b = a
b ссылается на тот же кортеж (1, 2, 3).
a += (4, 5)
Для кортежей += уже не может менять объект на месте (они immutable).
Поэтому Python делает так:
a = a + (4, 5)
То есть создаётся новый кортеж (1, 2, 3, 4, 5) и переменная a переназначается на него.
b при этом остаётся смотреть на старый кортеж (1, 2, 3).
Поэтому:
print(a) # (1, 2, 3, 4, 5)
print(b) # (1, 2, 3)
В чём хитрость
Для списка a += [4, 5] мутирует объект на месте, и это видно через все переменные, которые на него ссылаются.
Для кортежа a += (4, 5) создаёт новый объект и переназначает только a.
Итого:
Если хочешь, могу ещё один хитрый вопрос разобрать - про изменяемые значения по умолчанию в аргументах функции или про циклы и замыкания.
Что выведет этот код и почему?
a = [1, 2, 3]
b = a
a += [4, 5]
print(a)
print(b)
a = (1, 2, 3)
b = a
a += (4, 5)
print(a)
print(b)
Попробуй сначала сам ответить, а потом смотри разбор.
Часть 1. Списки
a = [1, 2, 3]
b = a
a += [4, 5]
print(a)
print(b)
Что происходит по шагам:
a = [1, 2, 3]
Переменная a ссылается на список [1, 2, 3].
b = a
Теперь b ссылается на тот же самый список, что и a.
Не копия, а один и тот же объект в памяти.
a += [4, 5]
Важно: для списков += работает как изменение объекта на месте:
это примерно то же самое, что:
a.extend([4, 5])
То есть в существующий список, на который ссылаются и a, и b, добавляются элементы 4 и 5.
Поэтому:
print(a) # [1, 2, 3, 4, 5]
print(b) # [1, 2, 3, 4, 5]
Оба указывают на один изменённый список.
Часть 2. Кортежи
a = (1, 2, 3)
b = a
a += (4, 5)
print(a)
print(b)
Кортежи неизменяемы, и здесь начинается магия.
a = (1, 2, 3)
a ссылается на кортеж (1, 2, 3).
b = a
b ссылается на тот же кортеж (1, 2, 3).
a += (4, 5)
Для кортежей += уже не может менять объект на месте (они immutable).
Поэтому Python делает так:
a = a + (4, 5)
То есть создаётся новый кортеж (1, 2, 3, 4, 5) и переменная a переназначается на него.
b при этом остаётся смотреть на старый кортеж (1, 2, 3).
Поэтому:
print(a) # (1, 2, 3, 4, 5)
print(b) # (1, 2, 3)
В чём хитрость
Для списка a += [4, 5] мутирует объект на месте, и это видно через все переменные, которые на него ссылаются.
Для кортежа a += (4, 5) создаёт новый объект и переназначает только a.
Итого:
# Часть со списком:
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
# Часть с кортежем:
(1, 2, 3, 4, 5)
(1, 2, 3)
Если хочешь, могу ещё один хитрый вопрос разобрать - про изменяемые значения по умолчанию в аргументах функции или про циклы и замыкания.
Media is too big
VIEW IN TELEGRAM
Главная цель - чтобы через полгода было не стыдно открывать код: понятно где что лежит, как это тестировать и куда встраивать новые фичи.
Основные принципы:
- Разделяй по ответственности, а не по типу файла
- Минимизируй связь между слоями
- Явно отделяй ядро домена от инфраструктуры (БД, HTTP, очереди)
Пример базовой структуры:
- app/
- api/ - HTTP handlers, REST, gRPC, CLI
- services/ - бизнес-логика, сценарии use case
- domain/ - сущности, модели, value objects
- repositories/ - работа с БД, кэшами, внешними сервисами
- config/ - настройки, env, схемы конфигурации
- utils/ - вспомогательные функции, которые не завязаны на домен
- tests/ - тесты по тем же модулям, что и в app/
- scripts/ - миграции, разовые утилиты, maintenance
Рекомендации:
- Один входной файл (main.py или cli.py), вся логика - в app/*
- Конфигурацию не хардкодить, а прокидывать через env и config-объекты
- Внутри services работать с абстрактными интерфейсами репозиториев, а не с конкретным ORM
- С самого начала заводить тесты, пусть даже простые, и поддерживать схему tests/ в том же дереве, что и код
- Любой новый модуль должен отвечать на вопрос: к какому слою относится и от кого ему можно зависеть
Если проект растет, не бойся дробить:
- крупный модуль на подмодули
- общие зависимости в отдельный layer (shared, common)
- разные bounded context в отдельные пакеты внутри app/
Архитектура большого проекта - это не про идеальный паттерн, а про понятные границы и минимальный хаос.
https://uproger.com/kak-organizovat-arhitekturu-bolshogo-python-proekta/
Видео: https://www.youtube.com/watch?v=Dk7A8ElHcKE
Please open Telegram to view this post
VIEW IN TELEGRAM
Что выведет код? Перевод на новую строку и пробелы не учитываем, вопрос про списки.
Anonymous Quiz
42%
[1] [1, 1]
47%
[1] [1]
6%
[ ] [ ]
5%
[ ] [1]
🐍 Хитрая ловушка в Python, на которую попадаются даже опытные
Интуитивно кажется, что это создаёт независимые строки матрицы.
Но на самом деле Python копирует ссылки - все три строки указывают на один и тот же список.
🔍 Поэтому изменение matrix[0][0] или append() влияет сразу на все строки.
🧠 Вывод программы:
[[1, 0, 0, 9],
[1, 0, 0, 9],
[1, 0, 0, 9]]
3
4
✔️ Как правильно создавать матрицу с независимыми строками:
matrix = [[0] * 3 for _ in range(3)]
Теперь каждая строка - отдельный список, и изменения не “протекают” по всей матрице.
matrix = [[0] * 3] * 3
matrix[0][0] = 1
matrix[1].append(9)
print(matrix)
print(len(matrix))
print(len(matrix[0]))
Интуитивно кажется, что это создаёт независимые строки матрицы.
Но на самом деле Python копирует ссылки - все три строки указывают на один и тот же список.
🧠 Вывод программы:
[[1, 0, 0, 9],
[1, 0, 0, 9],
[1, 0, 0, 9]]
3
4
✔️ Как правильно создавать матрицу с независимыми строками:
matrix = [[0] * 3 for _ in range(3)]
Теперь каждая строка - отдельный список, и изменения не “протекают” по всей матрице.
Каким будет вывод этого кода?
Anonymous Quiz
13%
1
9%
1 2
6%
1 2 3 4 5 6 ...
67%
1 3 5 7 9 11 ...
5%
Посмотреть ответ
Владение Docker - навык, который отличает новичка от профи
Сегодня почти всё разворачивается в контейнерах.
Если ты не умеешь работать с Docker, ты медленнее, зависим от чужих настроек и постоянно ловишь баги «у меня локально работает».
Этот курс покажет:
• разобраны все возможные ошибки при работе c Docker
• как упаковывать проекты в контейнеры
• как поднимать целые системы за минуты
• как избегать типичных ошибок в продакшене
• как делать стабильные и повторяемые окружения
Только практика и реальные кейсы - с нуля до уверенного уровня.
🎁 40 процентов скидка действует 48 часов в честь нового года
👉 Записывайся и сделай Docker своим настоящим рабочим инструментом.
Please open Telegram to view this post
VIEW IN TELEGRAM
Каким будет вывод этого кода в консоли?
Anonymous Quiz
8%
{1, 2}
39%
True
19%
False
24%
Это невозможная операция
10%
Посмотреть ответ
🧠 Python-задача с собеседования: найди ошибку
Код должен посчитать количество чисел больше среднего значения в списке.
Проблема в этой строке:
```python
def count_above_avg(nums, avg=sum(nums)/len(nums)):
```
Здесь используется значение по умолчанию, которое вычисляется один раз — в момент определения функции, а не при каждом её вызове.
Что происходит по шагам:
Когда Python читает определение функции, он сразу считает:
sum(nums)/len(nums)
Но nums в этот момент - это первый переданный список, то есть data1.
Значение avg фиксируется и больше не меняется.
При вызове:
• count_above_avg(data2)
• среднее значение не пересчитывается, используется старое — от data1.
Поэтому логика ломается, функция работает с неверным средним.
📌 Это известная ловушка Python
Значения аргументов по умолчанию вычисляются один раз.
Это та же причина, почему списки и словари в дефолтных параметрах часто приводят к багам.
🛠 Правильное решение
Нужно вычислять среднее внутри функции, а не в параметрах:
```python
def count_above_avg(nums, avg=None):
if avg is None:
avg = sum(nums) / len(nums)
return sum(1 for n in nums if n > avg)
```
Теперь среднее будет считаться заново при каждом вызове.
💡 Главное правило
Никогда не используй вычисляемые или изменяемые объекты как значения по умолчанию:
❌ def f(x, lst=[])
❌ def f(x, avg=sum(x)/len(x))
✅ Используй None и считай внутри функции.
Код должен посчитать количество чисел больше среднего значения в списке.
def count_above_avg(nums, avg=sum(nums)/len(nums)):
count = 0
for n in nums:
if n > avg:
count += 1
return count
data1 = [1, 2, 3, 4, 5]
data2 = [10, 20, 30]
print(count_above_avg(data1))
print(count_above_avg(data2))
```python
def count_above_avg(nums, avg=sum(nums)/len(nums)):
```
Здесь используется значение по умолчанию, которое вычисляется один раз — в момент определения функции, а не при каждом её вызове.
Что происходит по шагам:
Когда Python читает определение функции, он сразу считает:
sum(nums)/len(nums)
Но nums в этот момент - это первый переданный список, то есть data1.
Значение avg фиксируется и больше не меняется.
При вызове:
• count_above_avg(data2)
• среднее значение не пересчитывается, используется старое — от data1.
Поэтому логика ломается, функция работает с неверным средним.
📌 Это известная ловушка Python
Значения аргументов по умолчанию вычисляются один раз.
Это та же причина, почему списки и словари в дефолтных параметрах часто приводят к багам.
🛠 Правильное решение
Нужно вычислять среднее внутри функции, а не в параметрах:
```python
def count_above_avg(nums, avg=None):
if avg is None:
avg = sum(nums) / len(nums)
return sum(1 for n in nums if n > avg)
```
Теперь среднее будет считаться заново при каждом вызове.
💡 Главное правило
Никогда не используй вычисляемые или изменяемые объекты как значения по умолчанию:
❌ def f(x, lst=[])
❌ def f(x, avg=sum(x)/len(x))
✅ Используй None и считай внутри функции.
Ты научишься делать те, которые живут в проде.
Это не про BeautifulSoup ради галочки.
Это про системы сбора данных, которые:
• не падают от мелких правок на сайте
• собирают данные в разы быстрее
• обновляют всё сами по расписанию
• обходят ограничения и баны
• выглядят как сервис, а не хаос из файлов
Ты начнёшь видеть сайты не как страницы, а как источники данных, к которым можно подключиться.
В итоге ты сможешь:
• забирать данные для своих проектов
• автоматизировать чужую рутину
• делать инструменты для аналитики
• брать коммерческие заказы на сбор данных
Это навык, который напрямую превращается в деньги.
Не “знаю Python”, а умею добывать данные из интернета профессионально.
🎁 48 часов скидка 50% на Stepik: https://stepik.org/a/269942/
Please open Telegram to view this post
VIEW IN TELEGRAM
Этот код выдаст ошибку, если ввести в качестве инпута -5.
Anonymous Quiz
38%
True
54%
False
8%
Посмотреть ответ