PytStart | Программирование на Python


Channel's geo and language: Russia, Russian
Category: Technologies


Python: примеры кода, уроки, статьи
Купить рекламу: https://telega.in/c/pytstart
✍️По всем вопросам: @Pascal4eg

Related channels

Channel's geo and language
Russia, Russian
Statistics
Posts filter


🖥 Срезы (slices) в Python позволяют удобно извлекать части последовательностей (списки, строки, кортежи) с помощью синтаксиса:

sequence[start:stop:step]

🔹start – начальный индекс (по умолчанию 0).
🔹stop – конечный индекс (не включается!).
🔹step – шаг (по умолчанию 1).

📌 Примеры:


lst = [0, 1, 2, 3, 4, 5]

print(lst[1:4]) # [1, 2, 3] (элементы с индекса 1 по 3)
print(lst[:3]) # [0, 1, 2] (с начала до индекса 2)
print(lst[::2]) # [0, 2, 4] (каждый второй элемент)
print(lst[::-1]) # [5, 4, 3, 2, 1, 0] (разворот списка)

⚡ Итог: срезы позволяют легко работать с последовательностями без циклов и лишнего кода!


🖥 Как превратить CSV в словарь Python

CSV часто используется для хранения таблиц. А загрузить его в Python можно буквально за несколько строк 👇


import csv

with open("users.csv", encoding="utf-8") as file:
users = list(csv.DictReader(file))

print(users[0]) # Alex

users.csv выглядит так:

name,age,city
Alex,25,Moscow
Anna,22,Kazan

💡 А дальше с данными можно работать как с обычными словарями:

for user in users:
if int(user["age"]) >= 25:
print(user["name"])

🔥 Полезно для:
— обработки таблиц
— импорта данных
— небольших скриптов
— автоматизации отчётов


🔄 Генераторы и 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
➡️ Почти как list comprehension, но без хранения всех элементов в памяти.


🟢 Где это реально нужно:
🟢обработка логов и CSV гигабайтного размера;
🟢потоковые данные (сокеты, API);
🟢построение бесконечных последовательностей;
🟢конвейеры обработки (map/filter без лишних списков).



🗣️ Запомни:yield отдаёт результат по частям, не занимая память. Генераторы можно объединять в цепочки — как трубы. Если данных много или они бесконечны — только генераторы спасут.


🎯 Как выглядеть как мидл, даже если ты джун

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

👍 1. Не пиши код сразу — начни с понимания

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

# ❌ Джун:
# Просто пишет как-нибудь

# ✅ Мидл:
# Планирует — какие модули затронет, где могут быть ошибки, какие кейсы проверить

👍 2. Всегда думай про edge cases

Мидлы знают, что код без тестов на крайние случаи — потенциальная мина.

def divide(a, b):
return a / b

# ✅ А если b = 0?

👍 3. Дай коду имя и порядок

Пиши функции с понятными именами, дели на модули, убирай мусор.
Мидл пишет поддерживаемый код — это важно.

# ❌
def f(x): return x*2

# ✅
def double_price(price: float) -> float:
return price * 2

👍 4. Будь предсказуемым

Мидлы не изобретают велосипеды. Используй стандартные конструкции, идиоматичный Python, pathlib, enumerate, with, dataclass, typing.

👍 5. Спрашивай правильно

Не “у меня не работает 😢”, а “я делаю X, жду Y, получаю Z. Вот код. Пробовал уже A и B.”

Это — уровень. И его видно сразу.


🗣 Пиши как мидл, спрашивай как мидл, думай как мидл — и к тебе начнут относиться как к мидлу.

📍 Где применимо:
На стажировках, джуниор-работе, open source — помогает получить фидбек, повысить доверие и быстрее вырасти.


👩‍💻 Библиотеки для ленивых: когда хочется больше делать с меньшими усилиями

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

1. `pathlib` — путь к лёгкости работы с путями

Ты всё ещё юзаешь os.path? Пора остановиться. pathlib — это объектно-ориентированная альтернатива, которая позволяет работать с путями проще и чище.

Пример:

from pathlib import Path

p = Path("/home/user/docs")
print(p / "file.txt") # /home/user/docs/file.txt

👉 Это значительно читаемее и проще, чем старые подходы с os.path.

2. `requests` — HTTP без головной боли

HTTP-запросы — одна из самых часто используемых операций, но с ними можно запутаться. requests делает этот процесс понятным и удобным.

Пример:

import requests

response = requests.get('https://api.example.com/data')
print(response.json())

👉 Всё! Нет лишнего кода, никаких ненужных сложностей.

3. `pydantic` — валидация данных с минимальными усилиями

Если тебе нужно проверять данные, а писать вручную кучу кода — не хочется, используй pydantic. Эта библиотека позволяет быстро проверять и валидировать данные, обрабатывая JSON, параметры и модели.

Пример:

from pydantic import BaseModel

class User(BaseModel):
name: str
age: int

user = User(name="Alice", age=30)
print(user)

👉 Валидация без лишних усилий и работы с типами. Всё автоматически.

4. `attrs` — создание классов без ненужного кода

Если ты создаёшь классы, но не хочешь писать лишние методы вроде __init__, __repr__, __eq__, то тебе в помощь attrs. Эта библиотека позволяет легко создавать классы с автоматическим заполнением всех необходимых методов.

Пример:

import attr

@attr.s
class Point:
x = attr.ib()
y = attr.ib()

p = Point(3, 4)
print(p) # Point(x=3, y=4)

👉 Быстро, удобно, без лишних усилий.

5. `click` — консольные приложения без мук

Создание CLI-интерфейсов может быть утомительным, но с click это делается быстро и без боли. Ты можешь создавать простые и мощные консольные команды с минимальными усилиями.

Пример:

import click

@click.command()
@click.argument('name')
def greet(name):
click.echo(f"Hello, {name}!")

greet()

👉 Лёгкая настройка, удобная обработка аргументов и флагов.

🗣️ Запомни: используй библиотеки, чтобы минимизировать шаблонный код, повысить читаемость и улучшить производительность разработки.


📐 Typing: TypedDict, Literal, Annotated в реальных проектах

Аннотации типов в Python — это не только int и str. Для сложных сценариев есть мощные инструменты: TypedDict, Literal, Annotated. Они помогают писать код понятнее и ловить ошибки ещё на этапе разработки.

📦 TypedDict — словари со строгой схемой
from typing import TypedDict

class User(TypedDict):
id: int
name: str
is_admin: bool

u: User = {"id": 1, "name": "Иван", "is_admin": False}
➡️ Теперь IDE и mypy знают структуру словаря. Ошибку в ключе или типе отловишь сразу.

🎯 Literal — фиксированные значения
from typing import Literal

def set_status(status: Literal["NEW", "IN_PROGRESS", "DONE"]) -> None:
print(f"Статус: {status}")

set_status("NEW") # ✅
set_status("INVALID") # ❌ mypy отловит
➡️ Полезно, когда параметр должен принимать строго ограниченные значения.

🧩 Annotated — тип + метаданные
from typing import Annotated
from dataclasses import dataclass

@dataclass
class User:
id: Annotated[int, "DB Primary Key"]
email: Annotated[str, "must be valid email"]
➡️ Аннотации становятся документацией и могут использоваться библиотеками (например, валидацией в FastAPI).

⚡️ TypedDict с опциональными ключами
class Config(TypedDict, total=False):
debug: bool
log_level: str

cfg: Config = {"debug": True} # ok
➡️ total=False позволяет делать часть ключей необязательными.

🔄 Literal в связке с Enum
from typing import Literal

Role = Literal["user", "admin", "moderator"]

def check_role(role: Role): ...
➡️ Даёт компактную альтернативу Enum, если не нужно хранить методы.

📑 Annotated для валидации данных
В FastAPI:

from typing import Annotated
from fastapi import Query

def read_items(size: Annotated[int, Query(ge=1, le=100)]):
return {"size": size}
➡️Ограничения накладываются прямо через типы, без лишнего кода.

🧠 Совмещение инструментов
class Product(TypedDict):
id: int
status: Literal["active", "archived"]

def process(p: Product): ...
➡️ Получается словарь со строгой схемой и фиксированным набором значений.

🗣️ Запомни: TypedDict даёт строгие словари, Literal ограничивает набор значений, Annotated связывает тип с метаданными. Вместе они делают код самодокументируемым и надёжным.


🖥 Как превратить список в строку одной командой

Допустим, есть список слов:

words = ["Python", "это", "просто", "🔥"]

Можно быстро объединить их через join():

text = " ".join(words)

print(text)

👉 Получим:

Python это просто 🔥

А если нужен другой разделитель:

csv = ", ".join(words)

print(csv)

👉

Python, это, просто, 🔥

💡 Очень удобно, когда нужно собрать строку из множества элементов.

🔥 Например, вывести список тегов:

tags = ["python", "backend", "coding"]

print("#" + " #".join(tags))

Результат:

#python #backend #coding

📌 Запомни простое правило:
split() - строку → список
join() - список → строку


🖥 Как запустить несколько задач одновременно в Python

Если есть несколько задач, которые ждут сеть или другие внешние операции, можно выполнять их конкурентно с asyncio ⚡


import asyncio

async def task(name, delay):
await asyncio.sleep(delay)
print(f"{name} готова")

async def main():
await asyncio.gather(
task("Задача 1", 2),
task("Задача 2", 1),
task("Задача 3", 3),
)

asyncio.run(main())

💡 Здесь три задачи запускаются конкурентно.

⏱️ Вместо ожидания примерно 2 + 1 + 3 = 6 секунд программа закончит примерно за 3 секунды - по времени самой долгой задачи.

🔥 Особенно полезно для:
— запросов к API
— загрузки данных
— сетевых приложений
— Telegram-ботов

⚠️ asyncio не делает обычные CPU-вычисления быстрее — он особенно хорош для задач, где много ожидания.


🖥 Как автоматически отправить email с Python

Можно отправлять письма прямо из Python — например, уведомления об ошибках или отчёты 📩


import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["Subject"] = "Отчёт"
msg["From"] = "you@example.com"
msg["To"] = "user@example.com"
msg.set_content("Отчёт готов!")

with smtplib.SMTP_SSL("smtp.example.com", 465) as smtp:
smtp.login("you@example.com", "PASSWORD")
smtp.send_message(msg)

💡 Что здесь происходит:

📨 EmailMessage — создаёт письмо
🔐 login() — авторизация на SMTP-сервере
🚀 send_message() — отправляет письмо

🔥 На этом можно сделать:
— автоматические отчёты
— уведомления о сбоях
— отправку файлов
— ежедневные рассылки

⚠️ Пароль лучше не хранить прямо в коде — используй переменные окружения или секреты.


🖥 Как сделать генератор случайных паролей на Python

Небольшой скрипт, который создаёт случайный пароль заданной длины 🔐


import secrets
import string

chars = string.ascii_letters + string.digits + "!@#$%^&*"

password = "".join(
secrets.choice(chars)
for _ in range(16)
)

print(password)

💡 Почему secrets, а не обычный random?

secrets предназначен именно для случаев, где важна непредсказуемость случайных значений.

📌 Можно менять длину:


length = 24

password = "".join(
secrets.choice(chars)
for _ in range(length)
)

🔥 На основе этого можно сделать:
— генератор паролей
— CLI-утилиту
— генератор токенов
— автоматическое создание временных ключей


🖥 Как найти дубликаты в папке с помощью Python

Например, в папке лежат сотни файлов, и нужно понять, какие из них полностью одинаковые.

Можно сравнивать их по хэшу 👇


from pathlib import Path
import hashlib

def get_hash(path):
return hashlib.md5(path.read_bytes()).hexdigest()

files = {}

for file in Path("files").iterdir():
if file.is_file():
file_hash = get_hash(file)
files.setdefault(file_hash, []).append(file)

for group in files.values():
if len(group) > 1:
print("Дубликаты:")
for file in group:
print(" ", file)

💡 Идея простая:

📄 файл → 🔢 хэш → 🔍 сравниваем хэши

Если хэши совпали, файлы с высокой вероятностью одинаковые.

🔥 Такой скрипт можно использовать для:
— очистки папок
— поиска повторяющихся фото
— анализа больших архивов
— автоматизации работы с файлами


🖥 Как превратить PDF в текст с помощью Python

Нужно быстро достать текст из PDF? Можно автоматизировать это 👇


import fitz

doc = fitz.open("document.pdf")

for page in doc:
print(page.get_text())

📦 Установка:


pip install pymupdf

💡 А если нужно сохранить весь текст в файл:


with open("result.txt", "w", encoding="utf-8") as file:
for page in doc:
file.write(page.get_text())

🔥 Получается простой конвертер PDF → TXT.

На этом можно построить:
— поиск по документам
— обработку большого количества PDF
— извлечение данных из отчётов
— подготовку текста для AI

⚠️ Если PDF состоит из сканов, обычное извлечение текста может не сработать - тогда понадобится OCR.


🖥 Как превратить текст в речь с помощью Python

Можно заставить Python буквально говорить 🔊

Для этого есть библиотека pyttsx3:

import pyttsx3

engine = pyttsx3.init()

engine.say("Привет! Я говорю с помощью Python")
engine.runAndWait()

📦 Установка:

pip install pyttsx3

💡 Можно сделать функцию:

def speak(text):
engine.say(text)
engine.runAndWait()

speak("Сегодня изучаем Python!")

🔥 На этой основе можно сделать:
— голосового помощника
— программу для чтения текста
— озвучку уведомлений
— простого desktop-бота

И всё это — без сложных моделей и API 🚀


🖥 Как повторить строку несколько раз

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


text = "Python! "

print(text * 3)

👉 Результат:

Python! Python! Python!

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

nums = [1, 2]

print(nums * 3)

Получим:

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

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

⚠️ Но со списками есть нюанс: элементы не копируются глубоко - для вложенных изменяемых объектов это может привести к неожиданному поведению.


👩‍💻 Как работает 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 особенно полезен для:
— анализа текста
— подсчёта слов
— статистики
— обработки данных


👩‍💻 *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-интерфейсов.


🖥 Как отсортировать список словарей по определенному полю?

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

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

users = [{'age': 30}, {'age': 20}, {'age': 10}]
users.sort(key=lambda user: user['age'])
>>> [{'age': 10}, {'age': 20}, {'age': 30}]


👩‍💻 Антипаттерны в 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)]

🗣️ Запомни: даже если код "работает", это не значит, что он хорош. Следи за чистотой — антипаттерны незаметны, но со временем превращают проект в хаос.


⚡️ functools.cache вместо самодельного мемо — просто и эффективно

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

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

def fib(n):
if n in _cache:
return _cache[n]
if n


👩‍💻 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: понятные, компактные и без лишнего шума.

20 last posts shown.