uz
Feedback

Firibgarlarga uchmang! Telemetrio bunday kanallarni topadi va belgilaydi 👉 Belgini ko‘rmoqchi bo‘lsangiz, obuna bo‘ling

Программистика

Программистика

Yopiq kanal

Лучший канал про python Ссылка для друга: https://t.me/+Ai6ughKtf5g2ZmFi Купить рекламу: https://telega.in/c/+Ai6ughKtf5g2ZmFi Админ: @JeyRahol По рекламе: @ReivuManager

Ko'proq ko'rsatish
5 791
Obunachilar
-624 soatlar
+157 kun
-4130 kun
Postlar arxiv
👩‍💻 Я заменил Python на PyPy и получил +400% скорости — не меняя код!
🎥 Первоисточник
Программистика|| #video

СРОЧНЫЙ ИНСАЙД❗️ Российский кодер в третий раз обошёл защиту ChatGPT Айтишник за пару часов нашёл промт, который обходит филь
СРОЧНЫЙ ИНСАЙД❗️
Российский кодер в третий раз обошёл защиту ChatGPT
Айтишник за пару часов нашёл промт, который обходит фильтры, а OpenAI спешно закрывает дыру. 😡 На канале «Мама, я в IT!» сливает свежие промты: –> Бесплатный доступ к Veo 3 и видео-генераторам –> 18+ фото без цензуры в Midjourney –> Разблокировка Gemini, GPT и Perplexity за 0₽ Сохрани, пока не заблокировали: https://t.me/+WHOPn_pf4JVlNWYy

🔧 Pre-commit: Автоматическая проверка кода перед каждым коммитом Забываешь запускать линтеры перед коммитом? Получаешь замечания на CI за кривое форматирование? Тратишь время на правки в пул-реквестах из-за опечаток? Пора автоматизировать контроль качества до того, как код попадёт в репозиторий. Pre-commit — это фреймворк для управления git-хуками. Он запускает указанные проверки перед каждым коммитом и не даёт сделать коммит, если что-то пошло не так. ❌ Было (ручная боль):
# Делаешь коммит, пушишь, создаёшь PR...
git commit -m "fix: баг"
git push origin feature

# А через 10 минут CI падает с ошибкой:
# "black: файл не отформатирован"
# "ruff: неиспользуемый импорт"
# "mypy: несоответствие типов"

# Приходится править, делать новый коммит, ждать снова...
✔️ Стало (автоматический контроль):
# Пытаешься сделать коммит
git commit -m "fix: баг"

# Pre-commit автоматически запускает:
# - black → форматирует код
# - ruff → проверяет ошибки
# - mypy → проверяет типы

# Если что-то не так — коммит отклоняется с описанием проблемы.
# Если всё ок — коммит проходит.

# В CI теперь только критичные проверки, код уже чистый.
📌 Как это работает: Pre-commit использует конфигурационный файл .pre-commit-config.yaml, в котором перечисляются все хуки (проверки). Хуки запускаются в изолированном окружении, поэтому не засоряют ваш проект. Пример конфига для Python-проекта:
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files

  - repo: https://github.com/psf/black
    rev: 23.12.1
    hooks:
      - id: black

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.1.11
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.8.0
    hooks:
      - id: mypy
        additional_dependencies: [types-requests]
➕ Преимущества, которые оценит каждый: 🟢 Автоматизация: Забудь о ручном запуске линтеров — они сами срабатывают при коммите 🟢 Скорость: Хуки кэшируют окружения, повторные запуски быстрые 🟢 Гибкость: Можно подключать любые инструменты (black, ruff, mypy, isort, даже свои скрипты) 🟢 Командная работа: Единый стандарт для всех разработчиков — конфликт "а у меня работает" исчезает 🟢 Интеграция с CI: В CI можно запускать только pre-commit run --all-files, что гарантирует идентичность проверок ➖ Особенности: 🔴 Нужно учить новый инструмент: Поначалу конфиг кажется сложным 🔴 Может тормозить первый запуск: Хуки скачиваются и устанавливаются 🔴 Не все хуки идеальны: Иногда приходится подбирать версии 🛠 Установка и первый запуск:
# Установка через pip
pip install pre-commit

# Или через brew (macOS)
brew install pre-commit

# В корне проекта создаём конфиг (пример выше)
# Устанавливаем хуки в git
pre-commit install

# Теперь хуки будут запускаться при каждом git commit
Проверить все файлы вручную:
pre-commit run --all-files
Один раз настроил — и забыл. А код сам становится лучше. 🐱 Ссылка на репозиторий Программистика ||#Library

⚡️Слита База из 1000+ топовых курсов и материалов для айтишников Отсортировали их для вашего удобства и выложили в телеграм-каналы по категориям: 🖥 Python — 1558+ материалов 👩‍💻 Frontend — 1241+ материалов 👩‍💻 Backend — 1095+ материалов 🤖 Нейросети – 855+ материалов ⚙️ Программы — 978+ материалов 📚 Книги по IT — 779+ материалов Всё лучшее про IT бесплатно — уже на Базе 🚀

😒 Подборка каналов по информационной безопасности Проверенные каналы по безопасности, которые реально помогают расти. 👍 Zer
😒 Подборка каналов по информационной безопасности Проверенные каналы по безопасности, которые реально помогают расти. 👍 ZeroDay — Уроки, эксплуатация уязвимостей с нуля 👍 Белый Хакер — Свежие новости из мира ИБ 😎 Бункер Хакера — Статьи, книги, шпаргалки и хакинг 👨‍💻 Серверная Админа — Настройка и уроки по компьютерным сетям 📂 Подписывайся

👩‍💻 Планировщик задач внутри Python-процесса: пишем персонального ассистента В повседневной рутине разработчика легко забыт
👩‍💻 Планировщик задач внутри Python-процесса: пишем персонального ассистента В повседневной рутине разработчика легко забыть о дейли-митинге, вовремя запустить бэкап или просто переключить контекст. Полагаться на память ненадёжно, а сторонние планировщики часто избыточны или требуют постоянного переключения между окнами. Гораздо элегантнее, когда напоминалки и фоновые задачи живут прямо в коде. В этом туториале автор показывает, как собрать легковесный фоновый сервис на чистом Python. Разбираем связку schedule (для гибкого расписания) и plyer (для нативных системных уведомлений) — и всё это без висящего окна терминала. 🧱 Почему не `time.sleep()`? Наивный подход с бесконечным циклом и sleep() имеет два фатальных недостатка: 🟢 Блокировка потока — пока программа спит, она не реагирует ни на что. 🟢 Временной дрейф — время выполнения кода плюсуется к паузе, и график уплывает. Библиотека schedule решает это элегантно, предоставляя чистый декларативный синтаксис и event loop без блокировки. 🛠 Базовый скелет планировщика
import time
import schedule
from plyer import notification

def send_notification(title, message):
    """Универсальная функция для нативных уведомлений"""
    try:
        notification.notify(
            title=title,
            message=message,
            app_name='Task Manager',
            timeout=10
        )
    except Exception as e:
        print(f"Ошибка уведомления: {e}")

# Задачи
def daily_standup():
    send_notification("Daily Meeting", "Подключайся к Zoom!")

def check_services():
    send_notification("System Monitor", "Локальные сервисы ОК")
    print("[LOG] Проверка выполнена")  # Для отладки

# Расписание
schedule.every().day.at("10:00").do(daily_standup)
schedule.every(2).hours.do(check_services)
schedule.every().friday.at("18:00").do(
    send_notification, 
    title="Конец недели", 
    message="Закоммить изменения и хороших выходных!"
)

# Event loop
if __name__ == "__main__":
    send_notification("Task Manager", "Планировщик запущен")
    while True:
        schedule.run_pending()
        time.sleep(1)  # Разгрузка CPU, а не интервал задач
📌 Важные нюансы из статьи: 1. Plyer — кроссплатформенная обёртка для системных уведомлений (Windows, Linux, macOS). На Linux может потребоваться sudo apt-get install libnotify-bin. 2. Обработка ошибок внутри send_notification критична: если уведомление упадёт, скрипт не должен схлопнуться. 3. Запуск в фоне: - На Windows переименуйте .py → .pyw — тогда скрипт выполнится через pythonw.exe без окна консоли. - Для автозагрузки создайте ярлык на pythonw.exe из виртуального окружения с указанием пути к вашему .pyw. 4. Логирование в stdout (print) оставлено специально — при отладке видно, что процесс жив, а в продакшене (в режиме .pyw) эти выводы просто игнорируются. 👉 Читать полный туториал на Хабре Программистика ||#article

👩‍💻 `__slots__` 🆚 `__dict__`: Когда экономия памяти оправдана, а когда — лишняя сложность Каждый экземпляр класса в Python носит с собой __dict__ — тяжёлый рюкзак для хранения атрибутов. Удобно: можно добавлять поля на лету. Но если у вас миллион объектов, этот рюкзак превращается в контейнер с цементом. __slots__ говорит Python: «Не выделяй словарь, я сам знаю свои атрибуты». Разбираемся, где это реально нужно, а где — преждевременная оптимизация. 🧱 Когда `__slots__` — это хорошо (и значительно ускоряет код): 1️⃣. Миллионы однотипных объектов (датасеты, игровые сущности, логи):
class Point:
    __slots__ = ('x', 'y')
    def __init__(self, x, y):
        self.x = x
        self.y = y

# Без __slots__ каждый Point занимает ~56 байт + __dict__ (56+56=112)
# С __slots__ ~48 байт на объект — экономия 2+ раз!
2️⃣. Иммутабельные структуры, где не нужна динамика:
class Color:
    __slots__ = ('r', 'g', 'b')
    def __init__(self, r, g, b):
        self.r = r
        self.g = g
        self.b = b
    
    def __repr__(self):
        return f"Color({self.r},{self.g},{self.b})"
3️⃣. Классы-обёртки для C-расширений / API:
class DeviceHandle:
    __slots__ = ('_handle', '_closed')
    # Запрещаем добавлять левые атрибуты, которые сломают низкоуровневый вызов
📊 Замер памяти (убедись сам):
import sys
from pympler import asizeof

class WithDict:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class WithSlots:
    __slots__ = ('x', 'y')
    def __init__(self, x, y):
        self.x = x
        self.y = y

d_obj = WithDict(1, 2)
s_obj = WithSlots(1, 2)

print(sys.getsizeof(d_obj))      # 56 (сам объект) + вес __dict__ (~56) ≈ 112
print(sys.getsizeof(s_obj))      # 48 (нет __dict__)

# Более честный замер с pympler:
print(asizeof.asizeof(d_obj))   # ~184 байта (со всеми накладными)
print(asizeof.asizeof(s_obj))   # ~80 байт
🧱 Когда `__slots__` — это ПЛОХО (антипаттерны и подводные камни): 1. Динамическое добавление атрибутов (сломается):
class User:
    __slots__ = ('name', 'email')
    
user = User()
user.age = 25  # ❌ AttributeError: 'User' object has no attribute 'age'
2. Наследование и множественное наследование — требует внимания:
class Base:
    __slots__ = ('id',)

class Child(Base):
    # Если не указать __slots__, у Child появится __dict__!
    pass

child = Child()
child.id = 1
child.extra = 2  # ✅ Работает! __dict__ создан неявно

# Чтобы сохранить экономию, надо явно повторить:
class Child(Base):
    __slots__ = ()  # или добавить свои поля
3. Слабые ссылки (weakref) перестают работать по умолчанию:
class Node:
    __slots__ = ('value',)
    
node = Node()
ref = weakref.ref(node)  # ❌ TypeError: cannot create weak reference to 'Node' object

# Фикс: добавить '__weakref__' в __slots__
class Node:
    __slots__ = ('value', '__weakref__')
4. Код становится менее читаемым для новичков: Команда может не понять, почему нельзя добавить атрибут «на лету» в тестах или прототипах. 🧪 Когда `__slots__` НЕ НУЖНЫ (и даже вредны): 1. Прототипирование и быстрое изменение кода:
# На этапе экспериментов __dict__ — друг, __slots__ — враг
2. Классы с несколькими экземплярами (десятки, сотни): Экономия 100 байт × 100 = 10 КБ — незаметно на фоне остальной памяти. 3. Библиотеки для широкого использования: Вы не знаете, как пользователь захочет расширить ваш класс. __slots__ может заблокировать monkey-patching и тестирование. 4. Если нужна аннотация типов + dataclass: Современные dataclass со slots=True (Python 3.10+) — элегантный компромисс:
from dataclasses import dataclass

@dataclass(slots=True)
class Point:
    x: float
    y: float
    
p = Point(1, 2)
p.z = 3  # ❌ Ошибка, как и с ручными __slots__
🔗 Подробнее в документации Программистика ||#article

В IT хватает тех, кто пересказывает чужие статьи. Но есть те, кто пишет изнутри системы. NeuroNinja 🥷🏻 - авторский канал инженера СберТехнологий, который показывает, что происходит по ту сторону интерфейса. В канале вы найдете: 🟢 Разборы реальных кейсов из практики 🟢 Гайды по нейросетям без воды 🟢 Полезные инструменты и лайфхаки 🟢 Честные мысли о трендах в IT Живые обсуждения для тех, кто не просто читает про ИИ, а строит его будущее🚀. 👉 Подписаться: https://t.me/+p7moTkYaAQo1MTEy

🔐 Шифруем данные в Python: просто о сложном Хранить пароли, ключи, приватные переписки в открытом виде - это дебильно. Давайте научимся защищать данные. Так делать нельзя (шифрование своими руками)
def my_encrypt(text, key):
    result = ""
    for char in text:
        result += chr(ord(char) ^ key)
    return result
Проблема: Самопальное XOR-шифрование - это хрень. Оно легко ломается, нет аутентификации, соли, криптостойкого генератора случайных чисел. ✔️ Правильно (используем проверенные библиотеки)
from cryptography.fernet import Fernet

# Генерируем ключ
key = Fernet.generate_key()
cipher = Fernet(key)

# Шифруем
text = b"My secret message"
encrypted_text = cipher.encrypt(text)
print(encrypted_text)  # b'gAAAAABn...'

# Расшифровываем
decrypted_text = cipher.decrypt(encrypted_text)
print(decrypted_text)  # b'My secret message'
Как это работает: Fernet использует симметричное шифрование (AES) и гарантирует целостность данных (HMAC). Ключ безопасно генерируется. 🔐Шифруем пароли правильно (хэширование)
import bcrypt

password = b"super_secure_pass"

# Создаём соль и хэш
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(password, salt)
print(hashed)  # b'$2b$12$...'

# Проверяем пароль
if bcrypt.checkpw(password, hashed):
    print("Password matches!")
Хэширование - односторонняя улица. Пароль нельзя расшифровать, можно только сведить хэш. Асимметричное шифрование (публичный/приватный ключ)
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes

# Генерация пары ключей
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()

# Шифруем публичным ключом
message = b"Confidential"
ciphertext = public_key.encrypt(
    message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Расшифровываем приватным
plaintext = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)
print(plaintext)  # b'Confidential'
Важно: Не изобретайте велосипед. Используйте cryptography, bcrypt, pycryptodome. Храните ключи в секрете и используйте надёжные алгоритмы. Программистика ||#article

Слили в телеграмм тонны инфы и отсортировали по каналам ☁️ Хакинг & ИБ — 756GB 🤒 OSINT — 315GB 🖥 Курсы & GitHub — 1579GB ⌨️ Python — 955GB 🙃 Linux & Bash — 459GB 😦 Работа в IT — 778GB 🖥 Общий архив — 2346GB ➡️ Практические инструкции, курсы, книги и инструменты.

СИМВОЛ. Квартиры для сдачи в аренду у центра Москвы ДОНСТРОЙ представляет новый инвестиционный продукт: доходный дом в кварта
СИМВОЛ. Квартиры для сдачи в аренду у центра Москвы ДОНСТРОЙ представляет новый инвестиционный продукт: доходный дом в квартале СИМВОЛ у центра Москвы. Это квартиры с отделкой, мебелью, управлением ""под ключ"" и постоянным доходом от сдачи в аренду. - Расположение у ЦАО, в 2 км от Садового кольца, рядом метро - Отельный сервис для арендаторов - Востребованные для аренды планировки: студии, 1- и 2-комнатные квартиры 28-60,8 м2. - Полная комплектация квартир: отделка, мебель, бытовая техника, кондиционеры - Постоянный поток арендаторов – рядом БЦ, вузы, туристические объекты - В квартале 150+ действующих объектов инфраструктуры, собственный парк 10 га Узнать больше #реклама simvol-kvartal.ru О рекламодателе

💻 Вопрос с собеседования: Что такое MRO (Method Resolution Order) в Python и как работает `super()`? Этот вопрос задают, когда хотят понять, насколько глубоко вы разбираетесь в ООП Python. Просто сказать "MRO — это порядок поиска методов" — недостаточно. Нужно объяснить, зачем это нужно и как избегать ловушек наследования. 📌 Базовый ответ (которого ждают от джуна): MRO (Method Resolution Order) — это порядок, в котором Python ищет методы в иерархии классов. super() позволяет вызывать метод родительского класса без явного указания его имени.
class A:
    def hello(self):
        print("A")

class B(A):
    def hello(self):
        super().hello()  # Вызовет A.hello()
        print("B")

obj = B()
obj.hello()
# Вывод:
# A
# B
🧱 Почему MRO важен при множественном наследовании: Без четкого порядка поиска методов возникли бы неоднозначности в "алмазе наследования":
class A:
    def method(self):
        print("A")

class B(A):
    def method(self):
        print("B")

class C(A):
    def method(self):
        print("C")

class D(B, C):
    pass

# В каком порядке искать method()?
# Старый стиль (до Python 2.3): D → B → A → C → A (дублирование A!)
# Новый стиль (C3 linearization): D → B → C → A
MRO по алгоритму C3 гарантирует: 1. Подкласс всегда проверяется раньше родительского 2. Порядок в списке родителей сохраняется 3. Все классы в иерархии уникальны
print(D.__mro__)  
# (<class '__main__.D'>, <class '__main__.B'>, 
#  <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
🧪 Как работает `super()` на самом деле: Важно: super() ищет метод не в "родительском классе", а в следующем классе по MRO.
class A:
    def process(self):
        print("A")

class B(A):
    def process(self):
        print("B - начало")
        super().process()  # Не всегда вызывает A!
        print("B - конец")

class C(A):
    def process(self):
        print("C - начало")
        super().process()
        print("C - конец")

class D(B, C):
    def process(self):
        print("D - начало")
        super().process()
        print("D - конец")

d = D()
d.process()
# Вывод:
# D - начало
# B - начало
# C - начало
# A
# C - конец
# B - конец
# D - конец
Порядок вызовов: D → B → C → A (согласно MRO класса D). ⚠️ Частые ошибки и ловушки: 1. Неправильный порядок родителей:
❌ Опасно:
class A: pass
class B(A): pass
class C(A, B): pass  
# TypeError: Cannot create a consistent method resolution order

✅ Правильно:
class A: pass
class B(A): pass
class C(B, A): pass  # B проверяется раньше A
2. `super()` с аргументами (старый стиль):
# Python 2 стиль (устарел)
class OldStyle:
    def __init__(self):
        super(OldStyle, self).__init__()

# Python 3 стиль
class NewStyle:
    def __init__(self):
        super().__init__()  # Автоматически определяет класс и self
3. Вызов `super()` не в том месте:
class Base:
    def __init__(self):
        self.setup()
    
    def setup(self):
        print("Base setup")

class Derived(Base):
    def __init__(self):
        self.value = 42  # Сначала инициализируем атрибуты
        super().__init__()  # Потом вызываем родителя
    
    def setup(self):
        print(f"Derived setup with value={self.value}")

d = Derived()
# Выведет: Derived setup with value=42
💡 Запомните: понимание MRO и super() критично для работы со сложными иерархиями классов. На собеседовании покажите, что вы понимаете не только синтаксис, но и логику работы Python с наследованием. Программистика || #jobs

🤔 ХОЧЕШЬ ДЕЛАТЬ ИГРЫ, НО НЕ ЗНАЕШЬ, С ЧЕГО НАЧАТЬ? Меня зовут Антон. Я 8 лет работал в найме в игровой индустрии - и в какой
🤔 ХОЧЕШЬ ДЕЛАТЬ ИГРЫ, НО НЕ ЗНАЕШЬ, С ЧЕГО НАЧАТЬ? Меня зовут Антон. Я 8 лет работал в найме в игровой индустрии - и в какой-то момент поставил всё на разработку собственной игры. Сегодня я делаю игру глазами продюсера и показываю этот путь открыто - без романтизации и иллюзий. ⚡️ В своём блоге я показываю закулисье геймдева: ➕ как на самом деле создаются игры в студиях ➕ как одиночки и маленькие команды доводят проекты до релиза ➕ как выглядит разработка игры с точки зрения продюсера ➕ какие ошибки совершают почти все новички и как их избежать 👉 Заходи в блог и забирай подробную инструкцию, как сделать свою первую игру - от идеи до первых билдов.

📜 Clean Imports: Автоматическая чистка неиспользуемых импортов в один клик Устал вручную удалять неиспользуемые импорты в каждом файле? Видишь from django.db import models, connection, transaction и понимаешь, что половина не нужна? Пора автоматизировать рутину. Этот скрипт найдет и удалит все неиспользуемые импорты в вашем Python-проекте, используя autoflake и isort для чистоты. 👉 Скрипт `clean_imports.py`:
#!/usr/bin/env python3
"""
Автоматическая очистка неиспользуемых импортов в Python-проекте
Использование: python clean_imports.py /путь/к/проекту
"""

import subprocess
import sys
from pathlib import Path

def clean_imports(project_path: str):
    """Рекурсивно очищает неиспользуемые импорты во всех .py файлах"""
    project = Path(project_path)
    
    if not project.exists():
        print(f"❌ Путь не найден: {project_path}")
        return
    
    # Находим все Python-файлы
    py_files = list(project.rglob("*.py"))
    
    print(f"🔍 Найдено {len(py_files)} Python-файлов")
    
    for file in py_files:
        print(f"🔄 Обработка: {file.relative_to(project)}")
        
        # 1. Удаляем неиспользуемые импорты с autoflake
        subprocess.run([
            "autoflake", 
            "--in-place", 
            "--remove-all-unused-imports",
            "--remove-unused-variables",
            str(file)
        ], check=False)
        
        # 2. Сортируем импорты с isort
        subprocess.run([
            "isort",
            str(file)
        ], check=False)
    
    print("✅ Готово! Все неиспользуемые импорты удалены.")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Использование: python clean_imports.py /путь/к/проекту")
        sys.exit(1)
clean_imports(sys.argv[1])
🛠 Как использовать: 1. Установите зависимости:
pip install autoflake isort
2. Создайте файл `clean_imports.py` с кодом выше 3. Запустите на проекте:
python clean_imports.py /путь/к/вашему/проекту
🧪 Пример работы: Было (файл `utils.py` с мусором):
import os
import sys
from typing import List, Dict, Tuple, Optional  # Optional не используется
import json
from datetime import datetime, timedelta  # timedelta не используется

def process_data(data: List[Dict]) -> str:
    """Обрабатывает данные и возвращает JSON строку"""
    return json.dumps(data)
Стало (после работы скрипта):
import json
from datetime import datetime
from typing import Dict, List


def process_data(data: List[Dict]) -> str:
    """Обрабатывает данные и возвращает JSON строку"""
    return json.dumps(data)
➕ Преимущества скрипта: 🟢 Автоматизация рутины: Больше не нужно вручную проверять каждый файл 🟢 Безопасность: Использует проверенные инструменты (autoflake, isort) 🟢 Рекурсивность: Обрабатывает все поддиректории проекта 🟢 Контроль: Видите прогресс и какие файлы обрабатываются ➖ Особенности: 🔴 Требует установки autoflake и isort 🔴 Может сломать код, если есть динамические импорты (но такое редко) 🔴 Всегда делайте коммит перед запуском на важном проекте Скачать скрипт https://gist.github.com/ваш-гист) (замените на реальную ссылку) Программистика|| #script

🤔 Кэширование в Python: От @lru_cache до Redis и обратно Когда приложение начинает тормозить, новички часто лезут в сложные оптимизации, хотя 80% проблем решаются грамотным кэшированием. Но какой инструмент выбрать: встроенный декоратор, внешнюю базу или ручное решение? Разбираемся без фанатизма. 🧱 Когда `@lru_cache` — это достаточно (быстро и просто): Встроенный декоратор @functools.lru_cache идеален для кэширования результатов тяжёлых функций, которые часто вызываются с одними и теми же аргументами. 1️⃣. Рекурсивные вычисления (числа Фибоначчи, факториалы):
from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# Без кэша: O(2^n), с кэшом: O(n)
print(fibonacci(100))  # Мгновенно!
2️⃣. Запросы к внешним API с ограниченным набором параметров:
@lru_cache(maxsize=256)
def get_weather(city, date):
    # Имитация тяжёлого запроса к API погоды
    time.sleep(1)
    return f"Погода в {city} на {date}: 25°C"

# Повторные вызовы с теми же аргументами — мгновенно
print(get_weather("Москва", "2024-01-01"))
print(get_weather("Москва", "2024-01-01"))  # Из кэша!
3️⃣. Сложные вычисления с детерминированным результатом:
@lru_cache(maxsize=None)  # Неограниченный кэш
def calculate_metrics(dataset_hash, params):
    # Тяжёлые вычисления над датасетом
    return processed_result
🧱 Когда `@lru_cache` — это ПЛОХО (опасные ограничения): 1. Функции с изменяемыми (mutable) аргументами:
❌ Опасно и не работает:
@lru_cache
def process_data(data_list):  # data_list — изменяемый список
    return sum(data_list)

process_data([1, 2, 3])
process_data([1, 2, 3, 4])  # Разные вызовы, но кэш может сломаться
2. Когда нужна инвалидация кэша по времени или событиям:
❌ @lru_cache не умеет "протухать":
@lru_cache
def get_live_scores(match_id):
    # Данные живые, обновляются каждую минуту
    # Но кэш будет хранить старый результат вечно!
3. Многопоточность и многопроцессность:
# Кэш в памяти процесса не доступен другим процессам
# При перезапуске приложения кэш теряется
🧱 Когда нужен `Redis` или `Memcached` (распределённое кэширование): 1️⃣. Многопроцессные приложения (Django, FastAPI в production):
# django.core.cache с Redis
from django.core.cache import cache

def get_user_data(user_id):
    data = cache.get(f"user_{user_id}")
    if not data:
        data = expensive_database_query(user_id)
        cache.set(f"user_{user_id}", data, timeout=3600)
    return data
2️⃣. Общий кэш между несколькими сервисами:
# Сервис A и Сервис B используют один Redis
import redis

cache = redis.Redis(host='localhost', port=6379, db=0)

# Сервис A записывает
cache.setex("api_response", 300, json.dumps(data))

# Сервис B читает
data = cache.get("api_response")
3️⃣. Сложная инвалидация и тегирование:
# Кэшируем с тегами, потом инвалидируем по тегу
cache.set("product_123", data, tags=["products", "category_5"])
# При обновлении категории
cache.delete_by_tag("category_5")  # Удалит все связанные кэши
🧱 Когда нужно ручное кэширование (полный контроль): 1. Кэширование с сложной логикой инвалидации:
class SmartCache:
    def __init__(self):
        self._cache = {}
        self._access_count = {}
    
    def get(self, key):
        if key in self._cache:
            self._access_count[key] += 1
            return self._cache[key]
        return None
    
    def set(self, key, value, *, max_accesses=100):
        self._cache[key] = value
        self._access_count[key] = 0
        
        # Автоочистка редко используемых ключей
        if len(self._cache) > 1000:
            self._cleanup(max_accesses)
2. Кэширование с зависимостями между данными:
# При обновлении пользователя нужно обновить все его заказы в кэше
def update_user(user_id, data):
    # Обновляем в БД
    db.update_user(user_id, data)
    
    # Инвалидируем связанные кэши
    cache.delete(f"user_{user_id}")
    cache.delete_by_pattern(f"orders_user_{user_id}_*")
🔗 Подробнее в статье Если хотите больше статьи ставьте 🔥 Программистика|| #doc

Колледж IThub. День Открытых Дверей 15 февраля! ✨9-11 классы — Поступление без экзаменов ✅Гос. диплом ✅Стажировки и трудоустройство ✅Свобода от сессий и отсрочка от армии ✅Отсутствие домашних заданий и 5-балльной системы оценивания Стань IT-профи и получи оффер от крупной компании. Востребованные профессии 2026! Наши выпускники работают в «Газпром», «Крок», «МТС», «Самолет», «Сбер» и др. Зарабатывай первые деньги в IT до 18 лет! Записаться онлайн #реклама 16+ ithub.ru О рекламодателе

Руководство по разработке безопасного программного обеспечения Почти треть российских компаний (28%) не проверяют свое ПО на
Руководство по разработке безопасного программного обеспечения Почти треть российских компаний (28%) не проверяют свое ПО на уязвимости или только планируют внедрить практики безопасной разработки. Это означает, что ошибки в коде, небезопасные конфигурации и уязвимые зависимости нередко остаются незамеченными до самого релиза. Исправление таких проблем после выхода продукта обходится значительно дороже. Кроме того, это несет серьезные репутационные и операционные риски. Чтобы избежать уязвимостей и рисков, связанных с непроверенными зависимостями, принципы DevSecOps нужно закладывать с самого начала — еще до первой строки кода. В статье расскажем, что такое безопасная разработка программного обеспечения, как она устроена и как внедрить подход в реальные процессы команды. ➡️ Читать статью Программистика || #article