# Функция, которую будем тестировать
def add(a, b):
return a + b
Теперь напишем модульный тест с использованием стандартного модуля
unittest:import unittest
class TestAddFunction(unittest.TestCase):
def test_add_positive_numbers(self):
self.assertEqual(add(2, 3), 5)
def test_add_negative_numbers(self):
self.assertEqual(add(-1, -2), -3)
def test_add_zero(self):
self.assertEqual(add(0, 5), 5)
if __name__ == '__main__':
unittest.main()
- Находят ошибки в логике функции.
- Упрощают рефакторинг (можно смело менять код — тесты покажут, что сломалось).
- Помогают при разработке: можно быстро проверить, работает ли новый код.
- Улучшают структуру кода — приходится писать функции так, чтобы их легко тестировать.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍3🔥3
__new__ вызывается автоматически при вызове имени класса (при создании экземпляра), тогда как init вызывается каждый раз, когда экземпляр класса возвращается __new__, передавая возвращаемый экземпляр в __init__ в качестве параметра self, поэтому даже если вы сохранили экземпляр где-нибудь глобально/статически и возвращали его каждый раз из __new__, для него все-равно будет каждый раз вызываться __init__.Пример:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
print("Создание объекта")
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
print("Инициализация объекта")
a = Singleton()
b = Singleton()
Создание объекта
Инициализация объекта
Инициализация объекта
__new__ сработал один раз — объект создан.__init__ вызвался дважды — каждый раз при создании экземпляра.Please open Telegram to view this post
VIEW IN TELEGRAM
❤9🔥3👾3
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self, engine: Engine):
self.engine = engine
def run(self):
self.engine.start()
engine = Engine()
car = Car(engine) # <-- внедрили зависимость
car.run()
В Python DI часто реализуется через:
1. Конструктор (constructor injection):
class Service:
def __init__(self, db_client):
self.db = db_client
2. Setter-инъекция (через метод):
class Service:
def set_db(self, db_client):
self.db = db_client
3. Передача через параметры функции:
def handler(service: Service):
return service.do_stuff()
- Легко тестировать (можно подменить зависимости моками)
- Повышает гибкость (меняем реализацию зависимости)
- Разделяет ответственность (класс делает только то, что должен)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍4🔥2
Что выдаст код выше❔
Anonymous Quiz
11%
True True
39%
True False
36%
False False
9%
False True
1%
None
3%
Error
🔥6👏2🤔2💯1👀1
str.isupper() -> bool
Возвращает флаг, указывающий не то, содержит ли строка символы только верхнего регистра.
Аналогично с islower, только для нижнего регистра.
Метод upper() возращает копию строки, в которой все буквы сконвертированы к большому регистру (заглавные буквы). Все остальные символы остаются неизмененными.
Аналогично с lower(), только к нижнему регистру.
В итоге получаем False == False, THIS IS NOW! == this is now! —> True, False
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3👾3⚡1
log_min_duration_statement в конфигурации. Это позволит записывать все запросы, выполняющиеся дольше указанного времени.EXPLAIN или EXPLAIN ANALYZE для просмотра плана выполнения запроса и оценки, где возникают задержки.pg_stat_statements, которое собирает информацию о времени выполнения и частоте запросов.Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3🔥3
[async] with <функция> as <переменная>:
# до и после гарантированно срабатывают события входа в блок with и выхода из него.
__exit__ срабатывает в момент выхода из блока, в том числе по причине возникновения исключения. В этом случае в метод будут переданы exc_class, exc_instance и traceback.with open('file.txt') as f:
data = f.read()
process_data(data)Файл гарантированно закроется.
class Printable:
def __enter__(self):
print('enter')
def __exit__(self, type, value, traceback):
print('exit')
from contextlib import contextmanager
@contextmanager
def printable():
print('enter')
try:
yield
finally:
print('exit')
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3🥰2🔥1🤔1
- Полнотекстовый поиск: Elasticsearch предоставляет мощные инструменты для полнотекстового поиска, что позволяет быстро находить данные в больших объемах текста.
- Агрегация данных: Elasticsearch позволяет агрегировать данные, что полезно для аналитики и создания дашбордов.
- Машинное обучение: Elasticsearch поддерживает машинное обучение, что позволяет автоматически обнаруживать аномалии и тенденции в данных.
- Распределенная архитектура: Elasticsearch является распределенной системой, что позволяет масштабировать поиск и анализ данных.
from elasticsearch import Elasticsearch
# Создание клиента Elasticsearch
es = Elasticsearch()
# Создание индекса
index_name = 'my_index'
es.indices.create(index=index_name)
# Агрегация данных
res = es.search(index=index_name, body={
'aggs': {
'author_count': {
'terms': {'field': 'author.keyword'}
}
}
})
print(res['aggregations'])
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3⚡2🔥1
Если операция случайно выполнится несколько раз (например, из-за сбоя в сети), идемпотентность гарантирует, что это не повлияет на итоговое состояние.
Позволяет избежать непреднамеренного добавления данных или повторного применения изменений.
Работа с HTTP:
1. GET — идемпотентен
GET /users/1
2. PUT — идемпотентен
PUT /users/1
{
"name": "Alice"
}
3. POST — не идемпотентен
POST /users
{
"name": "Alice"
}
Идемпотентный:
DELETE FROM users WHERE id = 5;
Не идемпотентный:
INSERT INTO users (name) VALUES ('Alice');Идемпотентность = безопасное повторное выполнение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3⚡3🔥2
- Сильные ссылки в замыканиях или глобальных структурах.
- Циклические ссылки (например, два объекта ссылаются друг на друга).
- Использование списков/словарей как кэшей без ограничения размера.
- Неочищенные обработчики событий, соединения или файлы.
- Использовать weakref для слабых ссылок.
- Очищать ненужные переменные (del, clear()).
- Контролировать размер кэшей.
- Проверять утечки с помощью инструментов вроде objgraph, gc, tracemalloc.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4⚡2🔥2
- Поверхностное копирование создает новый объект и сохраняет ссылки на вложенные объекты. Подходит для копирования объектов с иммутабельными вложенными элементами.
- Глубокое копирование создает полностью независимую копию объекта с вложенными элементами. Полезно при необходимости полностью отделить копию от оригинала.
import copy
original = [1, [2, 3], 4]
shallow_copied = copy.copy(original)
deep_copied = copy.deepcopy(original)
original[1][0] = 'изменено'
print(original) # [1, ['изменено', 3], 4]
print(shallow_copied) # [1, ['изменено', 3], 4] — вложенный список изменился
print(deep_copied) # [1, [2, 3], 4] — сохранено исходное состояние
Зная эту разницу при работе со сложными структурами данных, можно избежать неожиданного поведения. Но не забывайте, что глубокое копирование может быть более ресурсоемким.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍3⚡2🔥1
А ведь он нужен там, где что бы ни случилось — надо прибраться:
1. Закрытие файлов / соединений:
f = open("data.txt")
try:
process(f)
finally:
f.close() # всегда выполнится2. Откат транзакций:
try:
db.begin()
db.do_stuff()
finally:
db.rollback_or_commit()
3. Остановка фоновых задач:
try:
start_worker()
finally:
stop_worker()
Это твоя гарантированная уборка.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11❤4👍4⚡2
import secrets
# Хранение паролей
password_storage = {}
# Функция для создания и хранения хэша пароля
def store_password(username, password):
# Генерация случайного токена
token = secrets.token_hex(16)
password_storage[username] = {'token': token, 'password': password}
# Проверка пароля
def verify_password(username, provided_password):
if username in password_storage:
stored_password = password_storage[username]['password']
# Сравнение паролей с использованием secrets.compare_digest
return secrets.compare_digest(stored_password, provided_password)
return False
# Использование
store_password("user1", "my_secure_password")
# Проверка входящего пароля
if verify_password("user1", "my_secure_password"):
print("Пароль верный!")
else:
print("Неверный пароль.")
- Библиотека
secrets используется для генерации криптографически стойкого токена, который можно хранить, но в этом примере основной акцент сделан на безопасном сравнении паролей.- Функция
compare_digest сравнивает пароли безопасным способом, защищая от тайминговых атак.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍7⚡2🔥2
Во многих языках (
- Читаемость — код без лишних
- Принудительная структурность — нельзя "забыть закрыть скобку".
- Исторический фактор — Гвидо ван Россум вдохновлялся языком ABC.
➡️ Пример кода на Python:
➡️ Тот же код на C:
🐍 Pythoner
C, Java, JavaScript) блоки кода обозначаются {}. В Python же используются отступы. Почему так?- Читаемость — код без лишних
{} и end выглядит чище.- Принудительная структурность — нельзя "забыть закрыть скобку".
- Исторический фактор — Гвидо ван Россум вдохновлялся языком ABC.
for i in range(3):
print(i) # Отступ обязателен
for (int i = 0; i < 3; i++) {
printf("%d\n", i);
}Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤4👍4
🤔6🤷♀5❤2🤨1
sorted("Python") → ['P', 'h', 'n', 'o', 't', 'y'].
[::-1] переворачивает список → ['y', 't', 'o', 'n', 'h', 'P'].
[0] возвращает первый элемент → "y".
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11🔥7👀2👍1
- Подготовка базы данных: Создание таблиц, миграции.
- Инициализация соединений: Подключение к Redis, Kafka.
- Очистка ресурсов: Закрытие соединений, удаление временных файлов.
Декоратор @ asynccontextmanager создает асинхронный контекстный менеджер. Функция lifespan определяет, какой код выполняется до и после запуска приложения.
from contextlib import asynccontextmanager
from fastapi import FastAPI
# (Предположим, у вас есть функции create_db и close_db)
async def create_db():
print("Подключаемся к базе данных...")
# Здесь будет код подключения к БД
await asyncio.sleep(1) # Имитация асинхронной операции
print("База данных подключена!")
async def close_db():
print("Закрываем соединение с базой данных...")
# Здесь будет код закрытия соединения с БД
await asyncio.sleep(1) # Имитация асинхронной операции
print("Соединение с базой данных закрыто!")
@asynccontextmanager
async def lifespan(app: FastAPI):
print("Запуск приложения...")
await create_db()
yield
print("Завершение приложения...")
await close_db()
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def root():
return {"message": "Hello World"}
# Запуск: uvicorn main:app --reload
- При запуске FastAPI (uvicorn main:app --reload) выполнится код до yield (создание таблиц).
- При остановке FastAPI выполнится код после yield (удаление таблиц).
lifespan + @ asynccontextmanager - это чистый и эффективный способ управлять ресурсами вашего FastAPI приложения!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3⚡2🔥1
a = 1000
b = 1000
print(a is b) # False
Даже если
a == b, a is b может вернуть False, потому что это разные объекты. Python кэширует только небольшие числа и короткие строки.if value is "test": # ❌
Правильно:
if value == "test": # ✅
is уместен?Только для сравнения с singleton'ами, такими как:
if x is None:
...
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤4⚡4🔥2