В Python методы — это не всегда просто
def. Есть специальные декораторы, которые меняют то, как ты работаешь с логикой класса. С ними код чище, а интерфейс удобнее.Нужен, когда хочешь, чтобы метод выглядел как обычное поле, но с вычислением «на лету».
class User:
def __init__(self, name):
self._name = name
@property
def name(self):
print("📡 Получаем имя...")
return self._name.title()
u = User("ivan")
print(u.name) # 📡 Получаем имя... → Ivan
📛 Можно ещё добавить setter:
@name.setter
def name(self, value):
if not value:
raise ValueError("❌ Имя не может быть пустым")
self._name = value
u.name = "Petr" вызовет логику проверки, а не просто присвоение.Передаёт в первый аргумент
cls — сам класс. Отлично подходит для альтернативных конструкторов.class Product:
def __init__(self, name):
self.name = name
@classmethod
def from_dict(cls, data):
return cls(data["name"])
p = Product.from_dict({"name": "Laptop"})
print(p.name) # Laptop
__init__, всё скрыто за понятным методом.@classmethod
def default(cls):
return cls("Default Product")
Обычная функция внутри класса, не знающая про
self и cls.class MathUtils:
@staticmethod
def add(a, b):
return a + b
print(MathUtils.add(2, 3)) # 5
📛 Пример с валидацией:
class Temperature:
@staticmethod
def is_valid(value):
return -273.15 <= value
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
@property
def fahrenheit(self):
return (self.celsius * 9 / 5) + 32
@classmethod
def from_fahrenheit(cls, f):
return cls((f - 32) * 5 / 9)
@staticmethod
def is_valid(value):
return -273.15 <= value
👍 property — вычисляет по формуле👍 classmethod — создаёт объект из другой шкалы👍 staticmethod — проверяет, что температура физически возможна
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2⚡1
Когда код ждёт — ты теряешь время. Асинхронность позволяет работать с тысячами задач одновременно, не создавая кучу потоков. Это особенно круто в сетевых приложениях: боты, API, парсеры, чаты.
Вместо того чтобы блокироваться на ожидании, Python "прыгает" между задачами.
import asyncio
async def task(name, delay):
await asyncio.sleep(delay)
print(f"✅ Задача {name} выполнена")
async def main():
await asyncio.gather(
task("A", 2),
task("B", 1),
task("C", 3)
)
asyncio.run(main())
📛 Основные приёмы:
🟢 async def — объявление асинхронной функции🟢 await — «подожди» и уступи управление🟢 asyncio.gather() — запусти несколько задач параллельно
Отличается от
requests тем, что не блокирует поток.import aiohttp
import asyncio
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
return await resp.text()
async def main():
urls = [
"https://example.com",
"https://httpbin.org/get",
"https://python.org"
]
results = await asyncio.gather(*(fetch(u) for u in urls))
for i, html in enumerate(results, 1):
print(f"📄 Страница {i}: {len(html)} символов")
asyncio.run(main())
from aiohttp import web
async def handle(request):
return web.Response(text="👋 Привет, async!")
app = web.Application()
app.router.add_get("/", handle)
web.run_app(app, port=8080)
🟢 Чат-серверы и мессенджеры🟢 Парсинг тысяч страниц🟢 API с большим количеством одновременных клиентов🟢 Боты, которые делают много запросов
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4⚡1
Если в коде нет логов — ты как пилот без приборов. Ошибка случилась, баг вылез, сервер упал — и ты гадаешь на кофейной гуще.
logging в Python — это встроенный инструмент, который позволяет фиксировать всё важное и разбирать полёты, когда что-то идёт не так.🖋 Простой старт — замена print()
Наивно:
print("Starting app...")Правильно:
import logging
logging.basicConfig(level=logging.INFO)
logging.info("Starting app...")
INFO) и метка времени.В
logging есть 5 уровней:🟢 DEBUG — подробности для разработчика🟢 INFO — обычные события🟢 WARNING — что-то подозрительное🟢 ERROR — ошибка, но программа ещё жива🟢 CRITICAL — всё очень плохо
logging.debug("Запрос к API")
logging.warning("Медленный ответ от сервера")
logging.error("База данных недоступна")logging.basicConfig(
filename="app.log",
filemode="a",
format="%(asctime)s %(levelname)s:%(message)s",
level=logging.INFO
)
logging.info("Сервер запущен")
app.log с датой, временем и уровнем.FORMAT = "%(levelname)s | %(name)s | %(message)s"
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
log = logging.getLogger("billing")
log.info("Начало операции")
log.error("Ошибка списания средств")
billing, auth, db) и видеть источник.try:
1 / 0
except ZeroDivisionError:
logging.exception("Деление на ноль!")
logging.exception сам добавит traceback, не надо руками печатать traceback.print_exc().✔️ Для больших проектов делай конфиг через logging.config или YAML✔️ Разделяй логи по файлам: error.log, access.log, debug.log✔️ Не логируй пароли и токены — логи часто попадают в чужие руки✔️ Логи с ротацией (RotatingFileHandler) спасут диск от забивания
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3👏2⚡1🔥1💯1
Media is too big
VIEW IN TELEGRAM
Это видео объясняет, как использовать условные операторы в Python для принятия решений в коде. Вы узнаете, как проверять условия с помощью if, обрабатывать альтернативные варианты с elif и задавать действия по умолчанию с else.
Пример:
age = int(input("Введите ваш возраст: "))
if age < 18:
print("Вы молоды!")
elif age < 60:
print("Вы в расцвете сил!")
else:
print("Вы мудры и опытны!")Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🔥3👎1
Когда нужно подтянуть данные из стороннего сервиса или автоматизировать работу с платформой, Python и HTTP-запросы — идеальный инструмент.
Отправляем запрос → получаем JSON → используем в коде.
pip install requests
requests — самая популярная библиотека для работы с HTTP в Python. Простая и надёжная.import requests
url = "https://api.github.com/repos/psf/requests"
response = requests.get(url)
data = response.json()
print(data["full_name"], data["stargazers_count"])
payload = {"name": "test_repo", "private": True}
headers = {"Authorization": "token YOUR_GITHUB_TOKEN"}
r = requests.post("https://api.github.com/user/repos", json=payload, headers=headers)
print(r.status_code)from requests_oauthlib import OAuth2Session
oauth = OAuth2Session(client_id="...", redirect_uri="https://mysite.com/callback")
authorization_url, state = oauth.authorization_url("https://service.com/oauth/authorize")
print("Открой:", authorization_url)
📡 Обработка ошибок и таймаутов
try:
r = requests.get(url, timeout=5)
r.raise_for_status()
except requests.exceptions.RequestException as e:
print("Ошибка:", e)
raise_for_status() ловит ошибки HTTP.import aiohttp, asyncio
async def fetch(session, url):
async with session.get(url) as resp:
return await resp.json()
async def main():
async with aiohttp.ClientSession() as session:
data = await fetch(session, "https://api.github.com")
print(data)
asyncio.run(main())
aiohttp позволяет стучаться к API в десятки раз быстрее при большом количестве запросов.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7⚡1
Python умеет работать без блокировок — и это не только про скорость, а про масштабируемость.
asyncio — движок планирования задач.aiohttp — асинхронный HTTP-инструмент, построенный на asyncio.🌀 Пример: чистый
asyncioimport asyncio
async def task(name, delay):
await asyncio.sleep(delay)
print(f"✅ {name} завершена")
async def main():
await asyncio.gather(
task("A", 2),
task("B", 1)
)
asyncio.run(main())
aiohttp для загрузки страницimport aiohttp, asyncio
async def fetch(url):
async with aiohttp.ClientSession() as s:
async with s.get(url) as r:
return await r.text()
async def main():
urls = ["https://example.com", "https://python.org"]
html_list = await asyncio.gather(*(fetch(u) for u in urls))
print(f"📄 Загружено {len(html_list)} страниц")
asyncio.run(main())
async def get_data():
async with aiohttp.ClientSession() as s:
async with s.get("https://api.github.com") as r:
return await r.json()
print(asyncio.run(get_data()))
aiohttpfrom aiohttp import web
async def handle(req):
return web.Response(text="👋 Привет, async!")
app = web.Application()
app.router.add_get("/", handle)
web.run_app(app, port=8080)
📦 Как работают вместе
👍 asyncio — отвечает за переключение задач.👍 aiohttp — берёт это переключение и добавляет HTTP-клиент + сервер.
asyncio — это фундамент, aiohttp — инструмент на нём. Первое даёт параллелизм, второе — готовые HTTP-решения. Вместе — реактивный, быстрый и масштабируемый Python.Please open Telegram to view this post
VIEW IN TELEGRAM
❤4⚡1👍1
Media is too big
VIEW IN TELEGRAM
Это видео объясняет, как работать с базовым вводом и выводом в Python. Рассказывается, как вывести текст через print(), получить данные от пользователя с помощью input(), и как преобразовать строки в числа.
Подойдёт новичкам, которые только начинают писать интерактивные скрипты и хотят понять, как общаться с пользователем в консоли.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4⚡1
enumerate(): когда нужен индекс и значениеЧасто надо итерироваться по списку, но при этом иметь доступ и к индексу, и к элементу?
Забудь про
range(len(...)) — используй enumerate().names = ["Alice", "Bob", "Charlie"]
for i, name in enumerate(names):
print(f"{i}: {name}")
enumerate возвращает кортеж (индекс, значение) — и читаемо, и безопасно.for i, item in enumerate(items, start=1):
print(f"{i}. {item}")
for i, line in enumerate(file):
if "TODO" in line:
print(f"{i}: {line.strip()}")
# ❌ Не питонично:
for i in range(len(data)):
print(data[i])
# ✅ Лучше:
for i, value in enumerate(data):
print(value)
enumerate исключает ошибки с индексами, повышает читаемость.enumerate() — лучший способ, если тебе одновременно нужен индекс и значение. Код получается чище, безопаснее и читаемее.Парсинг, UI-выводы, CLI-меню, обработка строк, файлов и логов, генерация таблиц, аналитика, отладка, фильтрация по позиции.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2⚡1
В Python можно оставить комментарий — и он исчезнет при запуске.
Но если ты напишешь строку в
"""кавычках""" под def или class, она останется.Это не текст для людей. Это часть объекта.
📛 Пример: функция с docstring
def add(a, b):
"""➕ Складывает два числа."""
return a + b
print(add.__doc__)
# ➕ Складывает два числа.
Docstring — встроенная документация, доступная прямо из кода.
help()
help(add)
def square(x):
"""
Возвращает квадрат числа.
>>> square(3)
9
"""
return x * x
python -m doctest file.py — и пример из docstring превратится в тест.
"""📜 Этот модуль работает с пользователями."""
class User:
"""👤 Представляет юзера."""
def greet(self):
"""💬 Возвращает приветствие."""
return "Hello!"
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9⚡1
👟
Активировал окружение — и весь мир пакетов идёт в твою папку, а не в систему.
📦 Шаг 1 — создай окружение в корне проекта
➡️ Появится папка
🔑 Шаг 2 — активируй окружение
➡️ Подсказка терминала сменится на
⚙️ Шаг 3 — обнови pip (сначала всегда так)
➡️ Берёшь свежую версию установщика, меньше странных ошибок.
📥 Шаг 4 — ставь библиотеки
➡️ Всё уезжает в
🔎 Шаг 5 — смотри, что внутри
➡️ Видишь только пакеты твоего окружения, не всей машины.
🧾 Шаг 6 — фиксируй зависимости
➡️ Снимок версий. Его же можно отдать коллегам или CI.
🚚 Шаг 7 — восстановление на другой машине
➡️ Получишь те же версии пакетов, что и у автора.
🧪 Проверка — пакет реально в
➡️ Должен увидеть путь к твоему
🧹 Шаг 8 — удаление/выход
➡️
🛠 Быстрые фишки (когда что-то идёт не так)
➡️ Унификация через
🗂 Бонус — не коммить
➡️ Окружение — локальное. В репо нужен только
🗣️ Запомни:
pip + venv: ставим библиотеки изолированно — и это работаетvenv делает песочницу для проекта.pip ставит пакеты внутрь неё.Активировал окружение — и весь мир пакетов идёт в твою папку, а не в систему.
# Windows
py -m venv .venv
# macOS / Linux
python3 -m venv .venv
.venv — там свой Python и свой pip.# PowerShell
.\.venv\Scripts\Activate.ps1
# cmd
.\.venv\Scripts\activate.bat
# macOS / Linux
source .venv/bin/activate
(.venv) — ты внутри.python -m pip install --upgrade pip
pip install requests
pip install "uvicorn[standard]" fastapi
.venv. Глобальная система не трогается.🔎 Шаг 5 — смотри, что внутри
pip list
pip show requests
🧾 Шаг 6 — фиксируй зависимости
pip freeze > requirements.txt
# в новом клоне проекта
python -m venv .venv
# активируй (как в Шаге 2)
pip install -r requirements.txt
venvpython -c "import requests, sys; print(sys.prefix)"
.venv. Значит всё изолировано.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% проблем.venvecho .venv/ >> .gitignore
requirements.txt.venv — граница проекта, pip — грузовик с пакетами.Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2⚡1🔥1👏1
Media is too big
VIEW IN TELEGRAM
В этом видео автор объясняет, как в Python работают основные структуры данных: списки (lists), кортежи (tuples), множества (sets) и словари (dictionaries).
Пошагово показано, как создавать каждую структуру, в чём их отличие и в каких случаях стоит использовать именно их — удобно хранить, повторять или быстро искать данные.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3⚡1
Если у тебя Python-сервис начинает «тормозить» из-за тяжёлых операций (отправка почты, обработка файлов, запросы к API) — не надо делать
time.sleep(999). Всё это можно вынести в фон через Celery.Celery = таски + брокер сообщений (Redis или RabbitMQ) + воркеры, которые жрут эти таски.
pip install celery[redis]
pip install redis
# или если брокер RabbitMQ:
# pip install celery[rabbitmq]
# tasks.py
from celery import Celery
app = Celery(
"my_app",
broker="redis://localhost:6379/0", # Redis
backend="redis://localhost:6379/0" # для хранения результата
)
@app.task
def add(x, y):
return x + y
Запускаем воркера:
celery -A tasks worker --loglevel=info
В другом файле:
from tasks import add
result = add.delay(4, 6) # отправляем в очередь
print(result.get()) # ждем выполнения → 10
📛 RabbitMQ вместо Redis
RabbitMQ — более надёжный брокер, с очередями и персистентностью.
Просто меняем конфиг:
app = Celery("my_app", broker="pyamqp://guest@localhost//")Celery умеет сам повторять таску при сбое:
@app.task(bind=True, max_retries=3, default_retry_delay=5)
def fragile_task(self, url):
try:
# какая-то логика
return "ok"
except Exception as exc:
raise self.retry(exc=exc) # автоматический retry
Можно запускать таски по расписанию:
from celery.schedules import crontab
app.conf.beat_schedule = {
"clear-cache-every-night": {
"task": "tasks.clear_cache",
"schedule": crontab(hour=3, minute=0), # каждый день в 03:00
},
}
Запускаем:
celery -A tasks beat
🟢 Redis — проще, быстрее поднять, но хуже с очень тяжёлой нагрузкой.🟢 RabbitMQ — надёжнее, умнее с очередями (ack, приоритеты, персистентность).🟢 Celery умеет параллельные воркеры, пулы процессов/потоков.
🟢 .delay() — отправка таски асинхронно🟢 .apply_async(countdown=10) — отложить на 10 секунд🟢 .get(timeout=5) — дождаться результата с таймаутом🟢 Результаты можно хранить не только в Redis, но и в SQL, Mongo, S3
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2🔥1👏1
SQL — это язык запросов к базе.
ORM (Object–Relational Mapping) — это прослойка: вместо "писать руками SQL" ты работаешь с объектами.
Python делает это через SQLAlchemy или Django ORM.
import sqlite3
conn = sqlite3.connect("app.db")
cur = conn.cursor()
cur.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
cur.execute("INSERT INTO users (name) VALUES (?)", ("Alice",))
conn.commit()
cur.execute("SELECT * FROM users")
print(cur.fetchall())
SQLAlchemy (пример на SQLite):
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, Session
engine = create_engine("sqlite:///app.db")
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
Base.metadata.create_all(engine)
# работа через объекты
with Session(engine) as session:
session.add(User(name="Alice"))
session.commit()
users = session.query(User).all()
print([u.name for u in users])
models.py в Django-проекте:from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
app_user.Создание и запросы:
User.objects.create(name="Alice")
users = User.objects.all()
print([u.name for u in users])
SQLAlchemy:
users = session.query(User).filter(User.name == "Alice").all()
Django ORM:
users = User.objects.filter(name="Alice")
SELECT * FROM users WHERE name='Alice'SQLAlchemy:
from sqlalchemy.orm import relationship, Mapped, mapped_column, DeclarativeBase
class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True)
title = Column(String)
user_id = Column(Integer, ForeignKey("users.id"))
user = relationship("User", back_populates="posts")
User.posts = relationship("Post", back_populates="user")
user.posts даст список постов, а post.user вернёт автора.Django:
class Post(models.Model):
title = models.CharField(max_length=100)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
user.posts.all() и post.user работают как магия.🟢 SQLAlchemy: через Alembic (alembic revision --autogenerate)🟢 Django: встроенные миграции (python manage.py makemigrations && migrate)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4⚡2👏2
🔠 Type Hints: код говорит за тебя
Python — динамический, можешь писать без типов.
Но с аннотациями
Типы не проверяются в рантайме — но помогают читать, дебажить и ловить ошибки раньше.
📛 Пример: аннотации в функции
➡️ В рантайме работает так же.
Но теперь IDE и mypy понимают: на входе и выходе только числа.
🧪 Комбинации типов
➡️ Python по-прежнему не строгий.
Но твой код стал декларативным: видно, что ждёт функция.
📦 Опциональные значения
➡️ Без
А с
🔐 Собственные типы
➡️
но для анализатора — это разные сущности.
🪄 Магия PEP 604 (Python 3.10+)
➡️ Больше не нужно
Теперь типы можно писать через
🗣️ Запомни: type hints — это декларация смысла, а не ограничение.
Python — динамический, можешь писать без типов.
Но с аннотациями
: int, : str код начинает сам себя документировать.Типы не проверяются в рантайме — но помогают читать, дебажить и ловить ошибки раньше.
📛 Пример: аннотации в функции
def add(a: int, b: int) -> int:
return a + b
Но теперь IDE и mypy понимают: на входе и выходе только числа.
🧪 Комбинации типов
from typing import List, Dict
def users_to_dict(users: List[str]) -> Dict[str, int]:
return {u: len(u) for u in users}
Но твой код стал декларативным: видно, что ждёт функция.
📦 Опциональные значения
from typing import Optional
def find_user(id: int) -> Optional[str]:
if id == 0:
return None
return "admin"
if value is None не разберёшься.А с
Optional всё ясно из сигнатуры.
from typing import NewType
UserId = NewType("UserId", int)
def get_user(id: UserId) -> str:
return f"user-{id}"
UserId и int одинаковы в рантайме,но для анализатора — это разные сущности.
def foo(x: int | str) -> None:
...
Union.Теперь типы можно писать через
|.Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍3🔥3⚡1👎1🍌1
This media is not supported in your browser
VIEW IN TELEGRAM
while, Операторы break и continueВ этом видео автор подробно объясняет, как работает цикл while в Python.
Разбираются операторы break и continue, показано, как с их помощью управлять выполнением цикла. Всё демонстрируется на простых примерах, что помогает легко понять и применить эти конструкции на практике.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥6❤1
🧵
zip() объединяет несколько итерируемых объектов в кортежи по элементам.names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f"{name}: {score}")
Alice: 85
Bob: 92
Charlie: 78
-
zip останавливается по самому короткому из входов. - Можно “распаковать” с помощью
zip(*iterables).pairs = [("a", 1), ("b", 2)]
letters, numbers = zip(*pairs)
print(letters) # ('a', 'b')Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤3⚡2👍1
Ты написал:
def greet(name):
print(f"Привет, {name}!")
А потом захотел добавить логирование, проверку ошибок или права доступа. Переписывать код не хочется.
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Вызов {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_decorator
def greet(name):
print(f"Привет, {name}!")
greet("Анна")
greet осталась чистой, логика вынесена наружу.def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def hello():
print("👋 Привет")
hello()
hello() вызывается 3 раза подряд.⚠️ Без
functools.wraps теряется имя функцииfrom functools import wraps
def safe(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print("Ошибка:", e)
return wrapper
@safe
def divide(a, b):
return a / b
@wraps сохраняет имя и docstring, иначе функция станет просто wrapper.def require_admin(func):
def wrapper(user, *args, **kwargs):
if not user.get("is_admin"):
raise PermissionError("⛔️ Нет доступа")
return func(user, *args, **kwargs)
return wrapper
@require_admin
def delete_user(user, uid):
print(f"Удалён {uid}")
@safe
def risky(x):
return 10 / x
risky(0) # Ошибка перехвачена
@safe
@log_decorator
def risky_op(x):
return 10 / x
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥3⚡1
__str____repr__ : зачем два разных отображения объектаВ Python у любого объекта можно определить два разных способа отображения —
__str__ и __repr__. Кажется избыточным, но на деле это основа читаемости и отладки.Разберём всё по полочкам
class User:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Пользователь {self.name}"
u = User("Иван")
print(u) # Пользователь Иван
__str__ нужен для красивого вывода в консоли, логах или интерфейсе. Его цель — понятность.class User:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"User(name={self.name!r})"
u = User("Иван")
print(repr(u)) # User(name='Иван')
__repr__ всегда должен быть однозначным. Его читают программисты и дебаггер, а не пользователи.repru = User("Иван")
u__repr__. Поэтому именно он важен для отладки.📑 Логи: str для людей, repr для разработчиков
print(str(u)) # Пользователь Иван
print(repr(u)) # User(name='Иван')
class Item:
def __repr__(self):
return "Item(id=42)"
i = Item()
print(i) # Item(id=42)
__repr__, если __str__ не определён. Но наоборот — не работает.class Product:
def __init__(self, name, price):
self.name, self.price = name, price
def __repr__(self):
return f"Product({self.name!r}, {self.price})"
__str__ = __repr__ # одинаковый вывод
🟢 __repr__ должен быть «однозначным» (по возможности — похож на конструктор).🟢 __str__ должен быть «дружелюбным» — читаться как текст.🟢 Если сомневаешься — реализуй хотя бы __repr__.
str → для пользователя, repr → для разработчика.В консоли, дебаге и коллекциях срабатывает именно repr.Грамотное разделение делает код удобнее и чище, а логи — понятнее.Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3🔥2⚡1👏1
UnboundLocalError ломает кодВ Python переменные живут в разных областях видимости: локальной (функция), глобальной (модуль), и встроенной (
len, print, и т. д.).Новички часто сталкиваются с
UnboundLocalError — когда кажется, что переменная доступна, но интерпретатор думает иначе.
x = 10
def foo():
print(x) # 🔴 UnboundLocalError
x = 5
foo()
x = 5 и считает, что x — локальная переменная. Но до присвоения её нет, поэтому ошибка.
x = 10
def foo():
global x
print(x) # ✅ 10
x = 5
foo()
print(x) # 5
x.nonlocal
def outer():
x = 10
def inner():
x = x + 1 # 🔴 UnboundLocalError
return x
return inner()
outer()
x в inner — локальная, а к замыканию он не обращается.nonlocal
def outer():
x = 10
def inner():
nonlocal x
x = x + 1
return x
return inner()
print(outer()) # ✅ 11
nonlocal говорит: используй переменную из внешней функции.
def make_counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return inc
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
nonlocal счётчик всегда бы начинался с нуля.global и nonlocal?🟢 global — когда нужно изменять переменные уровня модуля (например, конфиг или кеш).🟢 nonlocal — когда пишешь вложенные функции и нужно работать с переменными из внешней, а не создавать новые.
users = []
def add_user(name):
users.append(name) # ✅ работает без global
global не нужен.UnboundLocalError = Python думает, что переменная локальная. Используй global для изменения глобальных переменных, nonlocal — для замыканий. Избегай глобалок: они делают код запутанным. Лучше возвращать значения и передавать их явно.Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3⚡2
В Python есть два типа объектов: immutable (строки, числа, кортежи) и mutable (списки, словари, множества).
Разница кажется очевидной, пока не сталкиваешься с функциями и дефолтными аргументами.
def add_item(item, bucket=[]):
bucket.append(item)
return bucket
print(add_item("🍎")) # ['🍎']
print(add_item("🍌")) # ['🍎', '🍌'] ❌
Python вычисляет значения аргументов по умолчанию при определении функции, а не при каждом вызове.
То есть bucket=[] создаётся один раз и живёт всё время жизни функции.
None
def add_item(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
print(add_item("🍎")) # ['🍎']
print(add_item("🍌")) # ['🍌']
def register_user(name, db={}):
db[name] = True
return db
print(register_user("Alice")) # {'Alice': True}
print(register_user("Bob")) # {'Alice': True, 'Bob': True} ❌
None:
def register_user(name, db=None):
if db is None:
db = {}
db[name] = True
return db
Иногда специально используют «общий объект по умолчанию»:
def cache_query(query, cache={}):
if query in cache:
return cache[query]
result = f"Выполнил {query}"
cache[query] = result
return result
def add_one(x=0):
return x + 1
print(add_one()) # 1
print(add_one()) # 1
arg=None, потом if arg is None: arg = []. Исключение — если тебе нужен общий объект (например, кеш).Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤4⚡2
yield: как делать ленивые вычисления и экономить памятьОбычные функции в Python возвращают всё сразу. Генераторы — по частям. Это «ленивые» вычисления: результат отдаётся только тогда, когда он нужен. Экономия памяти и скорость работы на больших данных становятся колоссальными.
yield
def numbers():
yield 1
yield 2
yield 3
for n in numbers():
print(n)
def read_file(path):
with open(path, "r") as f:
for line in f:
yield line.strip()
for line in read_file("big.log"):
print(line)
def counter(start=0):
while True:
yield start
start += 1
for n in counter():
if n > 5:
break
print(n)
def numbers():
for i in range(10):
yield i
def squared(seq):
for x in seq:
yield x * x
for x in squared(numbers()):
print(x)
squares = (x*x for x in range(1_000_000))
print(next(squares)) # 1
print(next(squares)) # 4
🟢 обработка логов и CSV гигабайтного размера;🟢 потоковые данные (сокеты, API);🟢 построение бесконечных последовательностей;🟢 конвейеры обработки (map/filter без лишних списков).
yield отдаёт результат по частям, не занимая память. Генераторы можно объединять в цепочки — как трубы. Если данных много или они бесконечны — только генераторы спасут.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7🤝3❤2