🤔 Что такое паттерн Мост (Bridge)?
Паттерн "Мост" (Bridge) является структурным паттерном проектирования, который предназначен для разделения абстракции и реализации так, чтобы они могли изменяться независимо друг от друга. Этот паттерн полезен, когда класс должен работать с различными платформами или когда нужно избежать жесткой связки между абстракцией и ее реализацией.
🚩 Зачем нужен
🟠Разделение абстракции и реализации:
Он позволяет отделить абстракцию от ее реализации, что упрощает поддержку и расширение системы.
🟠Уменьшение количества подклассов:
Без применения этого паттерна, если у нас есть несколько вариантов абстракции и несколько вариантов реализации, то нам пришлось бы создавать классы для всех возможных комбинаций, что приводит к взрывному росту количества классов.
🟠Гибкость:
Это позволяет изменять и абстракцию, и реализацию независимо друг от друга.
🚩Как используется
🟠Абстракция (Abstraction):
Определяет интерфейс и хранит ссылку на объект Implementor.
🟠Расширенная абстракция (RefinedAbstraction):
Наследует Abstraction и расширяет интерфейс.
🟠Реализатор (Implementor):
Определяет интерфейс для всех реализаций.
🟠Конкретный реализатор (ConcreteImplementor):
Реализует интерфейс Implementor.
Допустим, у нас есть программа для управления различными типами устройств (например, телевизор и радио), которые можно включать и выключать. Мы хотим, чтобы способ управления устройствами мог изменяться независимо от типов устройств.
Ставь 👍 и забирай 📚 Базу знаний
Паттерн "Мост" (Bridge) является структурным паттерном проектирования, который предназначен для разделения абстракции и реализации так, чтобы они могли изменяться независимо друг от друга. Этот паттерн полезен, когда класс должен работать с различными платформами или когда нужно избежать жесткой связки между абстракцией и ее реализацией.
🚩 Зачем нужен
🟠Разделение абстракции и реализации:
Он позволяет отделить абстракцию от ее реализации, что упрощает поддержку и расширение системы.
🟠Уменьшение количества подклассов:
Без применения этого паттерна, если у нас есть несколько вариантов абстракции и несколько вариантов реализации, то нам пришлось бы создавать классы для всех возможных комбинаций, что приводит к взрывному росту количества классов.
🟠Гибкость:
Это позволяет изменять и абстракцию, и реализацию независимо друг от друга.
🚩Как используется
🟠Абстракция (Abstraction):
Определяет интерфейс и хранит ссылку на объект Implementor.
🟠Расширенная абстракция (RefinedAbstraction):
Наследует Abstraction и расширяет интерфейс.
🟠Реализатор (Implementor):
Определяет интерфейс для всех реализаций.
🟠Конкретный реализатор (ConcreteImplementor):
Реализует интерфейс Implementor.
Допустим, у нас есть программа для управления различными типами устройств (например, телевизор и радио), которые можно включать и выключать. Мы хотим, чтобы способ управления устройствами мог изменяться независимо от типов устройств.
# Implementor
class Device:
def is_enabled(self):
pass
def enable(self):
pass
def disable(self):
pass
# ConcreteImplementor
class TV(Device):
def __init__(self):
self._on = False
def is_enabled(self):
return self._on
def enable(self):
self._on = True
def disable(self):
self._on = False
class Radio(Device):
def __init__(self):
self._on = False
def is_enabled(self):
return self._on
def enable(self):
self._on = True
def disable(self):
self._on = False
# Abstraction
class RemoteControl:
def __init__(self, device):
self._device = device
def toggle_power(self):
if self._device.is_enabled():
self._device.disable()
else:
self._device.enable()
# RefinedAbstraction
class AdvancedRemoteControl(RemoteControl):
def mute(self):
print("Device is muted.")
# Клиентский код
tv = TV()
remote = RemoteControl(tv)
remote.toggle_power() # Включает TV
radio = Radio()
advanced_remote = AdvancedRemoteControl(radio)
advanced_remote.toggle_power() # Включает Radio
advanced_remote.mute() # Заглушает Radio
Ставь 👍 и забирай 📚 Базу знаний
👍3
🤔 Какие основные функции Python есть?
Встроенные функции Python включают такие базовые инструменты, как len, type, print, input, int, str, list, dict, sum, max, min, zip, enumerate, range, map, filter и многие другие. Они обеспечивают широкий функционал без необходимости импортировать внешние библиотеки.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Встроенные функции Python включают такие базовые инструменты, как len, type, print, input, int, str, list, dict, sum, max, min, zip, enumerate, range, map, filter и многие другие. Они обеспечивают широкий функционал без необходимости импортировать внешние библиотеки.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Зачем нужен volume в docker?
В Docker
🚩Зачем нужен `volume`?
Данные не теряются при удалении контейнера
Общий доступ: несколько контейнеров могут использовать один и тот же
Производительность: тома быстрее, чем хранение внутри контейнера
Разделение кода и данных: удобно для баз данных и логов
🚩Как создать `volume`?
Способ 1: Автоматическое создание при запуске контейнера
Способ 2: Создать том отдельно и подключить его
Способ 3: Использовать путь на хосте (bind-mount)
🚩Как посмотреть список томов?
🚩Как удалить `volume`?
Важно: при удалении тома данные удаляются безвозвратно!
Ставь 👍 и забирай 📚 Базу знаний
В Docker
volume (том) — это специальное место для хранения данных контейнера, которое не исчезает при перезапуске или удалении контейнера. 🚩Зачем нужен `volume`?
Данные не теряются при удалении контейнера
Общий доступ: несколько контейнеров могут использовать один и тот же
volume Производительность: тома быстрее, чем хранение внутри контейнера
Разделение кода и данных: удобно для баз данных и логов
🚩Как создать `volume`?
Способ 1: Автоматическое создание при запуске контейнера
docker run -d -v my_volume:/app/data my_container
Способ 2: Создать том отдельно и подключить его
docker volume create my_volume
docker run -d -v my_volume:/app/data my_container
Способ 3: Использовать путь на хосте (bind-mount)
docker run -d -v /home/user/data:/app/data my_container
🚩Как посмотреть список томов?
docker volume ls # Покажет все тома
docker volume inspect my_volume # Информация о томе
🚩Как удалить `volume`?
Важно: при удалении тома данные удаляются безвозвратно!
docker volume rm my_volume # Удаление одного тома
docker volume prune # Удаление всех неиспользуемых томов
Ставь 👍 и забирай 📚 Базу знаний
👍1
🤔 Что такое dict comprehensions?
🚩Простейший пример `dict comprehension`
Вывод
🚩`dict comprehension` с условием (`if`)
Оставляем только чётные числа:
Вывод
🚩Преобразование списка в словарь
Создаём словарь из списка пар (
Вывод
🚩Обратный словарь (ключи и значения меняются местами)
Инвертируем словарь
Вывод
🚩Генерация словаря из `zip()`
Объединяем два списка в словарь
Вывод
🚩`dict comprehension` с `if-else`
Разделяем числа на чётные и нечётные
Вывод
Ставь 👍 и забирай 📚 Базу знаний
dict comprehension (генератор словаря) — это способ быстро создать словарь с помощью компактного синтаксиса, похожего на list comprehension. 🚩Простейший пример `dict comprehension`
squares = {x: x**2 for x in range(1, 6)}
print(squares)Вывод
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}🚩`dict comprehension` с условием (`if`)
Оставляем только чётные числа:
squares = {x: x**2 for x in range(1, 11) if x % 2 == 0}
print(squares)Вывод
{2: 4, 4: 16, 6: 36, 8: 64, 10: 100}🚩Преобразование списка в словарь
Создаём словарь из списка пар (
name → длина слова) names = ["Alice", "Bob", "Charlie"]
name_lengths = {name: len(name) for name in names}
print(name_lengths)
Вывод
{'Alice': 5, 'Bob': 3, 'Charlie': 7}🚩Обратный словарь (ключи и значения меняются местами)
Инвертируем словарь
{ключ: значение} → {значение: ключ} original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
print(inverted)Вывод
{1: 'a', 2: 'b', 3: 'c'}🚩Генерация словаря из `zip()`
Объединяем два списка в словарь
keys = ["name", "age", "city"]
values = ["Alice", 25, "New York"]
person = {k: v for k, v in zip(keys, values)}
print(person)
Вывод
{'name': 'Alice', 'age': 25, 'city': 'New York'}🚩`dict comprehension` с `if-else`
Разделяем числа на чётные и нечётные
numbers = range(1, 6)
parity = {x: "чётное" if x % 2 == 0 else "нечётное" for x in numbers}
print(parity)
Вывод
{1: 'нечётное', 2: 'чётное', 3: 'нечётное', 4: 'чётное', 5: 'нечётное'}Ставь 👍 и забирай 📚 Базу знаний
🤔 В чем отличие изменяемые / неизменяемые?
В Python все данные делятся на изменяемые (mutable) и неизменяемые (immutable)
🚩Неизменяемые (`immutable`) типы
После создания их нельзя изменить!
Пример:
🚩Изменяемые (`mutable`) типы
Можно менять их содержимое без создания нового объекта.
Пример:
🚩Почему это важно?
Неизменяемые объекты безопаснее для ключей
Используем
Ошибки с изменяемыми значениями по умолчанию
Используем
🚩Копирование объектов (`copy()` vs `deepcopy()`)
Используем
Ставь 👍 и забирай 📚 Базу знаний
В Python все данные делятся на изменяемые (mutable) и неизменяемые (immutable)
🚩Неизменяемые (`immutable`) типы
После создания их нельзя изменить!
x = 10
print(id(x)) # 140735598722544 (адрес в памяти)
x = x + 5 # Создаётся новый объект!
print(id(x)) # 140735598722704 (новый адрес)
Пример:
str неизменяемая s = "hello"
print(id(s)) # 140735598723664
s = s + " world" # Создаётся новая строка!
print(id(s)) # 140735598724240 (новый адрес)
🚩Изменяемые (`mutable`) типы
Можно менять их содержимое без создания нового объекта.
lst = [1, 2, 3]
print(id(lst)) # 140735598722544
lst.append(4) # Изменяем список
print(id(lst)) # 140735598722544 (адрес остался тот же!)
Пример:
dict изменяемый d = {"name": "Alice"}
print(id(d)) # 140735598723664
d["age"] = 25 # Добавляем ключ
print(id(d)) # 140735598723664 (адрес не изменился!)🚩Почему это важно?
Неизменяемые объекты безопаснее для ключей
dict и set d = {}
d[[1, 2, 3]] = "Ошибка!" # ❌ TypeError: unhashable type: 'list'Используем
tuple вместо list (он неизменяемый) d[(1, 2, 3)] = "OK"
Ошибки с изменяемыми значениями по умолчанию
def add_item(lst=[]): # ❌ Опасный код!
lst.append(1)
return lst
print(add_item()) # [1]
print(add_item()) # [1, 1] ❌ Список не создаётся заново!
Используем
None вместо списка def add_item(lst=None):
if lst is None:
lst = []
lst.append(1)
return lst
🚩Копирование объектов (`copy()` vs `deepcopy()`)
copy() делает поверхностную копию (новый объект, но старые вложенные элементы). deepcopy() делает глубокую копию (всё новое). import copy
lst1 = [[1, 2, 3], [4, 5, 6]]
lst2 = copy.copy(lst1) # Поверхностная копия
lst2[0][0] = 99
print(lst1) # [[99, 2, 3], [4, 5, 6]] ❌ Исходный список изменился!
Используем
deepcopy() для полной независимой копии lst3 = copy.deepcopy(lst1)
lst3[0][0] = 100
print(lst1) # [[99, 2, 3], [4, 5, 6]] ✅ Не изменился!
Ставь 👍 и забирай 📚 Базу знаний
🤔 Можно ли при вызове метода save указать какие поля изменять?
Да, в Django ORM можно указать конкретные поля для сохранения, используя параметр
🚩Как использовать `update_fields`
Пример модели
Обновляем только поле
🚩Что делает `update_fields`?
Генерирует SQL-запрос только для указанных полей, например:
🚩Когда `update_fields` полезен?
Уменьшает нагрузку на БД, так как обновляет только нужные поля.
Полезен, если нужно изменить одно поле, а не всю запись.
Избегает ненужных изменений в
🚩Ограничения `update_fields`
Нельзя использовать при создании объекта (
Не обновляет
Решение: обновить вручную:
Ставь 👍 и забирай 📚 Базу знаний
Да, в Django ORM можно указать конкретные поля для сохранения, используя параметр
update_fields в методе .save(). 🚩Как использовать `update_fields`
Пример модели
from django.db import models
class UserProfile(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
age = models.IntegerField()
Обновляем только поле
name, не трогая email и age user = UserProfile.objects.get(id=1)
user.name = "Новый пользователь"
user.save(update_fields=["name"]) # Обновит только поле `name`
🚩Что делает `update_fields`?
Генерирует SQL-запрос только для указанных полей, например:
UPDATE user_profile SET name = 'Новый пользователь' WHERE id = 1;
🚩Когда `update_fields` полезен?
Уменьшает нагрузку на БД, так как обновляет только нужные поля.
Полезен, если нужно изменить одно поле, а не всю запись.
Избегает ненужных изменений в
auto_now и auto_now_add полях (DateTimeField). 🚩Ограничения `update_fields`
Нельзя использовать при создании объекта (
save() с update_fields не работает для .create()). user = UserProfile(name="Alice", email="alice@example.com")
user.save(update_fields=["name"]) # ❌ Ошибка, объект ещё не в базе!
Не обновляет
auto_now-поля (DateTimeField) автоматически! updated_at = models.DateTimeField(auto_now=True) # Не обновится с `update_fields`
Решение: обновить вручную:
user.updated_at = timezone.now()
user.save(update_fields=["name", "updated_at"])
Ставь 👍 и забирай 📚 Базу знаний
🤔 Что такое звёздный синтаксис (*)?
В Python * используется: – при распаковке (например, аргументов или списков),
– для переменного числа аргументов функции,
– в срезах и других операциях с коллекциями.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
В Python * используется: – при распаковке (например, аргументов или списков),
– для переменного числа аргументов функции,
– в срезах и других операциях с коллекциями.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍1🤔1💊1
🤔 Какие ограничения есть у рекурсии в Python?
Рекурсия — это мощный инструмент, но в Python она имеет ограничения, которые нужно учитывать при написании кода.
🟠Ограничение на глубину рекурсии (`sys.getrecursionlimit()`)
В Python по умолчанию рекурсия ограничена 1000 вызовами, чтобы избежать переполнения стека.
Если превысить этот лимит, программа вызовет ошибку
🚩Как изменить лимит?
Можно увеличить глубину рекурсии, но это небезопасно
🟠Рекурсия требует много памяти
Каждый рекурсивный вызов создаёт новый фрейм в стеке вызовов.
🟠Отсутствие оптимизации хвостовой рекурсии
Другие языки (например, Lisp, JavaScript) автоматически оптимизируют хвостовую рекурсию (Tail Call Optimization, TCO).
Python не делает этого, поэтому даже "идеальная" рекурсия всё равно переполняет стек.
🟠Рекурсия медленнее цикла
Рекурсивный вызов требует больше накладных расходов (создание стек-фреймов), чем обычный
Ставь 👍 и забирай 📚 Базу знаний
Рекурсия — это мощный инструмент, но в Python она имеет ограничения, которые нужно учитывать при написании кода.
🟠Ограничение на глубину рекурсии (`sys.getrecursionlimit()`)
В Python по умолчанию рекурсия ограничена 1000 вызовами, чтобы избежать переполнения стека.
import sys
print(sys.getrecursionlimit()) # 1000 (обычное значение)
Если превысить этот лимит, программа вызовет ошибку
def recursive():
return recursive()
recursive() # RecursionError: maximum recursion depth exceeded
🚩Как изменить лимит?
Можно увеличить глубину рекурсии, но это небезопасно
sys.setrecursionlimit(2000) # Увеличиваем до 2000
🟠Рекурсия требует много памяти
Каждый рекурсивный вызов создаёт новый фрейм в стеке вызовов.
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(10000)) # Ошибка из-за переполнения стека
🟠Отсутствие оптимизации хвостовой рекурсии
Другие языки (например, Lisp, JavaScript) автоматически оптимизируют хвостовую рекурсию (Tail Call Optimization, TCO).
Python не делает этого, поэтому даже "идеальная" рекурсия всё равно переполняет стек.
def tail_recursive(n, acc=1):
if n == 1:
return acc
return tail_recursive(n - 1, n * acc)
print(tail_recursive(1000)) # Всё равно вызовет RecursionError
🟠Рекурсия медленнее цикла
Рекурсивный вызов требует больше накладных расходов (создание стек-фреймов), чем обычный
for или while.# Итеративный вариант (быстрее)
def factorial_iter(n):
result = 1
for i in range(1, n + 1):
result *= i
return result
# Рекурсивный вариант (медленнее)
def factorial_rec(n):
if n == 1:
return 1
return n * factorial_rec(n - 1)
Ставь 👍 и забирай 📚 Базу знаний
👍1
🤔 Какие есть операторы ограничений?
Ограничения (constraints) в SQL используются для контроля целостности данных в таблицах. Они помогают предотвратить некорректные значения и обеспечить согласованность данных.
🚩`NOT NULL` (Запрещает `NULL`)
Используется, если поле обязательно для заполнения
Нельзя вставить
🚩`UNIQUE` (Гарантирует уникальность значений)
Запрещает дубликаты в столбце
Попытка вставить одинаковый email вызовет ошибку
Создание
🚩`PRIMARY KEY` (Главный ключ, уникальный идентификатор)
Объединяет
Можно создать
🚩`FOREIGN KEY` (Связь таблиц)
Создаёт связь между таблицами и поддерживает ссылочную целостность.
Есть таблица пользователей (
Что делать при удалении пользователя?
Ставь 👍 и забирай 📚 Базу знаний
Ограничения (constraints) в SQL используются для контроля целостности данных в таблицах. Они помогают предотвратить некорректные значения и обеспечить согласованность данных.
🚩`NOT NULL` (Запрещает `NULL`)
Используется, если поле обязательно для заполнения
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL -- Поле name обязательно
);
Нельзя вставить
NULL в name INSERT INTO users (id, name) VALUES (1, NULL); -- Ошибка!
🚩`UNIQUE` (Гарантирует уникальность значений)
Запрещает дубликаты в столбце
CREATE TABLE users (
id INT PRIMARY KEY,
email VARCHAR(100) UNIQUE -- Email должен быть уникальным
);
Попытка вставить одинаковый email вызовет ошибку
INSERT INTO users (id, email) VALUES (1, 'test@example.com');
INSERT INTO users (id, email) VALUES (2, 'test@example.com'); -- Ошибка!
Создание
UNIQUE на нескольких колонках CREATE TABLE orders (
user_id INT,
product_id INT,
UNIQUE (user_id, product_id) -- Запрещает заказывать один товар дважды
);
🚩`PRIMARY KEY` (Главный ключ, уникальный идентификатор)
Объединяет
NOT NULL + UNIQUE и гарантирует, что строка уникальна. CREATE TABLE users (
id INT PRIMARY KEY, -- Уникальный идентификатор
name VARCHAR(50)
);
Можно создать
PRIMARY KEY на нескольких колонках CREATE TABLE enrollments (
student_id INT,
course_id INT,
PRIMARY KEY (student_id, course_id) -- Один студент не может записаться дважды на один курс
);
🚩`FOREIGN KEY` (Связь таблиц)
Создаёт связь между таблицами и поддерживает ссылочную целостность.
Есть таблица пользователей (
users) и таблица заказов (orders), где user_id в orders должен ссылаться на id в users. CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id) -- Связь с таблицей users
);
Что делать при удалении пользователя?
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
Ставь 👍 и забирай 📚 Базу знаний
🤔 Как собрать образ в Docker?
Образ собирается из Dockerfile при помощи команды сборки. В процессе выполнения создаются слои, соответствующие каждой инструкции в Dockerfile. По завершении формируется итоговый образ, который можно запускать как контейнер.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Образ собирается из Dockerfile при помощи команды сборки. В процессе выполнения создаются слои, соответствующие каждой инструкции в Dockerfile. По завершении формируется итоговый образ, который можно запускать как контейнер.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🔥3
🤔 Что случится с сервером при использовании GET?
Когда сервер получает HTTP-запрос типа GET, он выполняет следующие действия
🟠Анализ запроса
проверяет URL и параметры в строке запроса (например,
🟠Поиск ресурса
находит запрашиваемый файл, данные из базы или другой ресурс.
🟠Возврат ответа
отправляет данные клиенту (если ресурс найден — код 200, если нет — 404).
🚩Особенности GET-запроса
🟠Безопасный
не изменяет данные на сервере, используется только для чтения.
🟠Идемпотентный
повторные запросы дают одинаковый результат.
🟠Параметры в URL
данные передаются через строку запроса, что не подходит для конфиденциальной информации.
Ставь 👍 и забирай 📚 Базу знаний
Когда сервер получает HTTP-запрос типа GET, он выполняет следующие действия
🟠Анализ запроса
проверяет URL и параметры в строке запроса (например,
?id=123). 🟠Поиск ресурса
находит запрашиваемый файл, данные из базы или другой ресурс.
🟠Возврат ответа
отправляет данные клиенту (если ресурс найден — код 200, если нет — 404).
🚩Особенности GET-запроса
🟠Безопасный
не изменяет данные на сервере, используется только для чтения.
🟠Идемпотентный
повторные запросы дают одинаковый результат.
🟠Параметры в URL
данные передаются через строку запроса, что не подходит для конфиденциальной информации.
import requests
response = requests.get("https://api.example.com/data", params={"id": 123})
print(response.text) # Данные с сервера
Ставь 👍 и забирай 📚 Базу знаний
👍1💊1
🤔 Почему вычислять большие значения в асинхронной функции плохо?
Асинхронность (
Если в
🚩Асинхронность в Python подходит для ввода-вывода (I/O-bound)
Асинхронность позволяет выполнять задачи без блокировки, но только если они ждут чего-то (файлы, сеть, БД).
🚩Проблема с `async` и тяжёлыми вычислениями (CPU-bound)
Если в
🚩Как правильно выполнять вычисления в `async`?
🟠Использовать `asyncio.to_thread()` (делегирование в потоки)
В Python 3.9+ можно выполнять CPU-задачи в отдельных потоках, не блокируя
🟠Использовать `multiprocessing` (запуск на нескольких ядрах)
Так как Python использует GIL, единственный способ выполнять настоящий параллелизм — это
Ставь 👍 и забирай 📚 Базу знаний
Асинхронность (
asyncio) в Python не выполняет код параллельно, а переключается между задачами во время ожидания (I/O-bound). Если в
async-функции делать тяжёлые вычисления (CPU-bound), это блокирует asyncio, потому что в Python есть GIL (Global Interpreter Lock). 🚩Асинхронность в Python подходит для ввода-вывода (I/O-bound)
Асинхронность позволяет выполнять задачи без блокировки, но только если они ждут чего-то (файлы, сеть, БД).
import asyncio
import aiohttp
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["https://example.com"] * 5
results = await asyncio.gather(*(fetch(url) for url in urls))
asyncio.run(main())
🚩Проблема с `async` и тяжёлыми вычислениями (CPU-bound)
Если в
async-функции делать тяжёлые вычисления, Python не сможет переключаться между задачами. import asyncio
async def heavy_task(n):
print(f"Вычисляю {n}...")
total = sum(i**2 for i in range(n)) # Долгий процесс
return total
async def main():
await asyncio.gather(heavy_task(10**7), heavy_task(10**7))
asyncio.run(main())
🚩Как правильно выполнять вычисления в `async`?
🟠Использовать `asyncio.to_thread()` (делегирование в потоки)
В Python 3.9+ можно выполнять CPU-задачи в отдельных потоках, не блокируя
asyncio. import asyncio
def heavy_computation(n):
return sum(i**2 for i in range(n))
async def main():
result = await asyncio.to_thread(heavy_computation, 10**7)
print(result)
asyncio.run(main())
🟠Использовать `multiprocessing` (запуск на нескольких ядрах)
Так как Python использует GIL, единственный способ выполнять настоящий параллелизм — это
multiprocessing.import asyncio
import multiprocessing
def heavy_computation(n):
return sum(i**2 for i in range(n))
async def main():
loop = asyncio.get_running_loop()
with multiprocessing.Pool() as pool:
result = await loop.run_in_executor(pool, heavy_computation, 10**7)
print(result)
asyncio.run(main())
Ставь 👍 и забирай 📚 Базу знаний
👍3
🤔 Какие магические методы и для чего используются?
Магические методы (например, __init__, __str__, __len__, __add__) используются для определения поведения объектов в специфичных ситуациях, таких как инициализация, строковое представление, арифметические операции или работа с коллекциями.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍2
🤔 Что делать если нужно перехватить исключение, выполнить действия и опять возбудить это же исключение?
Если нужно:
Перехватить исключение
Выполнить какие-то действия (лог, очистка, уведомление и т. д.)
Снова выбросить это же исключение
Вывод
Пример: Логирование перед повторным выбросом
Пример: Очистка ресурсов перед выбросом исключения
Ставь 👍 и забирай 📚 Базу знаний
Если нужно:
Перехватить исключение
Выполнить какие-то действия (лог, очистка, уведомление и т. д.)
Снова выбросить это же исключение
try:
x = 1 / 0 # Ошибка деления на ноль
except ZeroDivisionError:
print("Ошибка! Записываем в лог...")
raise # Повторно выбрасываем то же исключение
Вывод
Ошибка! Записываем в лог...
Traceback (most recent call last):
File "script.py", line 2, in <module>
x = 1 / 0
ZeroDivisionError: division by zero
Пример: Логирование перед повторным выбросом
import logging
logging.basicConfig(filename="errors.log", level=logging.ERROR)
try:
user_input = int("abc") # Ошибка ValueError
except ValueError as e:
logging.error(f"Ошибка: {e}") # Записываем в лог
raise # Повторно выбрасываем исключение
Пример: Очистка ресурсов перед выбросом исключения
try:
file = open("data.txt", "r")
data = file.read()
except FileNotFoundError:
print("Файл не найден. Освобождаем ресурсы...")
raise # Снова выбрасываем исключение
finally:
file.close() # Гарантированно закроет файл
Ставь 👍 и забирай 📚 Базу знаний
🤔 Что такое git?
Git — это система контроля версий, позволяющая отслеживать изменения в коде, управлять ветками и работать в команде. Она поддерживает распределённый подход, где каждый разработчик имеет локальную копию репозитория. Git используется для ведения истории изменений и упрощения совместной работы.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Как разбить список?
Разбить список (
На части фиксированной длины
На N частей
По условию
🚩Разбить список на части фиксированного размера
Если нужно разделить список на подсписки длиной
Вывод
🚩Разбить список на N частей (равных или почти равных)
Если нужно разделить список на
Вывод
🚩Разбить список по условию
Если нужно разделить список по какому-то критерию, например, на чётные и нечётные числа
Вывод
Ставь 👍 и забирай 📚 Базу знаний
Разбить список (
list) можно разными способами в зависимости от задачи: На части фиксированной длины
На N частей
По условию
🚩Разбить список на части фиксированного размера
Если нужно разделить список на подсписки длиной
n, можно использовать list comprehensiondef split_list(lst, size):
return [lst[i:i + size] for i in range(0, len(lst), size)]
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(split_list(data, 3))
Вывод
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
🚩Разбить список на N частей (равных или почти равных)
Если нужно разделить список на
N частей, можно использовать numpy или itertools import numpy as np
def split_into_n_parts(lst, n):
return np.array_split(lst, n)
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(split_into_n_parts(data, 4))
Вывод
[array([1, 2, 3]), array([4, 5]), array([6, 7]), array([8, 9])]
🚩Разбить список по условию
Если нужно разделить список по какому-то критерию, например, на чётные и нечётные числа
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
even = [x for x in data if x % 2 == 0]
odd = [x for x in data if x % 2 != 0]
print(even, odd)
Вывод
[2, 4, 6, 8] [1, 3, 5, 7, 9]
Ставь 👍 и забирай 📚 Базу знаний
👍2
🤔 Что такое паттерн Стратегия (Strategy) ?
Это поведенческий паттерн проектирования, который определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Паттерн "Стратегия" позволяет изменять алгоритмы независимо от клиентов, которые их используют.
🚩Зачем нужен данный паттерн?
🟠Изоляция алгоритмов
Позволяет инкапсулировать различные алгоритмы и использовать их независимо.
🟠Упрощение кода
Устраняет дублирование кода и упрощает классы, которые используют эти алгоритмы.
🟠Гибкость и расширяемость
Легко добавлять новые алгоритмы или изменять существующие без изменения клиентского кода.
🚩Как работает данный паттерн?
🟠Стратегия (Strategy)
Интерфейс, определяющий общий метод, который должны реализовать все алгоритмы.
🟠Конкретные стратегии (ConcreteStrategy)
Реализации различных алгоритмов, которые реализуют интерфейс стратегии.
🟠Контекст (Context)
Класс, использующий стратегию для выполнения задачи.
🚩Плюсы и минусы
➕Изоляция алгоритмов
Алгоритмы инкапсулируются в отдельные классы, что упрощает их замену и добавление.
➕Упрощение кода
Контекст использует стратегии, избегая громоздких условных операторов.
➕Гибкость и расширяемость
Легко добавлять новые стратегии без изменения существующего кода.
➖Усложнение структуры кода
Добавление множества классов стратегий может усложнить проект.
➖Контекст знает о стратегиях
Контекст должен знать о всех возможных стратегиях, чтобы иметь возможность их переключать.
🚩Когда использовать данный паттерн?
Когда есть несколько вариантов алгоритмов для выполнения задачи.
Когда нужно динамически выбирать алгоритм во время выполнения.
Когда необходимо избежать множества условных операторов для выбора алгоритма.
Ставь 👍 и забирай 📚 Базу знаний
Это поведенческий паттерн проектирования, который определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Паттерн "Стратегия" позволяет изменять алгоритмы независимо от клиентов, которые их используют.
🚩Зачем нужен данный паттерн?
🟠Изоляция алгоритмов
Позволяет инкапсулировать различные алгоритмы и использовать их независимо.
🟠Упрощение кода
Устраняет дублирование кода и упрощает классы, которые используют эти алгоритмы.
🟠Гибкость и расширяемость
Легко добавлять новые алгоритмы или изменять существующие без изменения клиентского кода.
🚩Как работает данный паттерн?
🟠Стратегия (Strategy)
Интерфейс, определяющий общий метод, который должны реализовать все алгоритмы.
🟠Конкретные стратегии (ConcreteStrategy)
Реализации различных алгоритмов, которые реализуют интерфейс стратегии.
🟠Контекст (Context)
Класс, использующий стратегию для выполнения задачи.
from abc import ABC, abstractmethod
# Интерфейс стратегии
class Strategy(ABC):
@abstractmethod
def sort(self, data):
pass
# Конкретные стратегии
class BubbleSortStrategy(Strategy):
def sort(self, data):
print("Sorting using Bubble Sort")
for i in range(len(data)):
for j in range(0, len(data)-i-1):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]
class QuickSortStrategy(Strategy):
def sort(self, data):
print("Sorting using Quick Sort")
self.quick_sort(data, 0, len(data) - 1)
def quick_sort(self, data, low, high):
if low < high:
pi = self.partition(data, low, high)
self.quick_sort(data, low, pi - 1)
self.quick_sort(data, pi + 1, high)
def partition(self, data, low, high):
pivot = data[high]
i = low - 1
for j in range(low, high):
if data[j] <= pivot:
i = i + 1
data[i], data[j] = data[j], data[i]
data[i + 1], data[high] = data[high], data[i + 1]
return i + 1
# Контекст
class SortingContext:
def __init__(self, strategy: Strategy):
self._strategy = strategy
def set_strategy(self, strategy: Strategy):
self._strategy = strategy
def sort(self, data):
self._strategy.sort(data)
# Клиентский код
data = [5, 2, 9, 1, 5, 6]
context = SortingContext(BubbleSortStrategy())
context.sort(data)
print(data) # [1, 2, 5, 5, 6, 9]
context.set_strategy(QuickSortStrategy())
data = [3, 7, 8, 5, 2, 1, 9, 5, 4]
context.sort(data)
print(data) # [1, 2, 3, 4, 5, 5, 7, 8, 9]
🚩Плюсы и минусы
➕Изоляция алгоритмов
Алгоритмы инкапсулируются в отдельные классы, что упрощает их замену и добавление.
➕Упрощение кода
Контекст использует стратегии, избегая громоздких условных операторов.
➕Гибкость и расширяемость
Легко добавлять новые стратегии без изменения существующего кода.
➖Усложнение структуры кода
Добавление множества классов стратегий может усложнить проект.
➖Контекст знает о стратегиях
Контекст должен знать о всех возможных стратегиях, чтобы иметь возможность их переключать.
🚩Когда использовать данный паттерн?
Когда есть несколько вариантов алгоритмов для выполнения задачи.
Когда нужно динамически выбирать алгоритм во время выполнения.
Когда необходимо избежать множества условных операторов для выбора алгоритма.
Ставь 👍 и забирай 📚 Базу знаний
👍2
🤔 Что такое переменная?
Переменная — это имя, связанное с объектом в памяти. В Python переменные не имеют типа — тип привязан к значению. Они позволяют хранить и переиспользовать данные в программе.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Переменная — это имя, связанное с объектом в памяти. В Python переменные не имеют типа — тип привязан к значению. Они позволяют хранить и переиспользовать данные в программе.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Как избежать конфликтов при импорте файлов?
Когда в проекте много файлов, могут возникать конфликты импортов. Python ищет модули в определённом порядке, и если несколько файлов имеют одинаковые имена или неправильные пути, может возникнуть ошибка.
🚩Способы избежать конфликтов при импорте
🟠Используйте явные пути импорта
Вместо
Лучше указывать полный путь в пакетах
🟠Избегайте конфликтов имён файлов
Если у вас есть файл
- Не называйте файлы именами стандартных модулей:
- Проверьте, какой именно модуль загружается:
🟠Добавьте `__init__.py` в пакеты
Если у вас есть структура
Решение
Добавьте пустой
Теперь импорт будет работать
🟠Используйте `sys.path.append()` для указания путей
Иногда Python не находит модуль, если он находится вне стандартных путей. Решение
Добавьте путь вручную:
🟠Используйте `absolute` и `relative` импорт в пакетах
Абсолютный импорт (рекомендуется)
Относительный импорт (используется внутри пакетов):
🟠Проверяйте `sys.modules` и `sys.path`
Если импорт не работает, проверьте, какие модули загружены и где Python ищет файлы
Ставь 👍 и забирай 📚 Базу знаний
Когда в проекте много файлов, могут возникать конфликты импортов. Python ищет модули в определённом порядке, и если несколько файлов имеют одинаковые имена или неправильные пути, может возникнуть ошибка.
🚩Способы избежать конфликтов при импорте
🟠Используйте явные пути импорта
Вместо
import mymodule # Может вызвать конфликт, если есть несколько файлов с таким именем
Лучше указывать полный путь в пакетах
from myproject.utils.mymodule import my_function
🟠Избегайте конфликтов имён файлов
Если у вас есть файл
math.py, импорт import math будет загружать ваш файл, а не стандартный модуль math из Python. - Не называйте файлы именами стандартных модулей:
math.py, sys.py, json.py. - Проверьте, какой именно модуль загружается:
import math
print(math.__file__) # Путь к загруженному модулю
🟠Добавьте `__init__.py` в пакеты
Если у вас есть структура
/myproject
/utils
mymodule.py
Решение
Добавьте пустой
__init__.py в utils/: /myproject
/utils
__init__.py # Делаем utils пакетом
mymodule.py
Теперь импорт будет работать
from utils import mymodule
🟠Используйте `sys.path.append()` для указания путей
Иногда Python не находит модуль, если он находится вне стандартных путей. Решение
Добавьте путь вручную:
import sys
sys.path.append("/path/to/directory")
import mymodule # Теперь импорт будет работать
🟠Используйте `absolute` и `relative` импорт в пакетах
Абсолютный импорт (рекомендуется)
from myproject.utils.mymodule import my_function
Относительный импорт (используется внутри пакетов):
from .mymodule import my_function
🟠Проверяйте `sys.modules` и `sys.path`
Если импорт не работает, проверьте, какие модули загружены и где Python ищет файлы
import sys
print(sys.modules.keys()) # Список загруженных модулей
print(sys.path) # Пути, где Python ищет модули
Ставь 👍 и забирай 📚 Базу знаний
🤔 Какие есть коллекции и их особенности по скорости работы и использованию памяти?
В Python основные коллекции: списки, кортежи, множества, словари.
- Списки: изменяемы, быстрые при доступе по индексу, но медленнее при вставке в середину. Используют больше памяти за счёт зарезервированного места для расширения.
- Кортежи: неизменяемы, занимают меньше памяти, быстрее при доступе, хорошо подходят для фиксированных наборов данных.
- Множества: обеспечивают быстрый поиск (как словари), но не сохраняют порядок. Используют хеши.
- Словари: ассоциативные коллекции с быстрым доступом по ключу. Эффективны при поиске и обновлении.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
В Python основные коллекции: списки, кортежи, множества, словари.
- Списки: изменяемы, быстрые при доступе по индексу, но медленнее при вставке в середину. Используют больше памяти за счёт зарезервированного места для расширения.
- Кортежи: неизменяемы, занимают меньше памяти, быстрее при доступе, хорошо подходят для фиксированных наборов данных.
- Множества: обеспечивают быстрый поиск (как словари), но не сохраняют порядок. Используют хеши.
- Словари: ассоциативные коллекции с быстрым доступом по ключу. Эффективны при поиске и обновлении.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🤔 Назови основные команды docker?
Docker — это инструмент для создания, развертывания и управления контейнерами. Основные команды позволяют управлять образами, контейнерами, сетями и томами.
🚩Работа с образами (`images`)
Образы — это "шаблоны" для создания контейнеров.
Пример: скачиваем Python-образ
🚩Работа с контейнерами (`containers`)
Контейнер — это запущенный процесс на основе образа.
Пример: запустить контейнер с Ubuntu и войти в него
Пример: остановить и удалить контейнер
🚩Работа с томами (`volumes`)
Том (volume) — это способ хранения данных, которые не пропадут при перезапуске контейнера.
Пример: подключить том к контейнеру
🚩Работа с сетями (`networks`)
Сети в Docker позволяют контейнерам взаимодействовать друг с другом.
Пример: запустить два контейнера в одной сети
🚩5. Docker Compose (`docker-compose.yml`)
Docker Compose позволяет управлять несколькими контейнерами с помощью
Пример
Запуск
Ставь 👍 и забирай 📚 Базу знаний
Docker — это инструмент для создания, развертывания и управления контейнерами. Основные команды позволяют управлять образами, контейнерами, сетями и томами.
🚩Работа с образами (`images`)
Образы — это "шаблоны" для создания контейнеров.
Пример: скачиваем Python-образ
docker pull python:3.11
🚩Работа с контейнерами (`containers`)
Контейнер — это запущенный процесс на основе образа.
Пример: запустить контейнер с Ubuntu и войти в него
docker run -it ubuntu bash
Пример: остановить и удалить контейнер
docker stop my_app
docker rm my_app
🚩Работа с томами (`volumes`)
Том (volume) — это способ хранения данных, которые не пропадут при перезапуске контейнера.
Пример: подключить том к контейнеру
docker run -v my_data:/app/data ubuntu
🚩Работа с сетями (`networks`)
Сети в Docker позволяют контейнерам взаимодействовать друг с другом.
Пример: запустить два контейнера в одной сети
docker network create my_network
docker run -d --network my_network --name app1 ubuntu
docker run -d --network my_network --name app2 ubuntu
🚩5. Docker Compose (`docker-compose.yml`)
Docker Compose позволяет управлять несколькими контейнерами с помощью
docker-compose.yml. Пример
docker-compose.ymlversion: "3"
services:
app:
image: python:3.11
volumes:
- my_data:/app/data
networks:
- my_network
volumes:
my_data:
networks:
my_network:
Запуск
docker compose up -d
Ставь 👍 и забирай 📚 Базу знаний
🔥1