Это поведенческий паттерн проектирования, который позволяет сохранять и восстанавливать предыдущее состояние объекта без нарушения инкапсуляции. Этот паттерн особенно полезен для реализации операций отмены и повтора, так как он позволяет хранить состояния объектов и возвращать их к этим состояниям по необходимости.
Позволяет сохранять текущее состояние объекта и восстанавливать его позже.
Обеспечивает сохранение состояния объекта без нарушения его инкапсуляции. Внутренние детали объекта остаются скрытыми от других объектов.
Поддерживает функциональность отмены и повтора операций, так как позволяет возвращать объект к предыдущим состояниям.
Пример реализации
class Memento:
def __init__(self, state: str):
self._state = state
def get_state(self) -> str:
return self._state
class TextEditor:
def __init__(self):
self._state = ""
self._history = []
def type(self, text: str):
self._save_state()
self._state += text
def _save_state(self):
self._history.append(Memento(self._state))
def undo(self):
if not self._history:
return
memento = self._history.pop()
self._state = memento.get_state()
def get_content(self) -> str:
return self._state
# Клиентский код для использования паттерна Хранитель
def main():
editor = TextEditor()
editor.type("Hello, ")
editor.type("world!")
print(editor.get_content()) # Hello, world!
editor.undo()
print(editor.get_content()) # Hello,
editor.undo()
print(editor.get_content()) #
if __name__ == "__main__":
main()
Сохраняет состояние объекта. Он предоставляет методы для получения сохраненного состояния, но не предоставляет методов для изменения состояния, что обеспечивает неизменность.
Создает и использует объекты
Memento для сохранения и восстановления своего состояния. Методы type и undo позволяют редактировать текст и отменять изменения.Сохраняет текущее состояние редактора в истории перед каждым изменением.
Восстанавливает предыдущее состояние редактора из истории.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Это форма записи условного выражения в одну строку, которая позволяет выбрать значение в зависимости от условия. Он удобен, когда нужно быстро присвоить значение переменной на основе простого условия, не используя полноценную конструкцию if.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
Асинхронность, threading и мультипроцессинг - это три различных подхода к параллельному выполнению задач каждый из которых имеет свои особенности и применения:
Асинхронность предполагает выполнение задач без ожидания их завершения. Используется для работы с вводом-выводом (I/O), таким как чтение или запись файлов, сетевые запросы и т. д. В асинхронном коде задачи не блокируют основной поток выполнения, что позволяет эффективно использовать ресурсы процессора. Примеры асинхронных моделей включают в себя асинхронные функции и ключевые слова в Python (например,
async, await).Потоки позволяют выполнять несколько частей кода (потоков) параллельно в пределах одного процесса. Используются для выполнения многозадачных операций, которые могут быть распределены между несколькими ядрами процессора. Потоки могут выполняться параллельно, но могут также конкурировать за общие ресурсы, что может привести к проблемам синхронизации и безопасности. В некоторых языках, таких как Python, использование потоков ограничено из-за GIL (Global Interpreter Lock), что может снижать эффективность при использовании множества потоков для CPU-интенсивных задач.
Мультипроцессинг также позволяет выполнять несколько частей кода параллельно, но каждая часть выполняется в отдельном процессе. Каждый процесс имеет свое собственное пространство памяти, что делает мультипроцессинг более подходящим для многозадачных вычислений на многоядерных системах. Процессы обычно имеют больший накладные расходы по сравнению с потоками, поскольку каждый из них требует своих собственных ресурсов памяти и управления. Мультипроцессинг избегает проблемы GIL, что делает его более эффективным для CPU-интенсивных задач в Python и других языках.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Внутри блока except можно использовать ключевое слово raise без аргументов, чтобы повторно выбросить текущее перехваченное исключение. Это полезно, если нужно что-то логировать или изменить, но затем продолжить распространение ошибки.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥2
Да, в Django ORM можно указать конкретные поля для сохранения, используя параметр
update_fields в методе .save(). Пример модели
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`
Генерирует SQL-запрос только для указанных полей, например:
UPDATE user_profile SET name = 'Новый пользователь' WHERE id = 1;
Уменьшает нагрузку на БД, так как обновляет только нужные поля.
Полезен, если нужно изменить одно поле, а не всю запись.
Избегает ненужных изменений в
auto_now и auto_now_add полях (DateTimeField). Нельзя использовать при создании объекта (
save() с update_fields не работает для .create()). user = UserProfile(name="Alice", email="[email protected]")
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"])
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Проверить наличие ключа в словаре можно с помощью оператора in
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊6👍5🔥2
Пакет (
package) в Python — это набор модулей, объединённых в одну директорию. Главное отличие от обычной папки — наличие файла __init__.py, который делает директорию пакетом. Допустим, мы хотим создать пакет
math_utils с модулями для работы с числами. /my_project
/math_utils ← Это пакет
__init__.py ← Делаем директорию пакетом
arithmetic.py ← Модуль с функциями сложения/вычитания
geometry.py ← Модуль с функциями для работы с фигурами
main.py ← Основной файл программы
Код в
arithmetic.pydef add(a, b):
return a + b
def subtract(a, b):
return a - b
Код в
geometry.py def square_area(side):
return side * side
Код в
__init__.py from .arithmetic import add, subtract
from .geometry import square_area
Теперь можно импортировать функции прямо из пакета:
from math_utils import add, square_area
print(add(2, 3)) # 5
print(square_area(4)) # 16
Импортируем весь пакет (с
__init__.py) from math_utils import add, square_area
Импортируем конкретный модуль
from math_utils import arithmetic
print(arithmetic.add(3, 5))
Импортируем конкретную функцию из модуля
from math_utils.arithmetic import add
print(add(3, 5))
Python ищет пакеты по
sys.path import sys
print(sys.path) # Пути, где Python ищет модули
Если Python не находит пакет, можно добавить путь вручную:
import sys
sys.path.append("/path/to/my_project")
Можно создавать вложенные пакеты
/my_project
/math_utils
__init__.py
/advanced
__init__.py
calculus.py
Импорт:
from math_utils.advanced.calculus import derivative
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
1. Упрощает установку, обновление и управление зависимостями через файл pyproject.toml.
2. Поддерживает изоляцию зависимостей, автоматически создавая виртуальное окружение.
3. Помогает публиковать собственные Python-пакеты в PyPI, упрощая процесс сборки и выпуска.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3💊3
CRUD — это аббревиатура из четырех основных операций с данными:
C (Create) – создание
R (Read) – чтение
U (Update) – обновление
D (Delete) – удаление
Добавление новой записи в базу данных.
import sqlite3
conn = sqlite3.connect("example.db")
cursor = conn.cursor()
# Создаем таблицу, если её нет
cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
# Добавляем пользователя
cursor.execute("INSERT INTO users (name) VALUES (?)", ("Алиса",))
conn.commit() # Сохраняем изменения
conn.close()
Получение данных из базы.
conn = sqlite3.connect("example.db")
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
users = cursor.fetchall() # Получаем все записи
for user in users:
print(user)
conn.close()Изменение существующей записи.
conn = sqlite3.connect("example.db")
cursor = conn.cursor()
cursor.execute("UPDATE users SET name = ? WHERE id = ?", ("Боб", 1))
conn.commit()
conn.close()Удаление записи из базы.
conn = sqlite3.connect("example.db")
cursor = conn.cursor()
cursor.execute("DELETE FROM users WHERE id = ?", (1,))
conn.commit()
conn.close()Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Защищает Django-приложения от поддельных запросов. Алгоритм работы:
1. При загрузке формы сервер вставляет CSRF-токен в скрытое поле
2. При отправке запроса клиент должен отправить этот токен в заголовке
3. Django сверяет токен с тем, что хранится в сессии пользователя
4. Если токены не совпадают, запрос отклоняется
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2
Это неупорядоченная коллекция уникальных элементов в Python. Это одна из встроенных структур данных языка, которая используется, когда вам нужно работать с наборами данных, исключая дубликаты и выполняя операции над множествами (например, пересечение, объединение и разность).
Элементы множества не имеют фиксированного порядка, то есть вы не можете обращаться к элементам по индексу, как в списках или кортежах.
Во множестве не может быть дубликатов. Если вы добавите во множество несколько одинаковых элементов, они будут храниться как один экземпляр.
Множества в Python изменяемы: вы можете добавлять, удалять и изменять их элементы. Однако сами элементы множества должны быть неизменяемыми (например, числа, строки, кортежи).
Операции проверки принадлежности (
in), добавления и удаления элементов работают очень быстро, благодаря использованию хэш-таблиц в реализации множества.Для создания пустого множества используется функция
set(), так как {} создаёт пустой словарьempty_set = set()
print(empty_set) # Output: set()
Вы можете передать список, строку, кортеж или другой итерируемый объект в функцию
set(). # Создание множества из списка
numbers = set([1, 2, 3, 4, 5])
print(numbers) # Output: {1, 2, 3, 4, 5}
# Создание множества из строки (уникальные символы)
chars = set("hello")
print(chars) # Output: {'h', 'e', 'l', 'o'} (порядок может быть разным)
Вы также можете использовать фигурные скобки
{} для создания множестваfruits = {"apple", "banana", "cherry"}
print(fruits) # Output: {'apple', 'banana', 'cherry'}Используется метод
add()my_set = {1, 2, 3}
my_set.add(4)
print(my_set) # Output: {1, 2, 3, 4}remove() — удаляет элемент, выбрасывая ошибку, если его нет.discard() — удаляет элемент, не выбрасывая ошибку, если его нет.my_set = {1, 2, 3}
my_set.remove(2) # Удаляем элемент 2
print(my_set) # Output: {1, 3}
my_set.discard(5) # Ошибки не будет, если элемента 5 нетpop() — удаляет и возвращает случайный элемент (так как множество неупорядочено)my_set = {1, 2, 3}
removed_element = my_set.pop()
print(removed_element) # Например: 1
print(my_set) # Например: {2, 3}my_set = {1, 2, 3}
my_set.clear()
print(my_set) # Output: set()Используется оператор
inmy_set = {1, 2, 3}
print(2 in my_set) # Output: True
print(5 in my_set) # Output: FalsePython поддерживает классические операции теории множеств:
Возвращает множество, содержащее все элементы из двух множеств.
set1 = {1, 2, 3}
set2 = {3, 4, 5}
print(set1 | set2) # Output: {1, 2, 3, 4, 5}
print(set1.union(set2)) # То же самоеВозвращает элементы, которые присутствуют в обоих множествах.
print(set1 & set2) # Output: {3}
print(set1.intersection(set2)) # То же самоеВозвращает элементы, которые присутствуют только в одном множестве (а не в другом).
print(set1 - set2) # Output: {1, 2} (только в set1)
print(set1.difference(set2)) # То же самоеВозвращает элементы, которые есть в одном из множеств, но не в обоих сразу.
print(set1 ^ set2) # Output: {1, 2, 4, 5}
print(set1.symmetric_difference(set2)) # То же самоеЕсли вам нужно создать множество, которое нельзя изменить, используйте
frozensetfrozen = frozenset([1, 2, 3])
print(frozen) # Output: frozenset({1, 2, 3})
# frozen.add(4) # Ошибка: 'frozenset' object has no attribute 'add'
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
- Асинхронность не использует дополнительные потоки, работает в одном, переключаясь между задачами;
- Многопоточность использует несколько потоков ОС, где каждый может работать независимо; Асинхронность экономичнее по ресурсам, но подходит только для неблокирующих I/O-задач.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍1💊1
Это такие типы данных, которые имеют постоянное (неизменяемое) хеш-значение на протяжении всего времени их существования. Это означает, что их можно использовать в качестве ключей в словарях (
dict) и элементов в множествах (set), так как они поддерживают вычисление хеша с помощью функции hash().если объект можно изменить после создания, его хеш тоже изменится, что нарушает работу структур данных (словари, множества).
который возвращает уникальный идентификатор объекта.
Числа (
int, float, complex)print(hash(42)) # 42
print(hash(3.14)) # 322818021289917443
print(hash(1 + 2j)) # 8389048192121911274
Строки (
str)print(hash("hello")) # Например, 5320385861927423548Кортежи (
tuple), если все их элементы тоже хешируемые:print(hash((1, 2, 3))) # 529344067295497451
Булевы значения (
bool):print(hash(True)) # 1
print(hash(False)) # 0
Списки (
list)hash([1, 2, 3]) # TypeError: unhashable type: 'list'
Множества (
set)hash({1, 2, 3}) # TypeError: unhashable type: 'set'Словари (
dict)hash({"a": 1}) # TypeError: unhashable type: 'dict'Хешируемые типы используются в словари (
dict) и множества (set), так как они используют хеш-функцию для быстрого поиска данных.my_dict = { (1, 2, 3): "tuple_key" } # Работает, потому что кортеж неизменяемый
my_set = { 42, "hello", (1, 2) } # Все элементы хешируемыеСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Это способ быстро создать словарь из другого итерируемого объекта, задав, как именно формируются ключи и значения. Такой подход делает код компактным и читаемым, особенно когда нужно создать словарь на основе списка или другого словаря.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
В программировании многопоточность и многопроцессорность помогают выполнять задачи параллельно, но работают по-разному.
Многопоточность позволяет одной программе запускать несколько потоков (threads), которые работают одновременно.
import threading
import time
def task(name):
print(f"{name} начал работу")
time.sleep(2)
print(f"{name} завершил работу")
# Создаём два потока
t1 = threading.Thread(target=task, args=("Поток 1",))
t2 = threading.Thread(target=task, args=("Поток 2",))
t1.start()
t2.start()
t1.join()
t2.join()
print("Все потоки завершены")
Вывод
Поток 1 начал работу
Поток 2 начал работу
Поток 1 завершил работу
Поток 2 завершил работу
Все потоки завершены
Многопроцессорность запускает отдельные процессы, которые работают полностью независимо и могут использовать разные ядра процессора.
import multiprocessing
import time
def task(name):
print(f"{name} начал работу")
time.sleep(2)
print(f"{name} завершил работу")
if __name__ == "__main__":
p1 = multiprocessing.Process(target=task, args=("Процесс 1",))
p2 = multiprocessing.Process(target=task, args=("Процесс 2",))
p1.start()
p2.start()
p1.join()
p2.join()
print("Все процессы завершены")
Вывод (процессы действительно работают параллельно)
Процесс 1 начал работу
Процесс 2 начал работу
Процесс 1 завершил работу
Процесс 2 завершил работу
Все процессы завершены
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Параметр start=1 задаёт, с какого номера начинать (по умолчанию с 0). Это удобно, если нужен "человеческий" ID
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1💊1
Рекурсия — это мощный инструмент, но в Python она имеет ограничения, которые нужно учитывать при написании кода.
В 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)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
1. В многослойной архитектуре это уровень service или domain.
2. Хранение логики в контроллерах или представлениях считается плохой практикой.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2
Параллелизм — это способ выполнения программ, при котором несколько задач выполняются одновременно (реально параллельно). Он используется для ускорения работы программ, особенно на многоядерных процессорах.
Пример без параллелизма (последовательное выполнение)
Допустим, у нас есть две задачи:
1. Скачать файл (3 секунды).
2. Обработать данные (2 секунды).
Если выполнять их последовательно
[1] Скачать файл... (3 сек)
[2] Обработать файл... (2 сек)
[Готово за 5 секунд]
Пример с параллелизмом (оба процесса выполняются одновременно)
Если у нас 2 ядра процессора, можно выполнить задачи одновременно.
[1] Скачать файл... (3 сек) ──► Готово!
[2] Обработать файл... (2 сек) ──► Готово!
[Готово за 3 секунды] ✅ Быстрее!
В Python
multiprocessing создаёт отдельные процессы, которые работают на разных ядрах.import multiprocessing
import time
def task(name):
print(f"Начал {name}")
time.sleep(2)
print(f"Закончил {name}")
if __name__ == "__main__":
p1 = multiprocessing.Process(target=task, args=("Процесс 1",))
p2 = multiprocessing.Process(target=task, args=("Процесс 2",))
p1.start()
p2.start()
p1.join()
p2.join()
print("Все процессы завершены")
Python не может выполнять потоки параллельно из-за GIL, но
threading всё же полезен для задач ввода-вывода.import threading
import time
def task(name):
print(f"Начал {name}")
time.sleep(2)
print(f"Закончил {name}")
t1 = threading.Thread(target=task, args=("Поток 1",))
t2 = threading.Thread(target=task, args=("Поток 2",))
t1.start()
t2.start()
t1.join()
t2.join()
print("Все потоки завершены")
Асинхронность позволяет не ждать выполнения операции, а переключаться на другие задачи.
import asyncio
async def task(name):
print(f"Начал {name}")
await asyncio.sleep(2) # НЕ блокирует другие задачи
print(f"Закончил {name}")
async def main():
await asyncio.gather(task("Задача 1"), task("Задача 2"))
asyncio.run(main())
Процессор выполняет несколько инструкций одновременно. Например, в современных процессорах есть конвейер (pipeline), который выполняет несколько операций параллельно.
Одна операция применяется к разным данным одновременно (используется в нейросетях, GPU).
import numpy as np
arr = np.array([1, 2, 3, 4])
result = arr * 2 # Все элементы умножаются одновременно (векторизация)
print(result) # [2 4 6 8]
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💊2
Алгоритм Фейнмана — это метод обучения, который заключается в следующем:
1. Изучи концепт так, чтобы мог объяснить его простыми словами.
2. Найди, что непонятно, и углубись в эти части.
3. Перепиши и уточни объяснение, используя аналогии. Это способ глубокого понимания за счёт упрощения и переобъяснения.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊8🔥5