Если ты уже освоил основы Python и хочешь вывести свои навыки на новый уровень, этот лайфхак поможет тебе писать более эффективный, читаемый и профессиональный код. Мы разберём, как комбинировать декораторы, генераторы и контекстные менеджеры для решения сложных задач.
1. Декораторы для кэширования и логирования
Декораторы — это мощный инструмент для модификации функций без изменения их кода. Давай создадим декоратор, который кэширует результаты и логирует время выполнения.
import functools
import time
import logging
logging.basicConfig(level=logging.INFO)
def cache_and_log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Кэширование результата
cache_key = str(args) + str(kwargs)
if not hasattr(wrapper, 'cache'):
wrapper.cache = {}
if cache_key in wrapper.cache:
logging.info(f"Результат для {func.__name__} взят из кэша")
return wrapper.cache[cache_key]
# Логирование времени выполнения
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
logging.info(f"{func.__name__} выполнена за {end_time - start_time:.4f} сек")
wrapper.cache[cache_key] = result
return result
return wrapper
@cache_and_log
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(35)) # Первая попытка
print(fibonacci(35)) # Результат из кэша
Почему это круто?
- Кэш избавляет от повторных вычислений (особенно полезно для рекурсии).
- Логирование помогает отлаживать производительность.
@functools.wraps
сохраняет метаданные функции, что важно для профессионального кода.
2. Генераторы для экономии памяти
Когда работаешь с большими данными, списки могут "съесть" всю оперативку. Генераторы решают эту проблему, выдавая элементы по одному.
def large_data_generator(start, end):
for i in range(start, end):
yield i ** 2 # Генерируем квадраты чисел по одному
# Используем генератор в цикле
for num in large_data_generator(1, 1000000):
if num > 100:
print(f"Первое число > 100: {num}")
break
Лайфхак: Комбинируй генераторы с itertools
для ещё большей гибкости. Например, itertools.islice
позволяет брать только часть данных без загрузки всего в память:
from itertools import islice
first_10 = list(islice(large_data_generator(1, 1000000), 10))
print(first_10)
3. Контекстные менеджеры для управления ресурсами
Контекстные менеджеры (с ключевым словом with
) упрощают работу с файлами, соединениями и другими ресурсами. Создадим свой менеджер для временного изменения настроек.
from contextlib import contextmanager
@contextmanager
def temp_config(config_dict, key, value):
old_value = config_dict.get(key)
config_dict[key] = value
try:
yield
finally:
if old_value is None:
del config_dict[key]
else:
config_dict[key] = old_value
# Пример использования
settings = {"mode": "normal"}
print(f"До: {settings}")
with temp_config(settings, "mode", "debug"):
print(f"Во время: {settings}")
print(f"После: {settings}")
Вывод:
До: {'mode': 'normal'}
Во время: {'mode': 'debug'}
После: {'mode': 'normal'}
Почему это полезно?
- Гарантированно возвращает исходное состояние, даже если внутри блока
with
произойдёт ошибка. - Удобно для тестирования или временных изменений.
4. Комбинируем всё вместе
Теперь объединим эти техники в одном примере — обработка большого лога с кэшированием и временным изменением настроек.
import logging
from contextlib import contextmanager
from itertools import islice
logging.basicConfig(level=logging.INFO)
@contextmanager
def log_level(level):
old_level = logging.getLogger().level
logging.getLogger().setLevel(level)
try:
yield
finally:
logging.getLogger().setLevel(old_level)
def log_generator(file_path):
with open(file_path, 'r') as f:
for line in f:
yield line.strip()
@cache_and_log
def count_errors(log_lines):
return sum(1 for line in log_lines if "ERROR" in line)
# Пример использования
log_file = "sample.log" # Предположим, у нас есть файл логов
with log_level(logging.DEBUG):
logs = log_generator(log_file)
error_count = count_errors(islice(logs, 1000)) # Обрабатываем только первые 1000 строк
print(f"Найдено ошибок: {error_count}")
Что мы получили?
- Генератор читает файл построчно, экономя память.
- Декоратор кэширует результат и логирует время.
- Контекстный менеджер временно меняет уровень логирования.
Заключение
Эти техники — не просто "фишки для резюме". Они реально ускоряют код, упрощают отладку и делают его масштабируемым. Экспериментируй с ними в своих проектах, добавляй свои идеи и делись результатами!
Написать комментарий