PytStart | Программирование на Python
4.28K subscribers
23 photos
26 videos
57 links
Python: примеры кода, уроки, статьи

Купить рекламу: https://telega.in/c/pytstart

✍️По всем вопросам: @Pascal4eg
Download Telegram
🖥 Что делает enumerate() в Python?

3️⃣ enumerate() добавляет счётчик к итерации.

fruits = ["🍎", "🍌", "🍇"]
for i, fruit in enumerate(fruits):
print(i, fruit)


📌 Вывод:
0 🍎  
1 🍌
2 🍇



🗣 Используется, когда нужен индекс при переборе: списки, строки, циклы в UI и CLI.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31
📱 Генерируем QR‑коды в Python: просто, гибко, наглядно

Иногда нужно быстро создать QR‑код: для ссылки, текста, визитки или даже Wi‑Fi‑пароля. Python справляется с этим буквально за пару строк.
Давай разберём, как это делается и что внутри происходит.

pip install qrcode[pil]

➡️ Устанавливаем библиотеку qrcode. В скобках [pil] — сразу тянет Pillow для работы с изображениями.

import qrcode

img = qrcode.make("https://example.com")
img.save("qrcode.png")

➡️ Базовый случай: генерация QR‑кода для любой строки. Метод make сразу создаёт изображение, которое можно сохранить или отдать пользователю.

Обычно хочется чуть больше контроля: размер, плотность, уровень защиты от ошибок, цвета.
Для этого создаём QR‑код «вручную»:

qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data("Hello, QR!")
qr.make(fit=True)

img = qr.make_image(fill_color="black", back_color="white")
img.save("custom_qr.png")

➡️ Здесь мы задаём:

🟢 version — размер сетки (1 — минимальный);
🟢 error_correction — сколько данных можно потерять и всё ещё прочитать код;
🟢 box_size и border — масштаб и рамку.

А если хочется добавить логотип или иконку — тоже просто:

Создаём QR‑код с высоким уровнем коррекции ошибок и «вклеиваем» логотип по центру:
from PIL import Image

logo = Image.open("logo.png")
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H)
qr.add_data("https://mysite.com")
qr.make(fit=True)

qr_img = qr.make_image(fill_color="black", back_color="white").convert("RGB")

pos = (
(qr_img.size[0] - logo.size[0]) // 2,
(qr_img.size[1] - logo.size[1]) // 2,
)
qr_img.paste(logo, pos)
qr_img.save("qr_with_logo.png")

➡️ Логотип уменьшай так, чтобы не закрывал слишком много ячеек.
Высокий уровень коррекции (ERROR_CORRECT_H) позволяет восстанавливать данные даже при частичном перекрытии.


🗣️ Запомни: QR‑код — это обычное изображение, а Python — отличная среда, чтобы сгенерировать их сотнями или добавить фирменный стиль прямо в коде.
Просто текст → картинка → готово.
Please open Telegram to view this post
VIEW IN TELEGRAM
7🔥2
👩‍💻 `pip` — не просто "установить пакет"

Каждый Python-разработчик использует pip, но далеко не все понимают, насколько критична дисциплина в управлении зависимостями. Ошибки здесь = боль на проде, в CI и при сборке.

🔍 1. Никогда не устанавливай пакеты глобально

pip install some-library  # 


➡️ Это засоряет системный Python, может конфликтовать с другими проектами и ломает dev-среду.

✔️ Всегда используй виртуальное окружение:

python -m venv venv
source venv/bin/activate
pip install some-library


➡️ Чистота, изоляция, контроль.


🔐 2. Зафиксируй зависимости

Если ты не фиксируешь версии — ты играешь в лотерею.

pip install requests


Через месяц выйдет новая мажорная версия — и твой код может отвалиться.

✔️ Делай так:

pip install requests==2.31.0


А ещё лучше:

pip freeze > requirements.txt


➡️ И ты всегда знаешь, что работает. И на проде, и у коллег.

📦 3. Используй `--upgrade-strategy eager` с умом

pip install -U some-lib  # по умолчанию может подтянуть несовместимости


➡️ Это может внезапно обновить половину стека. Используй --upgrade-strategy only-if-needed, если хочешь избегать каскадных обновлений.

🛠 4. Обновление pip — не каприз

Иногда pip старый, и ты получаешь ошибки вроде "metadata generation failed".

✔️ Просто:

pip install -U pip


➡️ Новые версии pip реально решают кучу проблем с установкой.

⚙️ 5. Хочешь порядок? Используй `pip-tools`

pip install pip-tools


Работает как pip freeze, но человечно:

# requirements.in
requests==2.31.0
flask>=2.0


pip-compile requirements.in  # генерирует requirements.txt с зависимостями


➡️ Ты контролируешь high-level зависимости, pip-tools следит за всем остальным.

🗣️ Запомни: pip — это твой фундамент. Если ты не управляешь зависимостями осознанно, ты рано или поздно огребаешь. Особенно в команде.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72👏1
🔁 Как работает yield и зачем он реально нужен в Python

yield — это не return. Он не завершает функцию, а паузит её и отдаёт результат по частям.

Простой пример: отдаём по одному

def gen():
yield 1
yield 2
yield 3

for x in gen():
print(x)

👉 Вывод: 1, 2, 3 — не сразу, а по одному.
Функция работает до первого `yield`, потом «засыпает» и продолжает дальше.

🧾 Чтение большого файла без нагрузки

def read_lines(path):
with open(path) as f:
for line in f:
yield line.strip()

for line in read_lines("huge.log"):
print(line)

Если файл весит 10 ГБ — всё равно работает.
Никаких readlines(), которые жрут память.

🔢 Бесконечный счётчик

def counter():
n = 0
while True:
yield n
n += 1

for i in counter():
if i > 5:
break
print(i)

👉 Без yield тут не обойтись.
Можно генерировать бесконечный поток, но обрабатывать его как обычный список.

📤 Свой генератор фильтра

def even_only(numbers):
for n in numbers:
if n % 2 == 0:
yield n

nums = [1, 2, 3, 4, 5, 6]
for x in even_only(nums):
print(x)

👉 Не filter(), а свой контролируемый фильтр. Гибко и понятно.

🗣️ Запомни:yield — это когда ты генерируешь данные на лету.
Ты не ждёшь весь список, не держишь всё в памяти — просто отдаёшь, когда нужно.
Нужен потоковый режим? yield — лучший друг.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍71🤔1
👩‍💻 `@property`: не просто синтаксический сахар

В Python у тебя есть мощный способ скрыть логику за обычным доступом к атрибутам — и имя ему @property.

Пример:

class Circle:
def __init__(self, radius):
self._radius = radius

@property
def area(self):
return math.pi * self._radius ** 2


Теперь:

c = Circle(3)
print(c.area) # 28.27...


➡️ area выглядит как поле, но за ним — код. Удобно, безопасно и читаемо.

🔥 Где полезно использовать `property`:

1. Когда значение вычисляется "на лету"

@property
def is_active(self):
return self.last_seen > datetime.now() - timedelta(minutes=5)


➡️ user.is_active читается как флаг, но всегда актуален.

2. Когда хочешь валидировать данные при установке

@property
def age(self):
return self._age

@age.setter
def age(self, value):
if value < 0:
raise ValueError("Возраст не может быть отрицательным")
self._age = value


➡️ Можно написать person.age = -1 — но это вызовет ошибку, как и должно.

3. Когда хочешь спрятать внутренности, не меняя интерфейс

Сначала у тебя было:

user.is_admin  # булево поле


А потом ты передумал и решил вычислять его по ролям:

@property
def is_admin(self):
return "admin" in self.roles


➡️ Все старые вызовы user.is_admin останутся рабочими, но теперь они динамичные.


🧠 @property делает твой код гибким: интерфейс остаётся, а реализацию можно менять. Это инкапсуляция, но по-питоновски.

Ты можешь добавить к setter'у ещё и deleter:

@x.deleter
def x(self):
del self._x


Но чаще всего нужны только getter и setter.

🗣️ Запомни: @property — это не украшение. Это способ скрыть логику, проверки, кэширование, не портя интерфейс.
Ты получаешь читаемый API, не жертвуя гибкостью.


📍Где применяется:
ORM, модели, бизнес-логика, интерфейсы SDK, динамические флаги, защитные проверки. Везде, где важно: "пусть выглядит просто, но работает как надо".
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
👩‍💻 Парсинг сайтов с requests + BeautifulSoup: просто, быстро, эффективно

Если тебе нужно вытянуть данные с HTML-страницы — это классика.
requests тянет страницу, BeautifulSoup разбирает её в структуру, которую легко обрабатывать.

👍 Базовый шаблон парсера
import requests
from bs4 import BeautifulSoup

url = "https://example.com"
resp = requests.get(url)
soup = BeautifulSoup(resp.text, "html.parser")


➡️ soup — это объект, с которым можно работать как с DOM-деревом.

👍 Извлечение элементов
title = soup.find("h1").text
links = [a["href"] for a in soup.find_all("a") if "href" in a.attrs]


🟢find() — первый найденный элемент, find_all() — список всех. Атрибуты доступны как у словаря.

👍 CSS-селекторы вместо find()
items = soup.select("div.card > a.link")


➡️ select() — поддерживает любые CSS-селекторы. Гибко и читаемо.

👍 Обработка текста и атрибутов
for img in soup.select("img"):
print(img.get("src"), img.get("alt"))


➡️ get() безопаснее прямого доступа: не упадёт, если атрибута нет.

👍 Работа с headers и user-agent
headers = {"User-Agent": "Mozilla/5.0"}
r = requests.get(url, headers=headers)


➡️ Некоторые сайты блокируют запросы без User-Agent. Добавляй его для стабильности.

🗣️ Запомни: requests + BeautifulSoup — это основа для быстрого парсинга HTML.
Подходит для большинства задач: просто, мощно, читаемо. Но не забудь уважать robots.txt и лимитировать частоту запросов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
👩‍💻 Разница между copy() и deepcopy()

• copy() создает поверхностную копию объекта (ссылки на вложенные элементы сохраняются).
• deepcopy() создает полную независимую копию объекта.

✔️ Пример:


import copy

a = [[1, 2], [3, 4]]
b = copy.copy(a)
c = copy.deepcopy(a)

a[0][0] = 99

print(b) # [[99, 2], [3, 4]] (изменилось)
print(c) # [[1, 2], [3, 4]] (осталось прежним)


🗣️ Используйте deepcopy(), если хотите избежать изменения оригинальных данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
👩‍💻 Разница между is и ==

Многие путают is и ==, но их предназначение разное:

is проверяет, являются ли два объекта одной и той же сущностью в памяти.
== проверяет, равны ли их значения.

✔️ Пример:


a = [1, 2, 3]
b = a
c = [1, 2, 3]

print(a is b) # True (указывает на тот же объект)
print(a == b) # True (списки одинаковые)

print(a is c) # False (разные объекты)
print(a == c) # True (одинаковое содержимое)


🗣️ Используйте is для проверки, ссылаются ли переменные на один объект, а == — для сравнения значений.
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍2
👩‍💻 SQLite в Python: база прямо в файл, без сервера

Когда не нужен полноценный PostgreSQL, а просто надо где-то хранить данные — SQLite идеально.

✔️ Легковесно
✔️ Без установки
✔️ Всё в одном .db-файле

🔧 Пример: создать базу и таблицу
import sqlite3

conn = sqlite3.connect("users.db") # создаёт файл, если нет
cursor = conn.cursor()

cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
age INTEGER
)
""")
conn.commit()

➡️ Создали таблицу users — без серверов, Docker и настроек.

Вставка данных
cursor.execute("INSERT INTO users (username, age) VALUES (?, ?)", ("alice", 30))
conn.commit()

➡️ Используем ? — это защита от SQL-инъекций.

🔍 Чтение данных
cursor.execute("SELECT * FROM users")
for row in cursor.fetchall():
print(row)

➡️ Получаем все строки как кортежи.

🔁 Обновление и удаление
cursor.execute("UPDATE users SET age = ? WHERE username = ?", (31, "alice"))
cursor.execute("DELETE FROM users WHERE age < ?", (18,))
conn.commit()

➡️ Всё как в обычном SQL. Просто — и работает.

Закрытие соединения
conn.close()

Или так:
with sqlite3.connect("users.db") as conn:
...


🗣️Запомни:
SQLite — идеальный вариант для прототипов, локальных тулз, ботов, скриптов и парсеров.
Поддерживает SQL, транзакции, индексы — и всё в одном файле.
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2
🖥 Ленивый дебаг с f-строками

Если вы часто пишете print("var =", var), чтобы проверить значение переменной, то этот трюк сэкономит вам кучу времени.

Начиная с Python 3.8, в f-строках можно использовать знак равно =.

➡️Как это было раньше:

user = "Alex"
age = 25
print(f"user = {user}, age = {age}")
# Вывод: user = Alex, age = 25


📌Как делают профи:
Просто добавьте = в конце переменной внутри фигурных скобок. Python сам подставит имя переменной и её значение.

user = "Alex"
age = 25

print(f"{user=}, {age=}")
# Вывод: user='Alex', age=25


Это работает даже с выражениями:

print(f"{2 + 2 = }")
# Вывод: 2 + 2 = 4


Мелочь, а код для отладки пишется в два раза быстрее! 🚀
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍3
🔥 Частая ошибка: try/except пожирает всё


try:
do_something()
except:
pass


⛔️ Это плохая практика, которая уничтожает отладку, ломает контроль потока и маскирует реальные ошибки
.


🤯 Почему это опасно?

🟢 1. Ловит всё подряд:
- KeyboardInterrupt — Ctrl+C не сработает, ты не сможешь остановить процесс.
- SystemExitsys.exit() не завершит программу.
- SyntaxError, MemoryError, ImportError — всё будет съедено.

➡️ Такой код не просто "ловит ошибки" — он прячется от них.

🟢 2. Трудно отлаживать

Если внутри блока try падает непредсказуемая ошибка, а ты её не логируешь — ты даже не узнаешь, что код работает неправильно.


try:
complex_logic()
except:
pass # ничего не видно, баг скрыт


Ты можешь:
- Ловить AttributeError, потому что опечатался.
- Не инициализировать переменную.
- Получать KeyError, IndexError, ValueError — и никогда об этом не узнаешь.

Как правильно?

📌 1. Лови только нужные исключения:


try:
result = do_network_call()
except TimeoutError:
print("Превышено время ожидания")


Если ты не знаешь, какие ошибки может выбросить функция — выясни. Это важно.

📌 2. Логируй исключения:


import logging

try:
open("somefile.txt")
except FileNotFoundError as e:
logging.warning(f"Файл не найден: {e}")


Это поможет в отладке, особенно если ты на проде. Можно подключить sentry, rollbar, loguru — что угодно, лишь бы не терять ошибки в пустоте.

📌 3. Хочешь "молчаливое" поведение? — добавь комментарий, зачем:


try:
optional_feature()
except SomeError:
pass # ok to fail — не критично


Будущий ты (или твой тиммейт) скажет спасибо.

📌 4. Никогда не делай так:


try:
...
except Exception:
pass


🧨 Exception — тоже широкая сеть. Иногда это допустимо (например, в retry-декораторе), но по умолчанию — нет.

🚨 Запомни:

🟢 `except:` — ловит всё , даже Ctrl+C, exit().
🟢 `except Exception:` без логов — багов не видно, теряется контекст.
🟢`pass` в except — молча глушит ошибку , никаких действий.

Лучше: перехватывай конкретные ошибки, логируй, не скрывай баги.

📌 Когда можно ловить всё?

Иногда (но редко!) тебе нужно поймать всё — например, при логгировании в многопоточном приложении или глобальном хендлере ошибок:


try:
...
except Exception:
logger.exception("Что-то пошло не так")


Но всегда логируй, и никогда не делай pass без причины.

🗣 Грамотная работа с ошибками — одна из черт хорошего инженера. Код должен быть предсказуемым, отлаживаемым и честным: если ошибка есть — мы о ней узнаём.

📍 Где применяется:
Backend, парсеры, ETL-пайплайны, API, CLI-инструменты — везде, где ошибка не должна оставаться в тени.
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
🖥 Python и with: Чистый код и надёжное управление ресурсами

Ещё одна мощная и идиоматичная конструкция в Python — это менеджеры контекста и оператор with. Они кардинально упрощают работу с ресурсами, которые требуют обязательной "очистки" после использования, например, файлы, сетевые соединения или блокировки потоков.

Представьте, что вы открываете файл для записи. Крайне важно его потом закрыть, иначе данные могут не сохраниться, а файловый дескриптор останется занят. Классический, но многословный способ гарантировать закрытие — использовать try...finally:

f = open('my_file.txt', 'w')
try:
f.write('Важные данные!')
# ... тут может произойти ошибка
finally:
f.close() # Закроется в любом случае


Работает, но выглядит громоздко. Python предлагает элегантную альтернативу с with:

with open('my_file.txt', 'w') as f:
f.write('Важные данные!')
# ... тут тоже может произойти ошибка
# Как только блок `with` завершается (нормально или из-за ошибки),
# Python АВТОМАТИЧЕСКИ вызывает f.close()!


В чём магия with?

Объекты, используемые с with (как тот, что возвращает open()), реализуют так называемый "протокол менеджера контекста". У них есть специальные методы (__enter__ и __exit__). Оператор with вызывает __enter__ при входе в блок и гарантированно вызывает __exit__ при выходе из блока, передавая туда информацию об исключениях, если они были. Именно в __exit__ и происходит освобождение ресурса (закрытие файла).

Оператор with — это стандарт де-факто для управления ресурсами в Python. Он делает код не только короче, но и значительно безопаснее и понятнее.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥31👍1
🧬 Структурные шаблоны (match/case) с объектами – не только для строк и чисел!

Начиная с Python 3.10, match/case позволяет не просто сравнивать, но разбирать структуры объектов.

📌 Пример с классами:

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

def handle(p):
match p:
case Point(x=0, y=y):
print(f"На оси Y: y={y}")
case Point(x=x, y=0):
print(f"На оси X: x={x}")
case Point():
print("Внутри плоскости")

handle(Point(0, 5))


Работает благодаря __match_args__ — специальному атрибуту:
class Point:
__match_args__ = ("x", "y")


🗣️ Возможности match/case гораздо шире if — особенно при парсинге AST, JSON, конфигураций и DSL.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
🚰 Стриминг больших данных через генераторы и yield from

Когда данных слишком много — миллионы строк в файле, бесконечные события или поток логов — держать всё в памяти нельзя. Тут спасают генераторы и ключевое слово yield from, позволяющее строить цепочки ленивых итераторов.

📦 Чтение файла построчно
def read_file(path):
with open(path, "r") as f:
for line in f:
yield line.strip()

for row in read_file("bigdata.txt"):
print(row)

➡️ Память не переполняется: читается и отдаётся по строке.

🔗 Комбинация генераторов через yield from
def numbers():
yield from range(5)
yield from range(10, 15)

print(list(numbers()))

➡️ yield from разворачивает подгенераторы и прокидывает их значения наружу.

⚡️ Обработка пайплайнами
def read_lines(path):
with open(path) as f:
yield from f

def filter_errors(lines):
for line in lines:
if "ERROR" in line:
yield line

errors = filter_errors(read_lines("app.log"))
for e in errors:
print(e)

➡️ Логика разбивается на звенья, и каждое обрабатывает поток данных лениво.

🌀 Бесконечные источники

import time

def ticker():
while True:
yield time.time()
time.sleep(1)

for t in ticker():
print(t)

➡️ Генератор выдаёт значения бесконечно, но потребитель сам решает, когда остановиться.

📑 Вложенные пайплайны с yield from
def split_words(lines):
for line in lines:
yield from line.split()

data = ["hello world", "big data stream"]
for word in split_words(data):
print(word)

➡️ yield from красиво разрывает вложенные итерации без двойных циклов.

🚀 Генераторы + итераторы стандартной библиотеки
from itertools import islice

def stream():
for i in range(1000000):
yield i

print(list(islice(stream(), 5)))

➡️ Вместо списка в миллион чисел получаешь поток, из которого берёшь только нужное.

🗣️ Запомни: генераторы — это ленивые конвейеры данных, yield from связывает их в цепочку. Такой подход позволяет обрабатывать гигабайты без переполнения памяти и писать код, который дышит как поток.
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
👩‍💻 DSL в Python через __call__ и __getitem__ — красиво, читаемо, Pythonic

Хочешь, чтобы твой код выглядел как язык сам по себе?
Python позволяет строить мини-языки внутри кода — без библиотек, просто на магии dunder-методов.

✔️ Начнём с __call__

Он делает объект вызываемым, как функцию:
class Hello:
def __call__(self, name):
return f"Привет, {name}!"

h = Hello()
print(h("Мир")) # Привет, Мир!

Полезно, когда хочется сделать объекты лаконичными. Можно даже прокидывать параметры как в обычной функции.

✔️ Теперь __getitem__

Позволяет обращаться к объекту через квадратные скобки:
class SecretBox:
def __getitem__(self, key):
return f"🔒 Внутри: {key}"

box = SecretBox()
print(box["password"]) # 🔒 Внутри: password

Ты можешь использовать это для красивого синтаксиса без точек и скобок.

🤝 Комбинируем в DSL
class SQL:
def __call__(self, table):
return f"SELECT * FROM {table}"

def __getitem__(self, field):
return f'"{field}"'

q = SQL()

print(q("users")) # SELECT * FROM users
print(q["email"]) # "email"

Теперь у нас объект, который и вызывает таблицу, и красиво оформляет поля.

🧪 Более мощный пример: API-доступ
class API:
def __init__(self, base):
self.base = base

def __getitem__(self, endpoint):
return f"{self.base}/{endpoint}"

def __call__(self, endpoint, **params):
query = "&".join(f"{k}={v}" for k, v in params.items())
return f"{self.base}/{endpoint}?{query}"

api = API("https://api.server")

print(api["users"]) # https://api.server/users
print(api("users", id=5, active=True)) # https://api.server/users?id=5&active=True

Такой подход часто используют в клиентах к REST API, чтобы код выглядел как естественный DSL.

🧰 А можно вообще без классов?
class K:
def __getitem__(self, key):
return lambda d: d.get(key)

k = K()
data = {"name": "Neo", "role": "Hacker"}

print(k["name"](data)) # Neo
print(k["role"](data)) # Hacker

Так строятся мини-функции доступа к полям. Особенно круто в map/filter.

🗣️ Запомни: __call__ и __getitem__ — это способ превратить скучные объекты в выразительный синтаксис. Так строятся мини-языки прямо в Python: понятные, компактные и без лишнего шума.
Please open Telegram to view this post
VIEW IN TELEGRAM
1
⚡️ functools.cache вместо самодельного мемо — просто и эффективно

Зачем писать свои кеши, если Python уже умеет это из коробки?
С версии 3.9 появился @cache — аналог lru_cache, но проще и быстрее, если тебе не нужен лимит.

Было так (ручной мемо):
_cache = {}

def fib(n):
if n in _cache:
return _cache[n]
if n <= 1:
return n
_cache[n] = fib(n-1) + fib(n-2)
return _cache[n]

🧠 Работает, но нужно писать проверку, хранить словарь, вручную всё продумывать.

🔄 А теперь просто:
from functools import cache

@cache
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)

👏 Всё! Автоматически кеширует, ничего лишнего не пишем.

📌 Отличия от @lru_cache
from functools import lru_cache, cache

🟢 @lru_cache: можно задать размер (maxsize), есть контроль
🟢 @cache: просто бесконечный кеш всех входов → выходов

Если не нужна "очистка", бери @cache — он быстрее и проще.

🧪 Пример с реальным использованием:
from functools import cache
import requests

@cache
def get_user_info(user_id):
print("Запрос к API...")
return requests.get(f"https://api.example.com/users/{user_id}").json()

get_user_info(42) # Выполнит запрос
get_user_info(42) # Возьмёт из кеша


➡️ Отлично для API, парсинга, тяжёлых вычислений.

🗣️ Запомни: @functools.cache — это твой встроенный кеш без лишнего кода.
Хорош для любых чистых функций, где важна скорость и повторяемость.
Не изобретай велосипед — используй cache.
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍3
👩‍💻 Антипаттерны в Python-коде, которые встречаются даже у опытных

Даже опытные разработчики пишут код, который потом сложно читать, отлаживать и сопровождать. Вот 5 антипаттернов, которые встречаются особенно часто — и что с ними делать.

1. Мутируемые значения по умолчанию
def append_item(item, items=[]):
items.append(item)
return items


Ошибка — items сохраняет состояние между вызовами. Итог — неожиданные данные.

Правильно:
def append_item(item, items=None):
if items is None:
items = []
items.append(item)
return items


2. Импорт всего (`from module import *`)

Так ты теряешь контроль над namespace и рискуешь конфликтами имён. Особенно опасно в больших проектах.

Лучше явно:
from math import sqrt, pi


3. Голый `except:`
try:
do_something()
except:
pass


Так можно «поймать» даже KeyboardInterrupt, и программа зависнет.

✔️ Лучше:
try:
do_something()
except ValueError:
handle()


4. Чрезмерно вложенные list comprehensions

[x for x in lst if x > 0 if x < 100 if x % 2 == 0]


Читаемость? Нулевая.

Явный цикл:
result = []
for x in lst:
if 0 < x < 100 and x % 2 == 0:
result.append(x)


5. Копирование ссылок на изменяемые объекты
data = [{}] * 3
data[0]["a"] = 1
print(data)


Ожидаешь три разных словаря? А получил три ссылки на один и тот же.

Делай так:
data = [{} for _ in range(3)]


🗣️ Запомни: даже если код "работает", это не значит, что он хорош. Следи за чистотой — антипаттерны незаметны, но со временем превращают проект в хаос.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32
🖥 Как отсортировать список словарей по определенному полю?

Метод списка .sort() и встроенная функция sorted() принимают параметр key. Им должен быть вызываемый объект, который принимает очередной элемент (в нашем случае словарь) и возвращает значение-критерий сортировки.

Код ниже показывает, как отсортировать список людей по возрасту:

users = [{'age': 30}, {'age': 20}, {'age': 10}]
users.sort(key=lambda user: user['age'])
>>> [{'age': 10}, {'age': 20}, {'age': 30}]
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
👩‍💻 *args и **kwargs: гибкие параметры без боли

Иногда ты не знаешь заранее, сколько аргументов получит твоя функция. Python даёт тебе две магические конструкции для таких случаев — *args и **kwargs.

📌*args собирает все позиционные аргументы в кортеж:

def add_all(*args):
return sum(args)

add_all(1, 2, 3) # ➡️ 6


📌 **kwargs собирает все именованные аргументы в словарь:

def print_config(**kwargs):
for k, v in kwargs.items():
print(f"{k} = {v}")

print_config(debug=True, timeout=10)
# ➡️ debug = True
# ➡️ timeout = 10


🔥Комбинируем всё:

def func(a, b, *args, **kwargs):
pass

➡️ a и b — обязательные, args — остальные позиционные, kwargs — именованные.

🧠 Применения:

1. Проксирование аргументов
Ты вызываешь другую функцию, не зная её сигнатуру:

   def wrapper(*args, **kwargs):
return real_func(*args, **kwargs)


2. Гибкий API без переписывания сигнатур

Вместо:
   def create_user(name, email, age, is_admin=False):
...


Можно:
   def create_user(**kwargs):
...


3. Расширение без поломки интерфейса

У тебя есть базовый метод:

   def process(data, **kwargs):
...


➡️ В будущем можно спокойно добавить флаги, не меняя вызовы.


🗣️ Запомни: *args и **kwargs — это про гибкость и масштабируемость. Главное — использовать их осознанно: когда действительно нужно, а не “на всякий случай”.

📍Где применяется:
Декораторы, middleware, логгеры, фреймворки (Django, Flask), адаптеры, кастомные API, генераторы CLI-интерфейсов.
Please open Telegram to view this post
VIEW IN TELEGRAM
2💯1
👩‍💻 Как работает collections.Counter?

Counter — это удобный инструмент для подсчета элементов в коллекции.
Не обязательно писать цикл и вручную считать каждый элемент 👇

➡️ Пример:


from collections import Counter

data = "aabbbcccc"
counter = Counter(data)
print(counter) # Counter({'c': 4, 'b': 3, 'a': 2})


✔️ Можно использовать для нахождения самых частых элементов:


print(counter.most_common(2)) # [('c', 4), ('b', 3)]


⚙️ Также работает со списками:


words = ["apple", "banana", "apple", "orange", "banana", "banana"]
print(Counter(words)) # {'banana': 3, 'apple': 2, 'orange': 1}


🔥 Counter особенно полезен для:
— анализа текста
— подсчёта слов
— статистики
— обработки данных
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
🖥 Как повторить строку несколько раз

В Python для этого не нужен цикл 👇


text = "Python! "

print(text * 3)


👉 Результат:

Python! Python! Python!


💡 То же самое работает со списками:

nums = [1, 2]

print(nums * 3)


Получим:

[1, 2, 1, 2, 1, 2]


🔥 Это удобно, когда нужно быстро создать повторяющуюся строку или последовательность.

⚠️ Но со списками есть нюанс: элементы не копируются глубоко - для вложенных изменяемых объектов это может привести к неожиданному поведению.
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1