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

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

کانال بسته

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

نمایش بیشتر
5 852
مشترکین
اطلاعاتی وجود ندارد24 ساعت
-77 روز
+27930 روز

در حال بارگیری داده...

کانال‌های مشابه
هیچ داده‌ای
مشکلی وجود دارد؟ لطفاً صفحه را تازه کنید یا با مدیر پشتیبانی ما تماس بگیرید.
اشارات ورودی و خروجی
---
---
---
---
---
---
جذب مشترکین
سپتامبر '26
سپتامبر '26
+121
در 4 کانال‌ها
اوت '26
+380
در 75 کانال‌ها
Get PRO
ژوئیه '26
+85
در 17 کانال‌ها
Get PRO
ژوئن '26
+59
در 10 کانال‌ها
Get PRO
مه '26
+80
در 25 کانال‌ها
Get PRO
آوریل '26
+240
در 40 کانال‌ها
Get PRO
مارس '26
+352
در 85 کانال‌ها
Get PRO
فوریه '26
+120
در 7 کانال‌ها
Get PRO
ژانویه '26
+273
در 15 کانال‌ها
Get PRO
دسامبر '25
+186
در 52 کانال‌ها
Get PRO
نوامبر '25
+488
در 84 کانال‌ها
Get PRO
اکتبر '25
+43
در 16 کانال‌ها
Get PRO
سپتامبر '25
+62
در 1 کانال‌ها
Get PRO
اوت '25
+649
در 34 کانال‌ها
Get PRO
ژوئیه '25
+172
در 43 کانال‌ها
Get PRO
ژوئن '25
+306
در 26 کانال‌ها
Get PRO
مه '25
+75
در 4 کانال‌ها
Get PRO
آوریل '25
+80
در 1 کانال‌ها
Get PRO
مارس '25
+176
در 17 کانال‌ها
Get PRO
فوریه '25
+375
در 30 کانال‌ها
Get PRO
ژانویه '25
+326
در 18 کانال‌ها
Get PRO
دسامبر '24
+656
در 26 کانال‌ها
Get PRO
نوامبر '24
+350
در 14 کانال‌ها
Get PRO
اکتبر '24
+904
در 42 کانال‌ها
Get PRO
سپتامبر '24
+167
در 18 کانال‌ها
Get PRO
اوت '24
+153
در 3 کانال‌ها
Get PRO
ژوئیه '24
+611
در 18 کانال‌ها
Get PRO
ژوئن '24
+451
در 10 کانال‌ها
Get PRO
مه '24
+1 207
در 32 کانال‌ها
Get PRO
آوریل '24
+315
در 9 کانال‌ها
Get PRO
مارس '24
+101
در 4 کانال‌ها
Get PRO
فوریه '24
+180
در 12 کانال‌ها
Get PRO
ژانویه '24
+413
در 20 کانال‌ها
Get PRO
دسامبر '23
+30
در 4 کانال‌ها
Get PRO
نوامبر '23
+250
در 9 کانال‌ها
تاریخ
رشد مشترکین
اشارات
کانال‌ها
15 سپتامبر+3
14 سپتامبر0
13 سپتامبر+14
12 سپتامبر+2
11 سپتامبر0
10 سپتامبر+1
09 سپتامبر+6
08 سپتامبر0
07 سپتامبر+2
06 سپتامبر+73
05 سپتامبر0
04 سپتامبر0
03 سپتامبر0
02 سپتامبر+18
01 سپتامبر+2
پست‌های کانال
⚙️ Библиотека Python: Dynaconf Dynaconf — это гибкая библиотека для управления настройками приложения. Она поддерживает множе
⚙️ Библиотека Python: Dynaconf Dynaconf — это гибкая библиотека для управления настройками приложения. Она поддерживает множество форматов (.toml, .yaml, .json, .ini, .env), автоматически подхватывает переменные окружения и позволяет легко переключаться между средами (development, production). Вдохновлена принципами 12-factor приложений и избавляет от хаоса с конфигами. ✔️ Установка:
pip install dynaconf
🐱 Ссылка на репозиторий Программистика|| #Library

2
Программистика
Программистика
451
3
👩‍💻 9 ошибок, которые выдают Junior Backend разработчика Джуниор — это не тот, кто мало знает, а тот, кто ещё не научился д
👩‍💻 9 ошибок, которые выдают Junior Backend разработчика Джуниор — это не тот, кто мало знает, а тот, кто ещё не научился думать как инженер. Ошибки в коде — это полбеды. Ошибки в подходе к работе — вот что действительно выдаёт новичка. Разбираем 9 классических промахов, которые мешают джунам расти и проходить собеседования. 📱 Первоисточник Программистика|| #video
833
4
📁 `__init__.py` — что скрывается за этим файлом и зачем он нужен (не только чтобы сделать папку пакетом) Каждый Python-разработчик видел этот файл в папках проектов. Многие думают, что __init__.py — это просто маркер, который говорит Python: «эта папка — пакет». И оставляют его пустым. Но это лишь вершина айсберга. За ним скрывается мощный механизм управления импортами, инициализацией пакетов и даже экспортом API. Разбираемся, что умеет этот маленький файл. 🧱 Что делает `__init__.py` 1. Делает директорию пакетом До Python 3.3 __init__.py был обязателен для того, чтобы Python воспринимал папку как пакет. Сейчас это не строго обязательно (работают namespace-пакеты), но оставлять файл всё равно хорошая практика: он явно показывает, что папка — часть проекта. 2. Выполняется при первом импорте пакета Когда вы пишете import mypackage, Python сначала выполняет код из mypackage/__init__.py. Это даёт возможность выполнить инициализацию: настроить логирование, загрузить конфиги, установить соединение с БД — всё, что нужно сделать до работы с модулями пакета. 3. Формирует публичный интерфейс пакета Через __init__.py можно определить, какие объекты будут доступны при импорте пакета. Это позволяет скрыть внутреннюю структуру и предоставить пользователю удобный API. 📦 Что можно писать внутри `__init__.py` 1. Импорты подмодулей для удобного доступа Вместо того чтобы писать: ```python from mypackage.module import MyClass from mypackage.submodule import helper ``` Вы можете сделать в __init__.py: ```python from .module import MyClass from .submodule import helper ``` И тогда пользователь сможет писать: ```python from mypackage import MyClass, helper ``` Это делает код чище и скрывает внутреннюю структуру пакета. 2. `__all__` для явного экспорта Если вы используете from mypackage import *, Python ищет список __all__ в __init__.py. Определив его, вы контролируете, что попадёт в глобальное пространство имён при таком импорте. ```python all = ['MyClass', 'helper'] ``` Без __all__ import * импортирует всё, что не начинается с подчёркивания, что может быть нежелательно. 3. Инициализация пакета Код, который нужно выполнить один раз при первом импорте: ```python import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(name) ``` Это удобно для настройки логирования, загрузки конфигурации или проверки окружения. 4. Версионирование Вы можете определить __version__ в __init__.py, чтобы версия пакета была доступна как атрибут. ```python version = "1.0.0" ``` Тогда пользователь сможет проверить версию через mypackage.__version__. 5. Управление подпакетами Можно динамически импортировать подпакеты или модули в зависимости от условий (платформа, переменные окружения). 🧪 Пример: организация пакета для работы с API Допустим, у вас есть пакет api_client со структурой: api_client/ ├── __init__.py ├── client.py ├── auth.py ├── models.py └── utils.py В __init__.py вы можете сделать: from .client import APIClient from .auth import authenticate from .models import User, Product from .utils import validate_response __all__ = ['APIClient', 'authenticate', 'User', 'Product', 'validate_response'] Тогда внешний код будет использовать пакет так: from api_client import APIClient, authenticate client = APIClient() authenticate(client) Внутренняя структура скрыта, а пользователь получает чистый интерфейс. ⚠️ Ловушки и частые ошибки 1. Слишком много кода в `__init__.py` Всё, что выполняется при импорте, замедляет загрузку пакета. Оставляйте только инициализацию и импорты. Тяжёлые вычисления или загрузку данных выносите в отдельные функции. 2. Циклические импорты Если в __init__.py вы импортируете модули, которые в свою очередь импортируют что-то из __init__.py, может возникнуть циклическая зависимость. Решение — выносить логику в отдельные модули и избегать сложных взаимных импортов. 3. Путаница с относительными импортами Используйте явные относительные импорты (.module, ..subpackage), чтобы избежать конфликтов с глобальными модулями. 4. Игнорирование `__all__` при `import *` Без __all__ import * может принести лишние объекты, включая приватные (_internal). Всегда определяйте __all__, если планируете использовать import *. 5. Создание namespace-пакетов без `__init__.py` Если вы намеренно используете namespace-пакеты (когда один пакет разбит на несколько частей), пропускайте __init__.py. Но если вы не уверены, лучше оставить файл. 💡 Запомни: 🟢 __init__.py — не просто маркер, а точка входа в пакет. 🟢 Используйте его для упрощения импортов через from .module import .... 🟢 Определяйте __all__ для контроля публичного API. 🟢 Выполняйте инициализацию, но не перегружайте файл тяжёлым кодом. 🟢 Версионируйте пакет через __version__. 🟢 Помните про циклические импорты и относительные пути. Понимание устройства __init__.py делает вас не просто пользователем библиотек, а разработчиком, который умеет проектировать свои собственные пакеты чисто и удобно. Программистика|| #Статья
681
5
🧠 Отгадка: что выведет этот код? s1 = "hello" s2 = "hello" s3 = "".join(["h", "e", "l", "l", "o"]) print(s1 is s2, s1 is s3) ✅ Правильный ответ: 2. `True False` 📖 Почему так происходит? - s1 = "hello" и s2 = "hello" — это строковые литералы. Python интернирует короткие строки (состоящие из букв, цифр и подчёркиваний) для экономии памяти. Поэтому обе переменные указывают на один и тот же объект в памяти. s1 is s2 → True. - s3 = "".join(["h", "e", "l", "l", "o"]) — строка создаётся динамически во время выполнения. Даже если содержимое совпадает, интерпретатор не интернирует её автоматически (если только не используется sys.intern()). Поэтому s3 — это новый объект. s1 is s3 → False. Ключевой момент: - is проверяет идентичность объектов (адреса в памяти), а не значения. - Литералы могут быть интернированы, а динамически созданные строки — нет. Ставьте 🔥, если было полезно! Программистика || #quiz
652
6
بدون متن...
691
7
−16% на IT-профессию с ИИ-навыками до 17 сентября Освойте профессию и ИИ-навыки, которые уже требует рынок. Начните бесплатно
−16% на IT-профессию с ИИ-навыками до 17 сентября Освойте профессию и ИИ-навыки, которые уже требует рынок. Начните бесплатно до 17 сентября и учитесь со скидкой. Яндекс Практикум. Учим профессиям и навыкам с ИИ, чтобы вы не застряли в прошлом Узнать больше #реклама 16+ practicum.yandex.ru О рекламодателе
492
8
👨‍💻Гайд «Как стать программистом». А нейронки? А рынок вакансий? А можно еще? Путь в IT в 2026 году — это не просто выучить
👨‍💻Гайд «Как стать программистом». А нейронки? А рынок вакансий? А можно еще? Путь в IT в 2026 году — это не просто выучить Python и пойти на собеседование. Рынок изменился: нейросети пишут код, джунов стало больше, а требования — выше. Как не потеряться и построить карьеру сейчас — в новом большом гайде. Программистика|| #video
790
9
🚀 Память в Python: `__slots__`, `weakref` и `gc` — когда экономить, а когда не мешать В Python принято не думать о памяти. Вроде бы есть сборщик мусора, всё автоматически — живи и радуйся. Но когда ваш сервис начинает жрать 8 ГБ на ровном месте, а объекты, которые давно не нужны, почему-то не удаляются, становится не до шуток. Разбираемся с тремя инструментами, которые помогут держать память под контролем: __slots__, weakref и gc. 🧱 Проблема: почему память заканчивается, даже если объекты уже не нужны В Python память освобождается двумя способами: - Подсчёт ссылок — удаляет объект, когда счётчик падает до нуля. Работает мгновенно. - Циклический сборщик мусора (GC) — периодически ищет группы объектов, которые ссылаются друг на друга, но никому больше не нужны. Но есть ситуации, когда память всё равно утекает: - Вы храните объекты в глобальных списках или кэшах. - Циклические ссылки не дают объектам удалиться. - Вы создаёте миллионы объектов с __dict__, и память раздувается. - Слабые ссылки не используются, хотя могли бы спасти. 📦 `__slots__` — когда миллионы объектов, а памяти жалко По умолчанию каждый экземпляр класса содержит __dict__ — словарь для хранения атрибутов. Это удобно, но дорого: словарь занимает ~56 байт плюс сами атрибуты. Для 1 млн объектов разница — сотни мегабайт. __slots__ отключает __dict__ и заменяет его на дескрипторы. Объект становится компактнее. class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.z = 3 # ❌ AttributeError Замер памяти: import sys class WithoutSlots: 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 print(sys.getsizeof(WithoutSlots(1, 2))) # ~112 байт print(sys.getsizeof(WithSlots(1, 2))) # ~48 байт 🟢 Когда использовать: - Миллионы объектов с фиксированными атрибутами. - Классы-структуры (точки, векторы, DTO). ❌ Не для 99% проектов — оптимизируйте только по факту. 🔗 `weakref` — ссылки, которые не мешают сборщику Вы когда-нибудь создавали кэш, который должен хранить объекты, но не мешать им удаляться? Или писали Observer, но объекты не удалялись, потому что их держал список наблюдателей? Сильные ссылки держат объекты живыми. weakref — это слабая ссылка, которая не учитывается сборщиком мусора. Если на объект есть только слабые ссылки, он может быть удалён. import weakref class HeavyObject: def __del__(self): print("Объект удалён") obj = HeavyObject() weak = weakref.ref(obj) del obj print(weak()) # None Где пригодится: - Кэши (объекты удаляются, если память нужна). - Наблюдатели (слушатели удаляются, когда на них никто не ссылается). - Обратные ссылки в деревьях. Типы слабых ссылок: - weakref.ref(obj) — базовая. - WeakKeyDictionary — ключи — слабые ссылки. - WeakValueDictionary — значения — слабые ссылки. - WeakSet — множество слабых ссылок. cache = weakref.WeakValueDictionary() obj = HeavyObject() cache['key'] = obj del obj print(cache.get('key')) # None ⚠️ Ограничения: - Не все объекты поддерживают слабые ссылки (числа, строки, кортежи без изменяемых элементов). - При __slots__ нужно добавить '__weakref__'. 🧹 `gc` — ручной контроль над циклическим сборщиком В Python есть автоматический сборщик мусора для циклических ссылок. Обычно он работает незаметно, но иногда нужно вмешаться. import gc # Запустить вручную gc.collect() # Проверить пороги print(gc.get_threshold()) # (700, 10, 10) # Посмотреть объекты в поколениях print(gc.get_count()) Когда может понадобиться: - Много циклических ссылок (графы, деревья с обратными ссылками). - В долгоживущих процессах — периодический gc.collect(). - В тестах — проверить, что объекты удаляются. class Node: def __init__(self): self.parent = None a = Node() b = Node() a.parent = b b.parent = a del a, b gc.collect() # Удалит циклическую ссылку ⚠️ Ловушки и частые ошибки 1. `__slots__` везде — не нужно, усложняет код. 2. Забыть `__weakref__` в `__slots__` — слабые ссылки не работают. 3. Не проверять слабую ссылку на `None` — объект мог быть удалён. 4. Отключать `gc` без необходимости — приводит к утечкам. 5. Игнорировать циклические ссылки — они могут накапливаться. 💡 Запомни: 🟢 __slots__ — экономия памяти для миллионов объектов. 🟢 weakref — ссылки, которые не мешают удалять объекты. 🟢 gc — ручное управление циклическим сборщиком мусора. 🟢 Не оптимизируйте без измерений. 🟢 Используйте tracemalloc и gc.get_objects() для отладки утечек. Программистика || #Статья
827
10
🧠 Загадка на ночь: что выведет этот код? s1 = "hello" s2 = "hello" s3 = "".join(["h", "e", "l", "l", "o"]) print(s1 is s2, s
🧠 Загадка на ночь: что выведет этот код? s1 = "hello" s2 = "hello" s3 = "".join(["h", "e", "l", "l", "o"]) print(s1 is s2, s1 is s3) Варианты: 1. True True 2. True False 3. False True 4. False False Пиши свой вариант в комментарии! Ответ и разбор — через пару часов 🔥 Программистика || #quiz
775
11
Весь Python. Самое актуальное и исчерпывающее руководство Всеобъемлющее современное руководство по программированию на Python
Весь Python. Самое актуальное и исчерпывающее руководство Всеобъемлющее современное руководство по программированию на Python, охватывающее фундаментальные идеи и практические приемы! Вы научитесь писать собственные программы и получите четкое представление о том, куда двигаться дальше и как использовать полученные знания. Изучение Python подкреплено практикой — огромным количеством примеров приложений. К концу книги вы будете готовы применить полученные знания и создать несколько реальных проектов. Вы научитесь эффективно использовать Python в анализе данных, веб-разработке и автоматизации задач. Книга включает описание новейших возможностей, появившихся в версиях Python 3.9–3.12, в том числе главы об аннотациях типов и консольных приложениях, а также примеры, демонстрирующие современные практики веб-разработки на Python. Программистика || #Книги
811
12
3 дня. 60 откликов. 1 оффер. Очень интересный кейс произошёл у команды Софи — ии-ассистента для поиска работы. К ним в поддер
3 дня. 60 откликов. 1 оффер. Очень интересный кейс произошёл у команды Софи — ии-ассистента для поиска работы. К ним в поддержку написала девушка, которая отписалась от продукта ещё месяц назад: «Мне прислали оффер!» Начали разбираться — оказывается, она пользовалась только 3 тестовыми днями. То есть за 3 дня ии-ассистент успел сделать 60 откликов. Потом она отписалась. А уже позже — из этих откликов её позвали на интервью, и одно из них привело к офферу. «Оффер с той вакансии, куда я сама никогда бы не откликнулась» Изначально Аня отменила подписку, так как было дорого. Ребята честно спросили у Ани, считает ли она теперь, что подписка стоит своих денег — и получили утвердительный ответ. В следующий раз доступ в Софи откроется 22 сентября. Если хочешь получить 3 дня бесплатного доступа - подписывайся на этот канал, все анонсы будут там.
449
13
Шпаргалка методы списков в Python Программистика|| #doc
Шпаргалка методы списков в Python Программистика|| #doc
928
14
بدون متن...
1
15
Weekend Offer ML*: быстрый найм в Яндекс Открыли регистрацию на онлайн-мероприятие для ML и DL-специалистов. Мы ищем инженеро
Weekend Offer ML*: быстрый найм в Яндекс Открыли регистрацию на онлайн-мероприятие для ML и DL-специалистов. Мы ищем инженеров с опытом от 2 лет в областях NLP, CV, RecSys и Classic ML. Как всё устроено: ✅ До 4 сентября — регистрация на сайте. ✅ 12 сентября — две технические секции онлайн. ✅ 13 сентября — финальные интервью со знакомством с командами. Ждём вас! Подробности и форма регистрации — на сайте. Зарегистрироваться #реклама 16+ yandex.ru О рекламодателе
473
16
🖥 FastSQLA — это асинхронное расширение для SQLAlchemy версии 2.0 и выше, разработанное для интеграции с FastAPI! Оно предос
🖥 FastSQLA — это асинхронное расширение для SQLAlchemy версии 2.0 и выше, разработанное для интеграции с FastAPI! Оно предоставляет готовые шаблоны, поддержку SQLModel и встроенную пагинацию, упрощая настройку и управление асинхронными соединениями с реляционными базами данных. 🐱 Ссылка на GitHub Программистика|| #Репозиторий
990
17
Программистика
Программистика
1 073
18
🧠 Отгадка: что выведет этот код? a = [1, 2, 3] b = a a = a + [4] print(b) ✅ Правильный ответ: 1. `[1, 2, 3]` 📖 Почему так происходит? В Python оператор + для списков создаёт новый список, а не изменяет существующий. Разберём по шагам: 1. a = [1, 2, 3] — создаётся список, a указывает на него. 2. b = a — b указывает на тот же список. 3. a = a + [4] — выражение a + [4] создаёт новый список [1, 2, 3, 4]. Затем a переназначается на этот новый объект. 4. b всё ещё указывает на старый список [1, 2, 3] и не изменился. Если бы мы написали a += [4] (или a.append(4)), то изменили бы исходный список, и ответ был бы [1, 2, 3, 4]. Но здесь — создание нового объекта, поэтому b остался неизменным. Ключевой момент: + возвращает новый объект, += или append() меняют существующий. Ставьте 🔥, если было полезно! Программистика || #quiz
1 186
19
🧠 Загадка на ночь: что выведет этот код? a = [1, 2, 3] b = a a = a + [4] print(b) Варианты: 1. [1, 2, 3] 2. [1, 2, 3, 4] 3.
🧠 Загадка на ночь: что выведет этот код? a = [1, 2, 3] b = a a = a + [4] print(b) Варианты: 1. [1, 2, 3] 2. [1, 2, 3, 4] 3. [4] 4. Ошибка Пиши свой вариант в комментарии! Ответ и разбор — через пару часов 🔥 Программистика || #quiz
1 125
20
👨‍💻 Работа с памятью в Python: как экономить, не утекать и не ломать голову В Python принято не думать о памяти. Вроде бы есть сборщик мусора, всё автоматически — живи и радуйся. Но когда ваш сервис начинает жрать 8 ГБ на ровном месте, а объекты, которые давно не нужны, почему-то не удаляются, становится не до шуток. Разбираемся с тремя инструментами, которые помогут держать память под контролем: __slots__, weakref и gc. 🧱 Проблема: почему память заканчивается, даже если объектов уже нет В Python память освобождается двумя способами: 1. Подсчёт ссылок (reference counting) — удаляет объект, когда счётчик ссылок падает до нуля. Работает мгновенно. 2. Циклический сборщик мусора (GC) — периодически ищет группы объектов, которые ссылаются друг на друга, но никому больше не нужны. Но есть ситуации, когда память всё равно утекает: 🔴 Вы храните объекты в глобальных списках или кэшах. 🔴 Циклические ссылки не дают объектам удалиться. 🔴 Вы создаёте миллионы объектов с __dict__, и память раздувается. 🔴 Слабые ссылки не используются, хотя могли бы спасти. Разберём три инструмента, которые решают эти проблемы. 📦 1. `__slots__` — экономия памяти для миллионов объектов По умолчанию каждый экземпляр класса в Python содержит __dict__ — словарь для хранения атрибутов. Это удобно, но дорого: словарь занимает ~56 байт плюс сами атрибуты. Для 1 млн объектов разница может составлять сотни мегабайт. __slots__ отключает __dict__ и заменяет его на дескрипторы. Объект становится компактнее (как C-структура). class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.z = 3 # ❌ AttributeError: 'Point' object has no attribute 'z' Замер памяти: import sys class WithoutSlots: 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 obj1 = WithoutSlots(1, 2) obj2 = WithSlots(1, 2) print(sys.getsizeof(obj1)) # ~56 байт + __dict__ (~56) = 112 байт print(sys.getsizeof(obj2)) # 48 байт Когда использовать `__slots__`: 🟢 Миллионы объектов с фиксированным набором атрибутов. 🟢 Классы-структуры (Data Transfer Objects, точки, векторы). ❌ Для 99% проектов — не нужно. Оптимизируйте только по факту. Наследование: class Base: __slots__ = ('id',) class Child(Base): __slots__ = ('name', 'age') # id + name + age def __init__(self, id, name, age): self.id = id self.name = name self.age = age Нюанс: __slots__ не наследуется автоматически. Если дочерний класс не переопределяет __slots__, он получит __dict__ и потеряет экономию. 🔗 2. `weakref` — ссылки, которые не мешают сборщику мусора Вы когда-нибудь создавали кэш, который должен хранить объекты, но не мешать им удаляться? Или писали Observer, но объекты не удалялись, потому что их держал список наблюдателей? Это классическая проблема: сильные ссылки держат объекты живыми. weakref — это слабая ссылка, которая не учитывается сборщиком мусора. Если на объект есть только слабые ссылки, он может быть удалён. import weakref import gc class HeavyObject: def __del__(self): print("Объект удалён") obj = HeavyObject() weak = weakref.ref(obj) print(weak()) # <__main__.HeavyObject object at 0x...> del obj gc.collect() print(weak()) # None Где пригодится: 🟢 Кэши — объекты могут быть удалены, если память нужна. 🟢 Наблюдатели (Observer) — слушатели удаляются, когда на них больше никто не ссылается. 🟢 Обратные ссылки в деревьях — родитель держит сильную ссылку на детей, а дети — слабую на родителей. Типы слабых ссылок: 🔴 weakref.ref(obj) — базовая слабая ссылка. 🔴 weakref.WeakKeyDictionary — словарь, где ключи — слабые ссылки. 🔴 weakref.WeakValueDictionary — словарь, где значения — слабые ссылки. 🔴 weakref.WeakSet — множество слабых ссылок. Пример с WeakValueDictionary: import weakref class Cache: def __init__(self): self._data = weakref.WeakValueDictionary() def set(self, key, value): self._data[key] = value def get(self, key): return self._data.get(key) cache = Cache() obj = HeavyObject() cache.set('key', obj) print(cache.get('key')) # <HeavyObject object at ...> del obj print(cache.get('key')) # None Ограничения: 🔴 Не все объекты поддерживают слабые ссылки (числа, строки, кортежи без изменяемых элементов). 🔴 При использовании __slots__ нужно добавить '__weakref__' в слоты. 🔴 Проверяйте результат вызова слабой ссылки на None — объект мог быть удалён. 🧹 3. `gc` — ручное управление циклическим сборщиком мусора В Python есть автоматический сборщик мусора для циклических ссылок. Обычно он работает незаметно, но иногда нужно вмешаться. import gc # Включить/выключить сборку gc.enable() gc.disable() # Запустить вручную gc.collect() # Проверить пороги срабатывания print(gc.get_threshold()) # (700, 10, 10) # Посмотреть количество объектов в поколениях print(gc.get_count()) Когда может понадобиться: 🟢 Вы знаете, что создаётся много циклических ссылок (например, графы, деревья с обратными ссылками). 🟢 В долгоживущих процессах — периодический вызов gc.collect() может помочь. 🟢 В тестах — чтобы проверить, что объекты действительно удаляются. Пример с циклической ссылкой: class Node: def __init__(self): self.parent = None a = Node() b = Node() a.parent = b b.parent = a del a, b # Объекты зависли в циклической ссылке gc.collect() # Удалит их Модуль `gc` для отладки утечек: import gc import tracemalloc # Включить трассировку tracemalloc.start() # Получить список всех объектов objects = gc.get_objects() # Найти объекты определённого типа import pprint pprint.pprint([obj for obj in gc.get_objects() if isinstance(obj, dict)]) ⚠️ Ловушки и частые ошибки 1. Использовать `__slots__` везде — не нужно, усложняет код. 2. Забыть про `__weakref__` в `__slots__` — слабые ссылки не будут работать. 3. Проверять слабые ссылки без `if` — при доступе к удалённому объекту вернётся None. 4. Отключать `gc` без необходимости — приведёт к утечкам. 5. Игнорировать циклические ссылки — в сложных структурах они могут накапливаться. 💡 Запомни: 🟢 __slots__ — экономия памяти для миллионов объектов. 🟢 weakref — ссылки, которые не мешают удалять объекты. 🟢 gc — ручное управление циклическим сборщиком мусора. 🟢 Не оптимизируйте память без измерений. 🟢 Используйте tracemalloc и gc.get_objects() для отладки утечек. Программистика || #Статья
1 002