Python для начинающих
1.06K subscribers
288 photos
3 videos
232 files
61 links
Python для начинающих
Download Telegram
Как настроить автоматическое тестирование кода с Tox
Привет! С вами Иван, и сегодня я расскажу, как прокачать свой Python-проект с помощью автоматизированного тестирования через Tox. Tox — это настоящий must-have для тех, кто хочет, чтобы код работал стабильно в разных версиях Python без кучи ручной возни.

### Что такое Tox и зачем он нужен?

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

### Начнем с установки

Для начала установим Tox (предполагаю, что Python и pip у тебя уже стоят):

pip install tox


### Конфигурируем Tox

Настраивать Tox элементарно. В корне проекта создаём файл tox.ini и пишем:

[tox]
envlist = py38, py39

[testenv]
deps = pytest
commands = pytest


Здесь мы указали, что хотим тестировать код в средах с Python 3.8 и 3.9. В каждой среде устанавливается pytest и запускаются тесты.

### Давайте напишем простой пример

Пусть у нас есть модуль с функцией:

# calc.py
def add(x, y):
return x + y


И тест к нему:

# test_calc.py
from calc import add

def test_add():
assert add(2, 3) == 5


Теперь просто набираем в терминале:

tox


Tox автоматически создаст окружения, поставит нужные зависимости и прогоним тесты в обеих версиях Python!

### Преимущества Tox

- Кроссплатформенность: ваш проект тестируется сразу с разными версиями Python.
- Изоляция: не надо засорять глобальное окружение.
- Гибкость: можно добавить линтеры, проверить стиль кода или даже сборку документации — всё через конфиг.

### Lifehack: запуск только одного окружения

Не хочется гонять все версии? Запусти:

tox -e py39


И тесты исполнятся только для Python 3.9.

---

Автоматизация тестов — это страховка вашего проекта. С Tox вы тратите время не на ручное переключение версий, а на улучшение своего кода. Попробуйте — и уже не захотите делать всё вручную!
👍1
Использование pathlib для упрощения работы с файловыми путями
Привет! С вами Иван, и сегодня поговорим о модуле, который может спасти вас от головной боли при работе с файловыми путями в Python — о pathlib.

До появления pathlib нам приходилось использовать громоздкие комбинации из os.path, склеивать пути через строчные конкатенации или возиться с кучей методов, помня при этом отличия между Windows и Unix. Всё это неудобно и легко сделать ошибку. Но теперь всё проще и элегантнее!

## Основы работы с pathlib

Модуль pathlib вводит класс Path, который делает манипуляции с путями интуитивно понятными:

from pathlib import Path

current_dir = Path.cwd() # Получаем текущую директорию
desktop = current_dir / 'Desktop' # Формируем новый путь к рабочему столу
print(desktop)


Здесь Path реализует перегрузку оператора /, превращая соединение частей пути в удовольствие.

## Проверка существования файлов и папок

Больше не нужно писать длинные конструкции на os.path — всё делается элегантно:

file_path = Path('some_folder') / 'example.txt'

if file_path.exists():
print("File exists!")
if file_path.is_file():
print("This is a file!")
if file_path.is_dir():
print("This is a directory!")


## Итерация по файлам в папке

Нужно найти все .txt файлы? Это делается в одну строку:

for txt_file in Path('documents').glob('*.txt'):
print(txt_file.name)


Можно даже искать рекурсивно во всех подпапках:

for file in Path('documents').rglob('*.pdf'):
print(file)


## Чтение/запись файлов

Чтение содержимого файла теперь просто как никогда:

file = Path('sample.txt')
text = file.read_text(encoding='utf-8')
print(text)


А вот так легко можно записать данные в файл:

file.write_text('Hello, World!', encoding='utf-8')


## Вывод

pathlib — это современный, кроссплатформенный и лаконичный способ работы с файлами и папками в Python. Просто начните использовать Path вместо старых подходов и почувствуйте, насколько проще стала ваша жизнь!
🔥2
Работа с двоичными данными на Python: модуль struct
Привет! На связи Иван, и сегодня мы разоблачим один из «секретных агентов» стандартной библиотеки Python — модуль struct. Если вам хоть раз приходилось работать с бинарными файлами или протоколами низкого уровня, struct станет вашим лучшим другом. Без него не получится удобно преобразовывать структурированные данные в байты и обратно. Давайте разберёмся, что к чему, на конкретных примерах.

## Быстро обо всём: для чего нужен struct?

Модуль struct позволяет «упаковать» данные в байтовые строки (bytes) и «распаковать» их обратно в привычные питоновские типы. Это незаменимо, если нужно, например, сериализовать числа для передачи по сети или сохранить данные так, чтобы их потом мог прочитать C-программа.

## Основные приёмы

Всё крутится вокруг функций pack и unpack, а также строки формата, описывающей, как упаковать данные.

### Пример 1: Запаковать числа в байты

import struct

data = (42, 3.14)
packed = struct.pack('if', *data) # i — int, f — float
print(packed) # что-то вроде b'*\x00\x00\x00\xc3\xf5H@'

# А теперь обратно:
unpacked = struct.unpack('if', packed)
print(unpacked) # (42, 3.140000104904175)


### Пример 2: Работа с бинарными файлами

with open('data.bin', 'wb') as f:
f.write(struct.pack('I2c', 2024, b'P', b'y'))

with open('data.bin', 'rb') as f:
content = f.read()
print(struct.unpack('I2c', content)) # (2024, b'P', b'y')


### Пример 3: Парсинг байтов вручную

Часто приходят сырые байты откуда-то (например, из сети).

msg = b'\x05\x00\x00\x00hello'  # длина строки (5), затем сама строка
length = struct.unpack('I', msg[:4])[0]
text = msg[4:4+length].decode()
print(length, text) # 5 hello


## Вывод

struct полезен там, где нужно строго соблюдать размер и формат данных. Для низкоуровневой магии или общения с «железом» — вещь незаменимая. Главное — освоиться с форматами (i, f, c, h, и так далее), и тогда любой бинарный файл у вас — как открытая книга!
👍2
Как выполнить симуляцию физической системы с Box2D
Симуляция физики в Python: знакомство с Box2D

Привет! Меня зовут Иван, и сегодня я расскажу, как оживить ваши питоновские проекты с помощью реальной физики. Модуль Box2D — это порт знаменитого C++-движка, который используется даже в Angry Birds. Работая с Box2D, вы сможете симулировать столкновения, гравитацию, трение и многие другие законы Ньютона.

### Установка

Для начала установим обертку для Python:

pip install box2d-py


### Первый шаг: «Мир» с гравитацией

Box2D моделирует «мир» (world), в котором живут все объекты. Добавим что-то простое: падение квадратика на землю.

from Box2D import (b2World, b2PolygonShape, b2_staticBody, b2_dynamicBody)

world = b2World(gravity=(0, -10), doSleep=True)

# Создаём статический объект — землю
ground = world.CreateStaticBody(
position=(0, 0),
shapes=b2PolygonShape(box=(50, 1)),
)

# Динамический объект — наш падающий ящик
box = world.CreateDynamicBody(position=(0, 20))
box.CreatePolygonFixture(box=(1, 1), density=1, friction=0.3)


### Шаг за шагом: симулируем падение

Box2D устроен так, что на каждом «шагающем» кадре пересчитывает все силы. Сделаем небольшой цикл:

timeStep = 1.0 / 60
vel_iters, pos_iters = 6, 2

for i in range(60):
world.Step(timeStep, vel_iters, pos_iters)
print(f"Step {i}: Box y-position = {box.position.y:.2f}")


Если вы запустите этот код, увидите, как координата вашего ящика падает: Box2D сам «роняет» объекты благодаря гравитации.

### Можно добавить столкновения

Box2D сразу учитывает коллизии: наш куб не провалится сквозь землю, остановится и немного подпрыгнет — настоящая физика!

### Как идти дальше?

Добавляйте больше динамических объектов: круги, многоугольники, соединяйте их шарнирами — с Box2D просто строить и домино, и симулятор машинки. Для визуализации можно использовать Pygame, pyglet или matplotlib, но для отработки логики совсем не обязательно что-то рисовать.

Box2D — отличный инструмент, чтобы почувствовать себя конструктором собственного физического мира, а главное, учиться наглядно — ведь питон в универе уже слишком скучен без весело прыгающих коробочек!
Введение в создание API с FastAPI и Python
Привет! Я — Иван, и сегодня у нас отличная тема: создание своих API на Python с помощью FastAPI. Если вы когда-нибудь хотели написать бэкенд для веб-приложения или просто быстро протестировать идею — вам определённо стоит познакомиться с этим модулем.

Зачем вообще нужен API?
API (Application Programming Interface) — это способ дать миру (или хотя бы вашему фронтенду/мобильному приложению) доступ к вашей программе. FastAPI — это современный и очень быстрый фреймворк, который позволяет создавать такие интерфейсы буквально за пару минут. Он поддерживает асинхронный код и автоматически документирует ваше API (Swagger/OpenAPI подключены "из коробки").

Минимальный пример

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
return {"message": "Hello, FastAPI!"}


Запустив этот код (uvicorn main:app --reload), вы моментально получите рабочее API: откройте браузер, зайдите на http://localhost:8000, и увидите JSON-ответ. А если перейти на /docs, там уже подробная документация и онлайн-тестирование всех маршрутов!

Добавим обработку параметров

Хотите API с параметрами? Без проблем:

@app.get("/square/{number}")
def calculate_square(number: int):
return {"number": number, "squared": number * number}


Теперь при обращении к /square/5 вы получите {"number": 5, "squared": 25}.

Работаем с запросами POST

Допустим, нужно принимать данные от пользователя. FastAPI умеет автоматически валидировать JSON с помощью Pydantic:

from pydantic import BaseModel

class Item(BaseModel):
name: str
price: float

@app.post("/items/")
def create_item(item: Item):
return {"item_name": item.name, "item_price": item.price}


Воспользуйтесь страничкой /docs, чтобы отправить JSON — попробуйте передать {"name": "Keyboard", "price": 99.99}.

Почему FastAPI крут?
- Автоматические интерактивные docs.
- Поддержка асинхронности и скорости.
- Простота написания и расширения.

FastAPI уже стал любимцем у многих компаний и разработчиков, ведь он позволяет сосредоточиться на коде, а не на рутине. Попробуйте, и уверяю: у вас не возникнет желания возвращаться к более громоздким фреймворкам!
👍2
Эффективное использование памяти: подсчет ссылок и сборка мусора
Привет! С вами Иван. Сегодня разберём одну из самых закулисных и магических тем Python — управление памятью: подсчёт ссылок и сборку мусора. Если вы когда-нибудь задумывались, почему Python не просит у вас явно освобождать память, то этот пост для вас!

## Подсчёт ссылок: сколько “рук” держат объект?

Python использует reference counting — счётчик ссылок на каждый объект. Когда переменная указывает на объект, счётчик увеличивается. Как только ни одна переменная на него больше не ссылается, объект считается “ненужным” и подлежит удалению.

Пример:

import sys

a = []
print(sys.getrefcount(a)) # Обычно вернёт 2 (a и аргумент функции)
b = a
print(sys.getrefcount(a)) # Уже 3 ссылки (a, b, и аргумент)
del b
print(sys.getrefcount(a)) # Снова 2


Магия проста: пока есть хотя бы одна “рука”, держащая объект, он живёт. Как только все переменные и ссылки исчезают — память освобождается.

## Сборка мусора: борьба с “каруселями”

Но что, если объекты ссылаются друг на друга? Простое удаление переменных не сработает — каждый будет держать “за руку” другого, и счётчики не опустятся до нуля! Тут появляется garbage collector.

В Python модуль gc следит за такими “каруселями”:

import gc

class Node:
def __init__(self):
self.ref = None

x = Node()
y = Node()
x.ref = y
y.ref = x

del x, y # Ссылок на объекты нет, но карусель всё ещё существует
gc.collect() # Явно собираем мусор, объекты будут удалены


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

## Практические советы

- Не бойтесь “загрязнить” память — Python делает всё сам.
- Если работаете с большим количеством данных и видите рост памяти — попробуйте вызвать gc.collect().
- Используйте weakref, если нужен временный “тонкий” доступ без увеличения счётчика ссылок.

Пусть ваша память всегда будет свободна для новых идей!
👍2
Как переназначить поток вывода и ввода в Python
Привет! На связи Иван, и сегодня в нашем блоге разберём магию перенаправления потоков ввода и вывода в Python. Зачем это нужно? Например, если вы хотите записывать вывод вашей программы не только на экран, но и в файл, или "обмануть" функцию, которая традиционно ждёт пользовательский ввод, подсовывая ей данные автоматически. Готовы? Погнали!

## Перенаправляем stdout: вывод в файл и обратно

Для работы с потоками в Python служит модуль sys. Самый популярный поток — это sys.stdout, который по умолчанию пишет в консоль. Давайте заставим его писать в файл:

import sys

with open('output.txt', 'w') as file:
original_stdout = sys.stdout # сохраняем ссылку на стандартный поток
sys.stdout = file # перенаправляем stdout в файл
print("Hello, file!")
sys.stdout = original_stdout # возвращаем stdout обратно

print("Hello, console!")

Теперь строка "Hello, file!" попадёт в файл, а "Hello, console!" — как обычно, в терминал.

## Подменяем stdin: автоматизируем ввод

Точно так же можно подменить поток ввода. Это удобно, когда нужно тестировать функции, требующие input от пользователя.

import sys
from io import StringIO

test_input = StringIO('42\n')
original_stdin = sys.stdin
sys.stdin = test_input

number = int(input("Enter a number: "))
print("Number x2:", number * 2)

sys.stdin = original_stdin

В этом примере input не ждёт ввода, а сразу получает '42'. Удобно для юнит-тестов!

## А если хочется перехватить вывод программы?

Трюк с подменой stdout особенно крут, когда хочется легко перехватывать и анализировать результат работы каких-то функций. Например, сделаем функцию, возвращающую всё, что она напечатала:

def capture_output(func):
import sys
from io import StringIO

output = StringIO()
original_stdout = sys.stdout
sys.stdout = output
try:
func()
finally:
sys.stdout = original_stdout
return output.getvalue()

def hello():
print("Hello from function!")

text = capture_output(hello)
print("Captured:", text)

Теперь мы можем обработать результат как строку — не круто ли?

На этом всё! Не стесняйтесь экспериментировать с потоками: это ключ к автоматизации, тестированию и оптимизации ваших программ. Желаю отличной практики и новых открытий с Python!
Иван.
2
Работа с метаклассами: расширенное использование классов
Привет! С вами Иван, сегодня копнем чуточку глубже — поговорим о метаклассах в Python.

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

## Для чего нужны метаклассы?

С их помощью можно:
- Автоматически модифицировать классы при создании (например, добавлять методы или атрибуты);
- Навязывать единый стиль (например, проверять именование или структуру классов);
- Реализовывать паттерны, вроде Singleton, прямо “на уровне класса”.

## Базовый пример

Создадим метакласс, который автоматически добавляет атрибут category = 'custom_class' во все классы:

class BaseMeta(type):
def __new__(mcs, name, bases, attrs):
attrs['category'] = 'custom_class'
return super().__new__(mcs, name, bases, attrs)

class ExampleClass(metaclass=BaseMeta):
pass

print(ExampleClass.category) # custom_class


## Валидация структуры класса

Иногда хочется убедиться, что каждый класс имеет нужные методы:

class MethodCheckerMeta(type):
def __new__(mcs, name, bases, attrs):
if 'process' not in attrs:
raise TypeError('Class must define "process" method')
return super().__new__(mcs, name, bases, attrs)

class DataWorker(metaclass=MethodCheckerMeta):
def process(self):
print("Processing...")

# class BadWorker(metaclass=MethodCheckerMeta):
# pass # Ошибка при определении класса!


## Подмена методов на лету

Допустим, хотим, чтобы все методы начинали логировать своё вызовы:

def log_decorator(func):
def wrapper(*args, **kwargs):
print(f'Call {func.__name__}')
return func(*args, **kwargs)
return wrapper

class LoggerMeta(type):
def __new__(mcs, name, bases, attrs):
for key, val in attrs.items():
if callable(val):
attrs[key] = log_decorator(val)
return super().__new__(mcs, name, bases, attrs)

class UserAction(metaclass=LoggerMeta):
def update_profile(self):
print("Profile updated")

u = UserAction()
u.update_profile()


Как видите, метаклассы — секретная дверца Python к по-настоящему мощным и гибким фичам. Пользуются ими редко, но знать о них точно стоит!
👍2
Как работает itertools: от простых комбинаций до сложных перестановок
Привет, друзья! На связи Иван, и сегодня мы окунемся в мир Python-модуля, который любит любой ценитель изящного кода — речь о itertools. Этот модуль открыт как сундук с сокровищами для разных комбинаторных задач: от банального перебора вариантов до создания хитроумных перестановок.

## Зачем вообще нужен itertools?

Когда возникает задача "перебрать все комбинации", "замиксовать значения" или "иcкать все варианты", большинство новичков берёт в руки вложенные циклы и — устаёт. Но если вы знаете про itertools, эти задачи превращаются в пару строк элегантного кода.

Давайте разбираться с основами!

### 1. Комбинации

Выберите любые 2 книги из 4-х? За нас всё сделает itertools.combinations:

from itertools import combinations

books = ['The Hobbit', 'Python 101', 'Moby Dick', 'War and Peace']
for combo in combinations(books, 2):
print(combo)


Этот код выведет все возможные пары книг — и ни одна не повторится.

### 2. Перестановки

Все возможные варианты порядка трёх футболистов на пьедестале? Простая задача для permutations:

from itertools import permutations

players = ['Alice', 'Bob', 'Charlie']
for p in permutations(players):
print(p)


Здесь будет 6 вариантов (3!) — идеально для задач, где важен порядок.

### 3. Произведения (Декартово произведение)

Когда нужно смиксовать элементы из разных коллекций, используем product:

from itertools import product

colors = ['red', 'green']
sizes = ['S', 'M']
for item in product(colors, sizes):
print(item)


Ты быстро получаешь комбинации вида: ('red', 'S'), ('red', 'M'), …

### 4. Комбинации с повторениями

Допустим, нужно узнать, какие мороженое можно собрать из 3-х шариков, если вкусы могут повторяться:

from itertools import combinations_with_replacement

flavors = ['chocolate', 'vanilla', 'strawberry']
for combo in combinations_with_replacement(flavors, 3):
print(combo)


Получаем все возможные варианты с повторениями, без головной боли!

---

itertools — это как швейцарский нож для работы с итерациями. Освоив всего несколько функций, ты вытесняешь громоздкие циклы лаконичными генераторами. Заходи в документацию и пробуй новые инструменты — и Python станет для тебя ещё более мощным и гибким!
👍1