Программистика
کانال بسته
Лучший канал про python Ссылка для друга: https://t.me/+Ai6ughKtf5g2ZmFi Купить рекламу: https://telega.in/c/+Ai6ughKtf5g2ZmFi Админ: @JeyRahol По рекламе: @ReivuManager
نمایش بیشتر5 768
مشترکین
-324 ساعت
-137 روز
-6530 روز
در حال بارگذاری دادهها
کانالهای مشابه
هیچ دادهای
مشکلی وجود دارد؟ لطفاً صفحه را تازه کنید یا با مدیر پشتیبانی ما تماس بگیرید.
ابر برچسبها
اشارات ورودی و خروجی
---
---
---
---
---
---
جذب مشترکین
اکتبر '26اکتبر '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 и внутренней механики функций.
🌐 СсылкаПрограммистика || #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 — это адаптивный фреймворк для веб-скрапинга, который решает главную боль парсеров: «сайт изменился — код сломался». Вместо жёстких CSS-селекторов он использует умное отслеживание элементов, запоминая их визуальные признаки и контекст. Если вёрстка обновилась, Scrapling автоматически находит нужные данные заново. Плюс в комплекте — обход Cloudflare, поддержка JavaScript-рендеринга, асинхронность и встроенный MCP-сервер для AI-агентов.
✔️ Установка:
pip install scrapling
Программистика|| #Library | 516 |
| 6 | 😎 Глубокое обучение на Python. 2-е международное издание
Глубокое обучение динамично развивается, открывая все новые и новые возможности создания ПО. Это не только автоматический перевод текстов с одного языка на другой, распознавание изображений, но и многое другое. Глубокое обучение превратилось в важный навык, необходимый каждому разработчику.
Keras и TensorFlow облегчают жизнь разработчикам и позволяют легко работать даже тем, кто не имеет фундаментальных знаний в области математики или науки о данных.
Настала пора познакомиться с глубоким обучением и мощной библиотекой Keras!
В этом расширенном и дополненном издании создатель библиотеки Keras — Франсуа Шолле — делится знаниями и с новичками, и с опытными специалистами. Иллюстрации и наглядные примеры помогут вам разобраться с самыми сложными вопросами и концепциями.
Вы быстро приобретете навыки, необходимые для разработки приложений глубокого обучения.
Программистика || #Книги | 587 |
| 7 | Как связаны случайные графы, дата-центры и человек, который просто хотел разобраться, как всё это работает?
На самом деле — очень просто. Иногда, чтобы понять, почему современные системы устроены именно так, приходится залезть в математику, теорию графов и архитектуру дата-центров. А потом ещё и объяснить всё это человеческим языком.
Именно этим занимается Аня — разработчик в 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 | 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 — 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 | 768 |
| 16 | 👩💻 От 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 |
