Python для начинающих
1.24K subscribers
546 photos
3 videos
232 files
74 links
Python для начинающих
Download Telegram
### Изучаем itertools: комбинации и декартовы произведения

Если вы хоть раз вручную писали вложенные циклы, чтобы перебрать все пары, тройки или варианты, — модуль itertools создан для вас. Он умеет генерировать комбинации и продукты «на лету», не занимая лишнюю память.

---

## Комбинации: выбираем без повторов

Комбинация — это выбор элементов без учета порядка. Из [1, 2, 3] пары такие: (1, 2), (1, 3), (2, 3).

from itertools import combinations

items = ['a', 'b', 'c', 'd']

for pair in combinations(items, 2):
print(pair)


combinations(iterable, r):
- не повторяет элементы;
- (a, b) и (b, a) считаются одним вариантом;
- всё генерируется лениво (по мере запроса).

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

---

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

Иногда элемент можно брать несколько раз: монеты, кубики, вкусы мороженого.

from itertools import combinations_with_replacement

flavors = ['vanilla', 'chocolate', 'strawberry']

for combo in combinations_with_replacement(flavors, 2):
print(combo)


('vanilla', 'vanilla') здесь вполне допустим.

---

## Декартово произведение: все возможные варианты

product — это как вложенные циклы, только в одну строку. Идеален для генерации всех комбинаций параметров.

from itertools import product

sizes = ['S', 'M', 'L']
colors = ['black', 'white']

for item in product(sizes, colors):
print(item)


Результат:
- ('S', 'black')
- ('S', 'white')
- ('M', 'black')
- и т.д.

Можно задать повторения:

for roll in product(range(1, 7), repeat=2):
print(roll)


Это уже все возможные броски двух кубиков.

---

## Комбинации против продукта: что когда использовать?

- Нужен выбор из одного набора без повторов → combinations
- Нужен выбор из одного набора с возможными повторамиcombinations_with_replacement
- Нужны все сочетания из нескольких наборовproduct
- Хотите сымитировать несколько одинаковых наборов (кубики, пароли фиксированной длины) → product(..., repeat=n)

---

itertools экономит память и время разработки: вы получаете мощный генератор вариантов без километров вложенных циклов. Как только ловите себя на мысли «сейчас напишу ещё один for внутри for», сначала загляните в этот модуль.
👍4
Модуль uuid: генерация уникальных идентификаторов
Модуль uuid: генерация уникальных идентификаторов без боли и коллизий

Когда нужно что-то «уникальное» — многие программисты тянутся к времени, счётчикам или даже случайным числам. Проблема в том, что всё это легко пересекается, особенно в распределённых системах. Здесь в игру вступает модуль uuid — стандартный способ генерировать уникальные идентификаторы в Python.

UUID (Universally Unique Identifier) — это 128-битное число, обычно записываемое как строка вроде:

550e8400-e29b-41d4-a716-446655440000

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

---

### Базовая генерация UUID

import uuid

user_id = uuid.uuid4()
print(user_id) # например: 3e7c0e78-9a8e-4b52-9780-4e1c23f57abc
print(type(user_id)) # <class 'uuid.UUID'>


uuid4() генерирует UUID на основе криптографически стойкого генератора случайных чисел. Это самый популярный вариант.

---

### Разные версии UUID

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

import uuid

# v1 — на основе MAC-адреса и времени
session_id = uuid.uuid1()

# v3 — хеш MD5 (детерминированный)
name_based_v3 = uuid.uuid3(uuid.NAMESPACE_DNS, "example.com")

# v5 — хеш SHA-1 (детерминированный, предпочтительнее v3)
name_based_v5 = uuid.uuid5(uuid.NAMESPACE_URL, "https://example.com")

print(session_id)
print(name_based_v3)
print(name_based_v5)


Где это полезно:

- uuid4() — когда нужна просто уникальность.
- uuid1() — когда порядок по времени важен (но может раскрывать MAC-адрес и время).
- uuid3() / uuid5() — когда один и тот же «вход» должен давать один и тот же UUID (идентификатор по имени, URL и т.п.).

---

### UUID как строки и обратно

Чаще всего UUID хранят как строки (например, в базе):

import uuid

order_id = uuid.uuid4()

order_str = str(order_id) # в строку
print(order_str)

restored = uuid.UUID(order_str) # обратно в объект UUID
print(restored == order_id) # True


Можно работать и с байтами:

token = uuid.uuid4()
token_bytes = token.bytes
restored_token = uuid.UUID(bytes=token_bytes)


---

### Практический мини-пример: генерация ключей для API

import uuid

def generate_api_key() -> str:
return uuid.uuid4().hex # без дефисов, 32 символа

keys = [generate_api_key() for _ in range(3)]
for k in keys:
print(k)


Метод .hex возвращает компактное шестнадцатеричное представление, удобное для токенов.

---

Модуль uuid снимает головную боль с уникальностью: вместо придумывания схем и «умных» счётчиков достаточно вызвать одну функцию — и получить идентификатор, с которым комфортно работать и локально, и в распределённых системах.
🔥2👍1
Использование difflib для поиска различий между строками и файлами
Использование difflib: как Python видит отличия лучше нас

Когда файл «чуть-чуть поменяли», глазами искать отличия — то еще удовольствие. Python-модуль difflib умеет делать это аккуратно, наглядно и… очень гибко. Разберёмся, как сравнивать строки и файлы, будто у нас встроен мини-Git.

---

### 1. Быстро сравнить две строки

Начнем с простого: найти различия между двумя строками посимвольно.

import difflib

s1 = "Python is awesome!"
s2 = "Python is awesom?"

diff = difflib.ndiff(s1, s2)
print("\n".join(diff))


Результат покажет строки с префиксами:
- - — удалено
- + — добавлено
- ? — подсказка, какие именно символы отличаются

Это удобно, когда нужно понять, почему строки «почти одинаковы», но сравнение == возвращает False.

---

### 2. Похожесть строк в процентах

Иногда важно не чем строки отличаются, а насколько они похожи. Для этого есть SequenceMatcher.

from difflib import SequenceMatcher

a = "color"
b = "colour"

ratio = SequenceMatcher(None, a, b).ratio()
print(ratio) # например, 0.91...


Значение от 0 до 1 — коэффициент похожести. Можно использовать для:
- поиска опечаток,
- подсказки «Вы имели в виду…»,
- фильтрации «почти одинаковых» записей.

---

### 3. HTML-отчет о различиях

Хотите красивый, наглядный diff в браузере? difflib.HtmlDiff как раз для этого:

import difflib

old_lines = [
"def add(a, b):\n",
" return a + b\n",
]

new_lines = [
"def add(a, b):\n",
" result = a + b\n",
" return result\n",
]

html = difflib.HtmlDiff().make_file(old_lines, new_lines,
fromdesc="Old version",
todesc="New version")

with open("diff.html", "w", encoding="utf-8") as f:
f.write(html)


Откройте diff.html в браузере — увидите таблицу с подсветкой добавленных/удалённых строк. Мини-система контроля версий прямо в одном файле.

---

### 4. Сравнение файлов построчно

Классический сценарий — сравнить два текстовых файла:

import difflib

with open("old.txt", encoding="utf-8") as f:
old = f.readlines()
with open("new.txt", encoding="utf-8") as f:
new = f.readlines()

for line in difflib.unified_diff(old, new,
fromfile="old.txt",
tofile="new.txt"):
print(line.rstrip())


Формат unified diff знаком всем, кто работал с Git: строки с +, - и контекстом вокруг изменений. Удобно для логов, конфигов, автопроверок.

---

difflib часто недооценивают, а зря. Это готовый швейцарский нож для работы с похожими текстами: от проверки орфографии до построения собственных дифф-отчетов. И всё это — в стандартной библиотеке, без единого pip install.
🔥3
Создание локального веб-сервера с помощью встроенного http.server
Создание локального веб-сервера с помощью встроенного http.server

Когда слышишь «веб‑сервер», в голове всплывают сложные штуки вроде Nginx, Apache или хотя бы Flask. Но в Python уже есть крошечный сервер «из коробки» — модуль http.server. Он идеален для экспериментов, отладки и быстрых демо.

---

### Запускаем самый простой сервер

Перейдите в папку с файлами, которые хотите раздавать, и запустите:

python -m http.server 8000


Теперь в браузере откройте http://localhost:8000 — вы уже подняли сервер, который раздает текущую директорию.
Порт можно не указывать, тогда по умолчанию будет 8000.

---

### Минимальный сервер своим скриптом

Можно сделать то же самое из Python‑файла:

from http.server import HTTPServer, SimpleHTTPRequestHandler

def run_server(port: int = 8000):
server_address = ("", port) # "" означает слушать на всех интерфейсах
httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
print(f"Serving on port {port}...")
httpd.serve_forever()

if __name__ == "__main__":
run_server()


SimpleHTTPRequestHandler умеет раздавать файлы из текущей папки и показывает простую HTML‑страницу со списком файлов.

---

### Свой обработчик запросов

Хотите кастомный ответ вместо списка файлов? Наследуемся от BaseHTTPRequestHandler:

from http.server import HTTPServer, BaseHTTPRequestHandler

class HelloHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/":
message = "Hello, Python beginner!"
else:
message = f"Unknown path: {self.path}"

data = message.encode("utf-8")

self.send_response(200)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Content-Length", str(len(data)))
self.end_headers()

self.wfile.write(data)

def run_server(port: int = 8080):
server_address = ("", port)
httpd = HTTPServer(server_address, HelloHandler)
print(f"Custom server on port {port}...")
httpd.serve_forever()

if __name__ == "__main__":
run_server()


Теперь при открытии http://localhost:8080/ вы получите текстовый ответ, а при переходе по другому пути — сообщение с этим путем.

---

### Когда это полезно

- Быстро показать HTML/CSS/JS без настройки больших серверов.
- Локально протестировать AJAX‑запросы.
- Написать минимальный API‑мок для отладки клиента.

http.server не для продакшена: нет защиты, логики масштабирования, нормального логирования. Но для обучения он идеально показывает, как HTTP‑запрос превращается в ответ, и помогает почувствовать «скелет» любого веб‑фреймворка.
👍2
Работа с буфером ввода-вывода с помощью io.StringIO
### Работа с буфером ввода-вывода с помощью io.StringIO

Иногда хочется поработать с текстом «как с файлом», но без создания настоящего файла на диске. Для этого в Python есть удобный инструмент — io.StringIO. Это такой «файлик в памяти»: его можно читать, писать в него, перематывать курсор — почти как с обычным файлом.

---

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

Типичные сценарии:

1. Тестирование кода, который работает с файлами, без создания временных файлов.
2. Промежуточная обработка строк в виде потока: удобно, когда данные приходят частями.
3. Перенаправление вывода (например, print) в строку, чтобы потом её обработать.

---

### Базовый пример: пишем и читаем

from io import StringIO

buffer = StringIO()

buffer.write("Hello, world!\n")
buffer.write("This is in-memory file.\n")

# Перемещаем курсор в начало, как после открытия файла для чтения
buffer.seek(0)

content = buffer.read()
print(content)


Здесь buffer ведет себя почти как файл, но все хранится в оперативной памяти в виде строки.

---

### Построчное чтение

from io import StringIO

data = "line 1\nline 2\nline 3\n"
buffer = StringIO(data)

for line in buffer:
print(line.strip())


Интерфейс знакомый: можно итерироваться по строкам, использовать readline(), readlines() и т.д.

---

### Перенаправление print в строку

Иногда нужно собрать то, что обычно выводится в консоль:

from io import StringIO
import sys

buffer = StringIO()
stdout_backup = sys.stdout

try:
sys.stdout = buffer
print("First line")
print("Second line")
finally:
sys.stdout = stdout_backup

result = buffer.getvalue()
print("Captured:")
print(result)


buffer.getvalue() возвращает всю накопленную строку. Удобно для логирования и тестов.

---

### Важные нюансы

- StringIO работает только с текстом (str). Для байтов используйте io.BytesIO.
- Метод getvalue() можно вызывать сколько угодно раз — он не сдвигает курсор.
- Не забывайте про seek(0), если хотите перечитать содержимое с начала.

io.StringIO — отличный способ тренироваться с файловым API, не засоряя диск, и гибкий инструмент для чистого и удобного кода при работе с текстовыми потоками.
👍1🔥1
Генерация диаграмм с pygraphviz: основы визуализации графов
Генерация диаграмм с pygraphviz: основы визуализации графов

Иногда проще один раз увидеть, чем сто раз распечатать print(). Особенно когда дело касается связей: кто с кем соединен, в каком направлении идет поток данных, как устроена архитектура проекта. Для этого отлично подходит pygraphviz — оболочка над знаменитым Graphviz, позволяющая генерировать диаграммы прямо из Python.

---

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

pip install pygraphviz


Важно: на некоторых системах сначала нужно установить сам Graphviz (через пакетный менеджер ОС).

---

### Простейший граф

Создадим ориентированный граф и сохраним его как PNG:

from pygraphviz import AGraph

g = AGraph(directed=True)

g.add_node("User")
g.add_node("API")
g.add_node("DB")

g.add_edge("User", "API")
g.add_edge("API", "DB")

g.layout(prog="dot") # алгоритм раскладки
g.draw("simple_graph.png")


prog="dot" — классический и самый читаемый для иерархических структур (запросы сверху, база снизу).

---

### Стайлинг: делаем диаграмму понятной

Граф без стиля — это просто клубок линий. Добавим цвета и формы, чтобы по диаграмме можно было ориентироваться за секунды:

from pygraphviz import AGraph

g = AGraph(directed=True, strict=True, rankdir="LR") # слева направо

g.add_node("Client", shape="box", style="filled", fillcolor="#AED6F1")
g.add_node("Service", shape="ellipse", style="filled", fillcolor="#A9DFBF")
g.add_node("Cache", shape="diamond", style="filled", fillcolor="#F9E79F")

g.add_edge("Client", "Service", label="HTTP")
g.add_edge("Service", "Cache", label="GET")
g.add_edge("Cache", "Service", label="HIT", color="green")
g.add_edge("Service", "Client", label="Response", color="blue")

g.graph_attr.update(label="Request Flow", fontsize="20")
g.layout(prog="dot")
g.draw("styled_graph.png")


Ключевые идеи:
- rankdir="LR" — направление слева направо (удобно для потоков).
- shape, fillcolor, style — визуальное кодирование типов узлов.
- label и color у ребер помогают понимать протоколы, типы взаимодействия и т.п.

---

### Быстрая визуализация структур из кода

pygraphviz удобно использовать для генерации диаграмм по данным из программы: граф зависимостей модулей, цепочка этапов обработки данных, схема микросервисов. Достаточно обхода вашей структуры (словаря, списка связей, дерева) и вызова add_node / add_edge в цикле.

---

pygraphviz хорош тем, что избавляет от ручного рисования схем в редакторах: диаграмма становится частью кода, обновляется автоматически и всегда соответствует реальности. Для начинающего питониста это отличный инструмент, чтобы увидеть свои структуры данных и архитектуру, а не только представлять их в голове.
👍1
Использование shutil для копирования и удаления файлов и папок
Используем shutil: копируем и удаляем файлы без боли

Работа с файлами в Python часто начинается с модуля os, но как только дело доходит до копирования и целых папок — на сцену выходит shutil. Это такой «швейцарский нож» для файловой системы.

Подключается просто:

import shutil
from pathlib import Path


## Копирование файлов

Базовый вариант — shutil.copy():

src = Path("data/source.txt")
dst = Path("backup/source_copy.txt")

shutil.copy(src, dst)


copy переносит содержимое и права доступа, но не метаданные (например, время изменения).

Если нужны максимально точные «клоны» файла, есть copy2:

shutil.copy2(src, dst)


Разница — в сохранении метаданных (atime, mtime и т.п.). Для бэкапов это часто критично.

## Копирование папок

Для директорий используется copytree:

src_dir = Path("data")
dst_dir = Path("data_backup")

shutil.copytree(src_dir, dst_dir)


Важно: если data_backup уже существует, будет ошибка. В Python 3.8+ можно указать dirs_exist_ok=True:

shutil.copytree(src_dir, dst_dir, dirs_exist_ok=True)


Так можно «обновлять» уже существующую папку бэкапа.

## Удаление файлов и папок

Одиночные файлы удобнее удалять через Path.unlink(), а вот для целых деревьев директорий есть rmtree:

target_dir = Path("old_logs")

shutil.rmtree(target_dir)


Команда безвозвратная: корзины не будет, поэтому перед вызовом стоит дважды проверить путь или добавить «защиту от дурака»:

if "backup" in str(target_dir):
shutil.rmtree(target_dir)


## Мини-утилита «скопировать и почистить»

Соберём всё вместе: скопируем папку и удалим старую:

def move_folder(src: Path, dst: Path):
shutil.copytree(src, dst, dirs_exist_ok=True)
shutil.rmtree(src)

move_folder(Path("tmp_uploads"), Path("storage/uploads"))


Фактически мы реализовали аналог «перемещения» папки силами shutil.

---

shutil хорош тем, что закрывает 80% задач по управлению файлами: копирование, рекурсивные операции, бэкапы, чистка временных директорий. А главное — код остаётся коротким и читаемым, без ручного обхода каталогов и велосипедов на os.listdir().
🔥2👍1
Создание фейковых данных для тестирования с библиотекой faker
Создание фейковых данных для тестирования с библиотекой Faker

Тестовые данные — боль любого начинающего разработчика. Ручное заполнение таблиц “Иван Иванов, test@test.ru, 123456” быстро превращает жизнь в скуку. К счастью, есть библиотека Faker, которая генерирует реалистичные фейковые данные: имена, адреса, телефоны, даты, тексты и даже фейковые компании.

---

## Установка

pip install faker


Базовое использование:

from faker import Faker

fake = Faker()

print(fake.name())
print(fake.email())
print(fake.address())


Каждый вызов вернет новое случайное, но правдоподобное значение.

---

## Локализация данных

Если вы тестируете российское приложение, логичнее видеть “Иван Петров”, а не “John Smith”:

from faker import Faker

fake = Faker("ru_RU")

for _ in range(3):
print(fake.name(), "-", fake.phone_number())


Faker поддерживает десятки локалей: en_US, de_DE, fr_FR и т.д.

---

## Генерация набора тестовых пользователей

Допустим, нужно быстро заполнить базу 10 фейковыми пользователями:

from faker import Faker

fake = Faker("ru_RU")

def generate_user():
return {
"name": fake.name(),
"email": fake.unique.email(),
"address": fake.address(),
"birthdate": fake.date_of_birth(minimum_age=18, maximum_age=65),
}

users = [generate_user() for _ in range(10)]
for user in users:
print(user)


Метод fake.unique гарантирует уникальность значения (пока не исчерпан генератор).

---

## Фейковые данные для API и фронтенда

Нужно протестировать список товаров или карточек в интерфейсе? Не проблема:

from faker import Faker
import random

fake = Faker()

def generate_product():
return {
"id": fake.uuid4(),
"title": fake.sentence(nb_words=3),
"price": round(random.uniform(10, 500), 2),
"description": fake.text(max_nb_chars=80),
"in_stock": fake.boolean(chance_of_getting_true=80),
}

products = [generate_product() for _ in range(5)]
for product in products:
print(product)


---

## Фиксация “сидов” для повторяемости

Важно, чтобы при тестах данные могли воспроизводиться. Для этого задаем seed:

from faker import Faker

fake = Faker()
Faker.seed(42)

print(fake.name())
print(fake.name()) # при повторном запуске будут те же значения


---

Faker экономит часы рутины, делает тестовые данные живыми и разнообразными, а ваш код — более надежным. Попробуйте заменить все “test123” в ваших проектах на фейковые, но правдоподобные данные и посмотрите, сколько багов всплывет.
👍4
Изучение таймеров и замеров времени с модулем timeit
Изучаем таймеры и замеры времени с модулем timeit

Когда код работает медленно, интуиция часто подводит. Кажется, что «вот это место точно тормозит», а на деле время утекает в другом участке. Здесь на сцену выходит модуль timeit — простой способ точно измерить, что действительно медленнее, а что быстрее.

### Почему не time.time()?

Наивный подход:

import time

start = time.time()
result = sum(range(10_000_000))
end = time.time()
print(end - start)


Проблемы:
- одно измерение: могли попасть на фоновую нагрузку системы;
- точность зависит от платформы;
- неудобно сравнивать несколько вариантов.

timeit решает это: он запускает код много раз, считает среднее время и делает это максимально «чисто».

### Базовый пример использования

Минимальный пример из консоли:

import timeit

t = timeit.timeit("sum(range(1000))", number=10000)
print(t)


Параметры важны:
- первый аргумент — строка с кодом, который измеряем;
- number — сколько раз выполнить этот код.

Но писать код в строках не всегда удобно. Лучше использовать функции и параметр stmt как объект:

import timeit

def calc():
return sum(range(1000))

t = timeit.timeit(stmt=calc, number=10000)
print(t)


Так проще рефакторить и отлаживать.

### Сравниваем два варианта кода

Предположим, мы хотим понять, что быстрее: список или генератор в sum.

import timeit

def use_list():
return sum([i for i in range(1000)])

def use_gen():
return sum(i for i in range(1000))

t_list = timeit.timeit(use_list, number=10000)
t_gen = timeit.timeit(use_gen, number=10000)

print("list:", t_list)
print("gen :", t_gen)


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

### Использование setup

Если нужна подготовка данных, её не стоит включать в измеряемый код. Для этого есть setup:

import timeit

setup_code = "data = list(range(10000))"

stmt_code = """
result = 0
for x in data:
result += x
"""

t = timeit.timeit(stmt=stmt_code, setup=setup_code, number=1000)
print(t)


Здесь:
- в setup мы генерируем данные один раз для каждого прогона timeit;
- в stmt считаем время только самого алгоритма.

### Немного удобства: repeat

Чтобы понять разброс по времени, используйте repeat:

import timeit

def func():
return sum(range(10_000))

times = timeit.repeat(func, number=1000, repeat=5)
print(times) # список из 5 измерений
print("best:", min(times))


Так можно ориентироваться на минимум как на «лучшие условия» выполнения.

---

timeit — это карманный профилировщик для микробенчмарков. Он не заменяет полноценный профилировщик, но идеально подходит, когда нужно честно ответить на вопрос: «Этот способ действительно быстрее, или мне только кажется?»
🔥4
Как использовать модуль zipfile для создания и извлечения архивов
Как использовать модуль zipfile для создания и извлечения архивов

Когда файлов становится много, а отправить нужно «всё и сразу», на сцену выходит модуль zipfile. Он входит в стандартную библиотеку Python, так что ничего устанавливать не нужно.

---

### Создаем ZIP‑архив из одного файла

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

import zipfile

with zipfile.ZipFile("data.zip", mode="w", compression=zipfile.ZIP_DEFLATED) as zf:
zf.write("report.txt", arcname="report_in_zip.txt")


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

- mode="w" — создаем новый архив (старый будет перезаписан).
- compression=ZIP_DEFLATED — обычное сжатие ZIP.
- write("report.txt", arcname=...) — первое имя — исходный файл, второе — как он будет называться внутри архива.

---

### Добавляем несколько файлов и папку

Чтобы пройтись по директории и заархивировать всё, что внутри:

import zipfile
import os

def zip_folder(folder_path, zip_name):
with zipfile.ZipFile(zip_name, "w", zipfile.ZIP_DEFLATED) as zf:
for root, dirs, files in os.walk(folder_path):
for file_name in files:
full_path = os.path.join(root, file_name)
rel_path = os.path.relpath(full_path, folder_path)
zf.write(full_path, arcname=rel_path)

zip_folder("project", "project_backup.zip")


Ключевой момент — rel_path. Благодаря относительному пути структура папок в архиве сохраняется аккуратно, без длинных системных путей.

---

### Извлекаем архив целиком или выборочно

Извлечь всё содержимое очень просто:

import zipfile

with zipfile.ZipFile("project_backup.zip", "r") as zf:
zf.extractall("restored_project")


А вот выборочное извлечение:

import zipfile

with zipfile.ZipFile("project_backup.zip", "r") as zf:
for name in zf.namelist():
if name.endswith(".py"):
zf.extract(name, "only_scripts")


namelist() возвращает список файлов внутри архива. Можно фильтровать по расширению, имени и т.д.

---

### Проверяем содержимое без распаковки

Иногда нужно просто «подглядеть» внутрь ZIP:

import zipfile

with zipfile.ZipFile("project_backup.zip", "r") as zf:
for info in zf.infolist():
print(info.filename, info.file_size, "bytes")


Так можно быстро оценить структуру и размер архива.

---

zipfile полезен для бэкапов, упаковки логов, раздачи учебных проектов и автоматизации рутины. Освоив эти несколько приёмов, вы легко встроите архивирование прямо в свои скрипты.
👍2
Работа с командной строкой с помощью argparse