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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
👟 pip + venv: ставим библиотеки изолированно — и это работает

venv делает песочницу для проекта.
pip ставит пакеты внутрь неё.
Активировал окружение — и весь мир пакетов идёт в твою папку, а не в систему.

📦 Шаг 1 — создай окружение в корне проекта
# Windows
py -m venv .venv
# macOS / Linux
python3 -m venv .venv

➡️ Появится папка .venv — там свой Python и свой pip.

🔑 Шаг 2 — активируй окружение
# PowerShell
.\.venv\Scripts\Activate.ps1
# cmd
.\.venv\Scripts\activate.bat
# macOS / Linux
source .venv/bin/activate

➡️ Подсказка терминала сменится на (.venv) — ты внутри.

⚙️ Шаг 3 — обнови pip (сначала всегда так)
python -m pip install --upgrade pip

➡️Берёшь свежую версию установщика, меньше странных ошибок.

📥 Шаг 4 — ставь библиотеки
pip install requests
pip install "uvicorn[standard]" fastapi

➡️ Всё уезжает в .venv. Глобальная система не трогается.

🔎 Шаг 5 — смотри, что внутри
pip list
pip show requests

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

🧾 Шаг 6 — фиксируй зависимости
pip freeze > requirements.txt

➡️ Снимок версий. Его же можно отдать коллегам или CI.

🚚 Шаг 7 — восстановление на другой машине
# в новом клоне проекта
python -m venv .venv
# активируй (как в Шаге 2)
pip install -r requirements.txt

➡️ Получишь те же версии пакетов, что и у автора.

🧪 Проверка — пакет реально в venv
python -c "import requests, sys; print(sys.prefix)"

➡️ Должен увидеть путь к твоему .venv. Значит всё изолировано.

🧹 Шаг 8 — удаление/выход
pip uninstall requests
deactivate

➡️ deactivate возвращает тебя в глобальную среду.

🛠 Быстрые фишки (когда что-то идёт не так)
# pip "не находится" — запускай через интерпретатор
python -m pip --version

# несколько Python — выбери конкретный
# Windows:
py -3.11 -m venv .venv
# macOS / Linux:
python3.11 -m venv .venv

# PowerShell ругается на Activate.ps1:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

➡️ Унификация через python -m pip и явный выбор версии решают 90% проблем.

🗂 Бонус — не коммить venv
echo .venv/ >> .gitignore

➡️ Окружение — локальное. В репо нужен только requirements.txt.

🗣️ Запомни: venv — граница проекта, pip — грузовик с пакетами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
🖥 Чем список отличается от кортежа?

Списки – это изменяемые последовательности, обычно используемые для хранения однотипных данных (хотя Python не запрещает хранить в них данные разных типов). Представлены классом list.

Кортежи – это неизменяемые последовательности, обычно используемые, чтобы хранить разнотипные данные. Представлены классом tuple.

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

Существуют специальные функции для работы со списками. Они вызываются методами списка. Ниже приведены наиболее часто используемые:


# Создаем исходный список
lst = [1, 2, 3]

# append(x): добавляет элемент в конец списка
lst.append(4)
# Теперь lst = [1, 2, 3, 4]

# extend(iterable): расширяет список, добавляя элементы из итерируемого объекта
lst.extend([5, 6])
# Теперь lst = [1, 2, 3, 4, 5, 6]

# insert(i, x): вставляет элемент x на позицию i
lst.insert(0, 'start')
# Теперь lst = ['start', 1, 2, 3, 4, 5, 6]

# remove(x): удаляет первое вхождение элемента x
lst.remove(3)
# Теперь lst = ['start', 1, 2, 4, 5, 6]

# pop([i]): удаляет и возвращает элемент на позиции i (по умолчанию последний)
last = lst.pop()
# last = 6, а lst = ['start', 1, 2, 4, 5]

# sort(): сортирует список на месте
lst = [3, 1, 4, 1, 5, 9, 2]
lst.sort()
# Теперь lst = [1, 1, 2, 3, 4, 5, 9]

# reverse(): разворачивает список на месте
lst.reverse()
# Теперь lst = [9, 5, 4, 3, 2, 1, 1]
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2
🐍 Как распаковать список прямо в аргументы функции

В Python можно передать список как отдельные аргументы с помощью * 👇

def add(a, b, c):
print(a + b + c)

nums = [1, 2, 3]

add(*nums)


👉 Результат:

6


💡 Что происходит:

add(*nums)


Python превращает это в:

add(1, 2, 3)


📌 Работает и с кортежами:

coords = (10, 20)

print(*coords)


🔥 Очень полезно при:
— работе с функциями
— динамических данных
— распаковке API-ответов

🚀 *args и распаковка - одна из самых удобных фишек Python

#python #фишки
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52
🖥 Что делает 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