fa
Feedback

فریب کلاهبرداران را نخورید! تل‌متریو این کانال‌ها را شناسایی و برچسب‌گذاری می‌کند 👉 برای مشاهده برچسب، اشتراک تهیه کنید

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

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

کانال بسته

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

نمایش بیشتر
5 768
مشترکین
-324 ساعت
-137 روز
-6530 روز

در حال بارگذاری داده‌ها

کانال‌های مشابه
هیچ داده‌ای
مشکلی وجود دارد؟ لطفاً صفحه را تازه کنید یا با مدیر پشتیبانی ما تماس بگیرید.
اشارات ورودی و خروجی
---
---
---
---
---
---
جذب مشترکین
اکتبر '26
اکتبر '26
+64
در 7 کانال‌ها
سپتامبر '26
+174
در 13 کانال‌ها
Get PRO
اوت '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
در 53 کانال‌ها
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 کانال‌ها
تاریخ
رشد مشترکین
اشارات
کانال‌ها
26 اکتبر0
25 اکتبر0
24 اکتبر+2
23 اکتبر0
22 اکتبر0
21 اکتبر0
20 اکتبر+1
19 اکتبر+1
18 اکتبر0
17 اکتبر0
16 اکتبر0
15 اکتبر0
14 اکتبر0
13 اکتبر+1
12 اکتبر+2
11 اکتبر0
10 اکتبر+1
09 اکتبر+3
08 اکتبر+1
07 اکتبر+2
06 اکتبر+7
05 اکتبر+1
04 اکتبر0
03 اکتبر+1
02 اکتبر+3
01 اکتبر+38
پست‌های کانال
🐈 Декораторы в Python Парадокс этого курса в том, что он МАЛЕНЬКИЙ, но при этом позволяет сделать БОЛЬШОЙ шаг в понимании фу
🐈 Декораторы в Python Парадокс этого курса в том, что он МАЛЕНЬКИЙ, но при этом позволяет сделать БОЛЬШОЙ шаг в понимании функциональных возможностей Python и внутренней механики функций.
🌐 Ссылка
Программистика || #Course

2
0️⃣ Секрет `int.bit_count()`: считай единицы в двоичном представлении без циклов В Python 3.10+ появился встроенный метод для подсчёта единичных битов в числе. Больше не нужно писать циклы или использовать bin(x).count('1'). ❌ Было (медленно и некрасиво): x = 42 count = bin(x).count('1') # 3 ✔️ Стало (быстро и чисто): x = 42 count = x.bit_count() # 3 🟢 Почему круто: - Работает на уровне C — быстрее, чем преобразование в строку. - Поддерживает отрицательные числа (возвращает количество единиц в дополнительном коде). - Идеально для битовых масок, криптографии, алгоритмов. Пример с битовой маской: permissions = 0b101101 print(permissions.bit_count()) # 4 — количество включённых флагов Запомни: bit_count() — твой друг, когда работаешь с битами. Программистика|| #tips
421
3
Вся правда о комиссиях — от ИИ на данных FinamTrade ИИ-агенты забираются в банковские процессы — а ваши счета пока разбираются вручную. Считать вручную долго. 💻 Finam MCP передаёт ваши счета, позиции и историю сделок в привычный AI-клиент (ChatGPT, Claude и др.). Дальше вы просто спрашиваете ИИ: динамика портфеля, прибыль и убытки, комиссии, графики — ответ по реальным данным FinamTrade. • Счета, история сделок и заявок — прямо в чате с ИИ • Интерактивные графики, списки наблюдения, заметки • Несколько счетов в одном запросе, работает и с демо • Токен за пару минут в FinamTrade, сервис бесплатный ✅ Дополнительный софт не нужен. Сгенерируйте MCP-токен и задайте ИИ первый вопрос о своих сделках. Информация не является индивидуальной инвестиционной рекомендацией и не гарантирует доходности. Инвестиции связаны с риском. Попробовать Финансовые услуги оказывает: АО «Инвестиционная компания «ФИНАМ». #реклама 16+ broker.finam.ru О рекламодателе
329
4
Что ему написали, что он выдал ТАКОЕ? Иногда смотришь на чужой результат нейросети и не понимаешь: почему у тебя получается п
Что ему написали, что он выдал ТАКОЕ? Иногда смотришь на чужой результат нейросети и не понимаешь: почему у тебя получается поздравление от завуча, а у него — будто работала целая команда? Самое интересное здесь — запрос, который остался за кадром. В «Докторе GPT» разбирают нейросети, делятся готовыми промптами и находками для текстов, картинок и видео. Чтобы было что скопировать, попробовать и оставить себе 👇 https://t.me/+sH14t7NdryRhOGRi
379
5
🕷 Библиотека Python: Scrapling Scrapling — это адаптивный фреймворк для веб-скрапинга, который решает главную боль парсеров:
🕷 Библиотека Python: Scrapling Scrapling — это адаптивный фреймворк для веб-скрапинга, который решает главную боль парсеров: «сайт изменился — код сломался». Вместо жёстких CSS-селекторов он использует умное отслеживание элементов, запоминая их визуальные признаки и контекст. Если вёрстка обновилась, Scrapling автоматически находит нужные данные заново. Плюс в комплекте — обход Cloudflare, поддержка JavaScript-рендеринга, асинхронность и встроенный MCP-сервер для AI-агентов. ✔️ Установка: pip install scrapling Программистика|| #Library
516
6
😎 Глубокое обучение на Python. 2-е международное издание Глубокое обучение динамично развивается, открывая все новые и новые
😎 Глубокое обучение на Python. 2-е международное издание Глубокое обучение динамично развивается, открывая все новые и новые возможности создания ПО. Это не только автоматический перевод текстов с одного языка на другой, распознавание изображений, но и многое другое. Глубокое обучение превратилось в важный навык, необходимый каждому разработчику. Keras и TensorFlow облегчают жизнь разработчикам и позволяют легко работать даже тем, кто не имеет фундаментальных знаний в области математики или науки о данных. Настала пора познакомиться с глубоким обучением и мощной библиотекой Keras! В этом расширенном и дополненном издании создатель библиотеки Keras — Франсуа Шолле — делится знаниями и с новичками, и с опытными специалистами. Иллюстрации и наглядные примеры помогут вам разобраться с самыми сложными вопросами и концепциями. Вы быстро приобретете навыки, необходимые для разработки приложений глубокого обучения. Программистика || #Книги
587
7
Как связаны случайные графы, дата-центры и человек, который просто хотел разобраться, как всё это работает? На самом деле — о+1
Как связаны случайные графы, дата-центры и человек, который просто хотел разобраться, как всё это работает? На самом деле — очень просто. Иногда, чтобы понять, почему современные системы устроены именно так, приходится залезть в математику, теорию графов и архитектуру дата-центров. А потом ещё и объяснить всё это человеческим языком. Именно этим занимается Аня — разработчик в Microsoft — в своём Telegram-канале Baba Нюра’s Wisdom. Здесь разбирают IT без попытки сделать вид, что вы уже знаете все эти страшные слова. Недавно, например, говорили о квазислучайных графах, строили графы своими руками, а потом добрались до того, как устроены сети в дата-центрах. А ещё здесь есть собеседования, карьера в IT, жизнь в США, путешествия, книги и просто истории из жизни разработчика. Если хочется не просто читать про IT, а наконец понять, что там происходит под капотом, — загляните в Baba Нюра’s Wisdom. Реклама. Аникина А.С. ИНН 772796434915. erid: 2W5zFK8npCq
321
8
🧵 `contextvars` — как пробросить данные через весь асинхронный код Вы пишете асинхронный сервис на asyncio. В каждом запросе нужно логировать request_id, передавать текущего пользователя и собирать метрики. Вы начинаете прокидывать эти данные через аргументы всех функций. Через неделю сигнатуры становятся трёхэтажными, а код — нечитаемым. Знакомо? Тогда эта статья для вас. contextvars решает эту проблему элегантно. 🧱 Проблема: `threading.local` не работает в async В синхронном мире для «глобальных в рамках потока» данных используют threading.local. Каждый поток видит свои значения, и они не мешают друг другу. import threading local_data = threading.local() def worker(): local_data.request_id = "abc" print(local_data.request_id) # abc t = threading.Thread(target=worker) t.start() Но в asyncio всё иначе. Корутины выполняются в одном потоке, переключаясь на await. Если использовать threading.local, все корутины будут видеть одни и те же данные, потому что поток один. Начинается хаос: request_id одного запроса «протекает» в другой. # ❌ Так делать нельзя import threading local_data = threading.local() async def handle_request(request_id): local_data.request_id = request_id await some_async_operation() print(local_data.request_id) # может быть уже чужой request_id! 🧠 `contextvars`: контекст, привязанный к задаче contextvars — это модуль из стандартной библиотеки, который создаёт переменные, чьи значения привязаны к текущему контексту выполнения. В asyncio каждая задача (Task) получает свой контекст. Переключение между корутинами не смешивает данные. from contextvars import ContextVar request_id: ContextVar[str] = ContextVar("request_id", default="unknown") async def handle_request(rid): request_id.set(rid) # устанавливаем значение для текущего контекста await some_async_operation() print(request_id.get()) # всегда наш rid async def some_async_operation(): await asyncio.sleep(0.1) print(request_id.get()) # тоже наш rid, хотя функция вложенная Что произошло: - ContextVar создаёт переменную. - .set(value) устанавливает значение в текущем контексте. - .get() читает значение из текущего контекста. - При переключении на другую корутину контекст сохраняется и восстанавливается. 🧪 Пример: логирование с `request_id` Самое частое применение — прокидывание request_id в логи через middleware. import asyncio import logging from contextvars import ContextVar request_id: ContextVar[str] = ContextVar("request_id", default="-") # Настраиваем логгер с request_id class RequestIdFilter(logging.Filter): def filter(self, record): record.request_id = request_id.get() return True logging.basicConfig( format="%(asctime)s [%(request_id)s] %(message)s", level=logging.INFO, ) logger = logging.getLogger(__name__) logger.addFilter(RequestIdFilter()) async def handle_request(rid): request_id.set(rid) logger.info("Начало обработки") await asyncio.sleep(0.1) logger.info("Конец обработки") async def main(): await asyncio.gather( handle_request("req-1"), handle_request("req-2"), ) asyncio.run(main()) Вывод: 2026-10-19 12:00:00,001 [req-1] Начало обработки 2026-10-19 12:00:00,002 [req-2] Начало обработки 2026-10-19 12:00:00,102 [req-1] Конец обработки 2026-10-19 12:00:00,102 [req-2] Конец обработки Каждый запрос видит свой request_id, хотя все корутины работают в одном потоке. 🧱 `copy_context` и `run_in_executor` Если вы запускаете синхронный код в пуле потоков через loop.run_in_executor, контекст не пробрасывается автоматически. Нужно скопировать его вручную. import asyncio from contextvars import copy_context async def main(): request_id.set("req-42") loop = asyncio.get_running_loop() ctx = copy_context() # Запускаем синхронную функцию в потоке с нашим контекстом await loop.run_in_executor(None, ctx.run, sync_function) ctx.run(func) выполняет функцию в скопированном контексте, и request_id.get() внутри sync_function вернёт "req-42". ⚠️ Ловушки и частые ошибки 1. Использовать `threading.local` в асинхронном коде — данные перемешиваются между корутинами. 2. Забыть, что `set()` возвращает `Token` — можно использовать для сброса значения. ```python token = request_id.set("abc") # ... request_id.reset(token) # вернуть прежнее значение ``` 3. Ожидать, что контекст пробросится в `run_in_executor` сам — нужно копировать через copy_context. 4. Создавать `ContextVar` внутри функции — создавайте на уровне модуля, иначе каждый вызов создаёт новую переменную. 5. Использовать `ContextVar` для передачи больших данных — это лёгкий механизм для небольших значений (ID, флаги, пользователь). 💡 Запомни: 🟢 contextvars — это threading.local для асинхронного мира. 🟢 ContextVar привязан к контексту задачи, а не к потоку. 🟢 Используйте .set() и .get() для установки и чтения значения. 🟢 Для run_in_executor копируйте контекст через copy_context(). 🟢 Идеально для request_id, текущего пользователя, флагов и метрик. 🟢 Не используйте threading.local в asyncio — данные перемешаются. contextvars — это не «ещё одна фича». Это способ писать асинхронный код, который не превращается в спагетти из аргументов. Освоив его, вы перестанете бояться пробрасывать данные через вложенные вызовы. Программистика|| #Статья
497
9
Какое будущее ждет Python? 🤔 📱 Первоисточник Программистика|| #video
Какое будущее ждет Python? 🤔 📱 Первоисточник Программистика|| #video
583
10
🧠 Отгадка: что выведет этот код? class A: def __new__(cls): return B() def __init__(self): print("A init") class B: def __init__(self): print("B init") a = A() print(type(a).__name__) ✔️ Правильный ответ: 2. `B init`, затем `B` 📖 Почему так происходит? Когда вы вызываете A(), Python сначала вызывает __new__ класса A. В нашем коде __new__ возвращает экземпляр класса `B` (вызов B()), а не A. Поэтому: 1. __new__ создаёт объект класса B → срабатывает B.__init__ → печатается B init. 2. Поскольку __new__ вернул объект не того класса, для которого вызван (вернул B, а не A), Python не вызывает A.__init__. Поэтому A init не печатается. 3. a — это экземпляр B. type(a).__name__ возвращает 'B'. Итог: B init, затем B. Ключевой момент: __init__ вызывается только если __new__ вернул экземпляр того же класса (или его подкласса). Если возвращён объект другого класса, __init__ игнорируется. Это отличный пример того, как __new__ может полностью изменить поведение конструктора. Ставьте 🔥, если было полезно! Программистика|| #quiz
734
11
⚪️ Все лучшие инструкции, гайды, книги и инструменты — без воды. ☁️ Хакинг & ИБ — 756GB ⌨️ Python — 955GB 🙃 Linux & Bash — 4
⚪️ Все лучшие инструкции, гайды, книги и инструменты — без воды. ☁️ Хакинг & ИБ — 756GB ⌨️ Python — 955GB 🙃 Linux & Bash — 459GB 🤒 OSINT — 315GB 🖥 Курсы & GitHub — 1579GB ➡️ Присоединяйтесь и качай. Пост будет удален через 48 часов.
353
12
⚡️ Библиотека Python: Thermite Thermite — это сверхбыстрая библиотека машинного обучения, написанная на Rust и полностью совместимая с scikit-learn. Она переписывает вычислительно тяжёлые части sklearn нативно на Rust, используя SIMD, многопоточность Rayon и оптимизации matrixmultiply, при этом сохраняя тот же Python API. Достаточно заменить import sklearn на import thermite — никакого нового синтаксиса и руководств по миграции не требуется. Библиотека поддерживает zero-copy интеграцию с Polars, GPU-ускорение через wgpu и настоящий параллелизм без GIL, что делает её идеальной для высоконагруженных ML-пайплайнов и подготовки данных. ✔️ Установка: pip install thermite-ml Программистика|| #Library
758
13
🔍 Секрет `math.isclose`: никогда не сравнивай float через `==` Вы уже знаете, что 0.1 + 0.2 не равно 0.3? В Python это даёт False из-за особенностей хранения чисел с плавающей точкой. ❌ Плохо: print(0.1 + 0.2 == 0.3) # False ✅ Хорошо: import math print(math.isclose(0.1 + 0.2, 0.3)) # True math.isclose(a, b) сравнивает числа с учётом погрешности. Можно настроить точность через rel_tol и abs_tol. 🟢 Запомни: для float используй math.isclose, а не ==. Программистика|| #tips
801
14
🧠 Загадка на ночь: что выведет этот код? class A: def __new__(cls): return B() def __init__(self): print("A init") class B: def __init__(self): print("B init") a = A() print(type(a).__name__) Варианты: 1. A init и B init, затем A 2. B init, затем B 3. A init, затем A 4. B init, затем A Пиши свой вариант в комментарии! Ответ и разбор — через пару часов 🔥 Программистика|| #quiz
788
15
🗺 Шпаргалка по Python Программистика//#doc
🗺 Шпаргалка по Python Программистика//#doc
768
16
👩‍💻 От 1 до 10 000 RPS: Как масштабируется Backend приложение при росте нагрузки 📱 Первоисточник Программистика|| #video
👩‍💻 От 1 до 10 000 RPS: Как масштабируется Backend приложение при росте нагрузки 📱 Первоисточник Программистика|| #video
853
17
Программистика
Программистика
757
18
💀 Почему вы не пишете тесты (и почему это ошибка) Вы пишете код. Он работает. Вы проверяете вручную — «вроде норм». Через ме
💀 Почему вы не пишете тесты (и почему это ошибка) Вы пишете код. Он работает. Вы проверяете вручную — «вроде норм». Через месяц нужно что-то изменить. Вы меняете одну строчку. Ломается три других. Вы не понимаете, где именно. Начинаете проверять всё руками снова. Знакомо? Тогда эта статья для вас. Только честно, без утешений. 🧱 Почему вы не пишете тесты Давайте честно. Вы не пишете тесты, потому что: - «Это долго» - «Я и так знаю, что код работает» - «Тесты пишут только в больших компаниях» - «У меня нет времени» Но правда в другом: вы не пишете тесты, потому что не умеете. Вас этому не научили. Курсы про тесты — скучные. А ручная проверка даёт мгновенный результат. 📌 Правило: если вы не можете написать тест на свою функцию — вы не понимаете, что она делает. 🧱 Что происходит без тестов Каждое изменение — это русская рулетка. Вы не знаете: - что сломалось после правки - работает ли код на краевых случаях - можно ли безопасно рефакторить - не вернулся ли старый баг Вы тратите часы на ручную проверку. И всё равно пропускаете баги. Потому что человек не может проверить 50 сценариев в голове одновременно. 📌 Правило: код без тестов — это код, который работает «сегодня». Завтра он может сломаться. 🧱 Тесты — это не про «доказать, что код работает» Новички думают, что тесты нужны, чтобы доказать правильность. На самом деле тесты нужны для другого: - Уверенность при рефакторинге. Вы меняете код и знаете: если что-то сломалось — тест покажет. - Документация поведения. Тест — это живой пример использования функции. - Быстрая обратная связь. Ошибку видно за секунды, а не через неделю в проде. - Смелость менять. Без тестов вы боитесь трогать код. С тестами — рефакторите спокойно. 📌 Правило: тесты — это не про «доказать», а про «не бояться». 🧱 Почему это ошибка Работодатели знают: код без тестов — это технический долг. Проект, который нельзя безопасно менять, умирает. Именно поэтому на собеседованиях спрашивают про тестирование. Вы можете быть гениальным программистом. Но если вы не пишете тесты — вы не инженер. Вы ремесленник, который делает одноразовые вещи. 📌 Правило: в современной разработке тесты — это не опция. Это часть профессии. 🧱 Что делать прямо сейчас 1. Начните с одного теста. Возьмите самую простую функцию и напишите для неё test_*.py. Пять минут — и вы уже в игре. 2. Не гонитесь за 100% покрытием. Начните с критичных мест. 3. Используйте `pytest`. Он проще, чем unittest, и читается как обычный код. 4. Пишите тесты до рефакторинга. Сначала зафиксируйте поведение, потом меняйте. 5. Не оправдывайтесь. «Нет времени на тесты» — значит, будет время на отладку багов в проде. 💡 Запомни: 🟢 Тесты — не про доказательство, а про уверенность. 🟢 Без тестов рефакторинг — это хождение по минному полю. 🟢 Не можете написать тест — не понимаете функцию. 🟢 Начните с одного теста. Прямо сейчас. 🟢 Тесты — это часть профессии, а не «для больших компаний». Вы не пишете тесты не потому, что у вас нет времени. Вы не пишете их потому, что не умеете. Научитесь — и код станет надёжнее, а работа спокойнее. Если зашла такая рубрика ставь реакцию 🔥? Программистика|| #Статья
748
19
🧠 TypeVar и ограничения типов: как писать гибкий, но безопасный код Вы пишете функцию, которая должна работать с разными типами, но при этом сохранять типовую безопасность. Например, функция first() возвращает первый элемент списка — но если вы передали list[int], она должна вернуть int, а не Any. Для этого в Python есть TypeVar — мощный инструмент дженериков. Разбираемся, как его готовить. 🧱 Что такое `TypeVar` TypeVar — это переменная типа, которая позволяет создавать обобщённые (generic) функции и классы. Она говорит: «тип будет уточнён при вызове». from typing import TypeVar T = TypeVar('T') def first(items: list[T]) -> T: return items[0] # type checkers знают, что результат — int result = first([1, 2, 3]) # int Без TypeVar пришлось бы возвращать Any или object, теряя всю информацию о типе. 🧱 Ограничения: `bound` vs `constraints` У TypeVar есть два способа ограничить типы. 1. `bound` — верхняя граница Говорит: «тип должен быть наследником указанного класса». from typing import TypeVar class Animal: def speak(self) -> str: return "..." class Dog(Animal): def speak(self) -> str: return "Гав" T = TypeVar('T', bound=Animal) def make_speak(animal: T) -> T: print(animal.speak()) return animal make_speak(Dog()) # OK make_speak(42) # ❌ type checker ошибётся 🟢 Важно: bound разрешает наследников, но не требует точного типа. 2. `constraints` — жёсткий список типов Говорит: «тип должен быть ровно одним из перечисленных». from typing import TypeVar T = TypeVar('T', int, str) def double(value: T) -> T: return value * 2 # работает и для int, и для str double(5) # int double("ab") # str double(3.14) # ❌ type checker ошибётся — float не разрешён 🟢 Разница: bound — «или наследник», constraints — «ровно один из списка». 🧱 Generic-классы TypeVar можно использовать и в классах. from typing import TypeVar, Generic T = TypeVar('T') class Stack(Generic[T]): def __init__(self) -> None: self._items: list[T] = [] def push(self, item: T) -> None: self._items.append(item) def pop(self) -> T: return self._items.pop() stack: Stack[int] = Stack() stack.push(1) stack.push("abc") # ❌ type checker ошибётся 🟢 Type checkers (mypy, pyright) проверят, что вы не смешиваете типы в одном стеке. 🧱 Практический пример: кэш с типами from typing import TypeVar, Generic, Optional K = TypeVar('K') V = TypeVar('V') class Cache(Generic[K, V]): def __init__(self) -> None: self._data: dict[K, V] = {} def get(self, key: K) -> Optional[V]: return self._data.get(key) def set(self, key: K, value: V) -> None: self._data[key] = value cache = Cache[str, int]() cache.set("age", 30) value = cache.get("age") # int | None 🧱 Ограничения и `bound` в реальном коде from typing import TypeVar from collections.abc import Sequence T = TypeVar('T', bound=Sequence) def total_length(items: list[T]) -> int: return sum(len(item) for item in items) total_length([[1, 2], "abc", (4, 5)]) # OK total_length([1, 2, 3]) # ❌ int не Sequence ⚠️ Ловушки и частые ошибки 1. Путать `bound` и `constraints`. bound — наследники разрешены, constraints — только точные типы. 2. Использовать `TypeVar` без необходимости. Если функция работает с любым типом и не зависит от него — используйте object или Any. 3. Забыть про `Generic` в классе. Без Generic[T] type checker не поймёт, что класс обобщённый. 4. Ожидать, что `TypeVar` работает в runtime. TypeVar — только для статических анализаторов. В рантайме это просто объект. 5. Игнорировать `covariance` и `contravariance`. Для сложных случаев есть covariant=True и contravariant=True, но это уже высший пилотаж. 💡 Запомни: 🟢 TypeVar — переменная типа для обобщённых функций и классов. 🟢 bound — верхняя граница (наследники разрешены). 🟢 constraints — жёсткий список допустимых типов. 🟢 Используйте Generic[T] для обобщённых классов. 🟢 TypeVar работает только со статическими анализаторами (mypy, pyright). Программистика|| #Статья
595
20
✂️ Секрет `removeprefix` и `removesuffix`: обрезай строки без срезов и условий Устали удалять начало или конец строки через срезы и проверки? В Python 3.9+ есть два метода, которые делают это элегантно. ❌ Было (костыль со срезами): url = "https://example.com" if url.startswith("https://"): url = url[8:] # знай длину префикса наизусть filename = "report.pdf" if filename.endswith(".pdf"): filename = filename[:-4] # и суффикс отрезать вручную ✔️ Стало (чисто и безопасно): url = "https://example.com" url = url.removeprefix("https://") # "example.com" filename = "report.pdf" filename = filename.removesuffix(".pdf") # "report" 🟢 Почему круто: - Не нужно считать символы и помнить длину. - Если префикса/суффикса нет, строка возвращается без изменений (никаких ошибок). - Работает быстрее, чем проверка + срез. Где пригодится: обработка URL, имён файлов, логов, API-ответов. Запомни: removeprefix() и removesuffix() — твои друзья для чистой работы со строками. Программистика|| #tips
705