Создание простых HTTP-запросов вручную с модулем
Большинство новичков начинают работу с сетью через библиотеку
---
### Простой GET-запрос
Сделаем обычный GET-запрос к публичному API:
Что здесь важно:
-
-
-
-
Без обязательного заголовка
---
### Отправка POST-запроса с данными
Теперь отправим POST с JSON-данными на тестовый сервис
Здесь уже видно «ручную работу»:
- Сериализуем данные сами (
- Указываем
- Сами кодируем/декодируем текст (
---
### Зачем это нужно?
- Понимание того, как устроен HTTP «на проводе».
- Возможность тонко контролировать заголовки и поведение соединения.
- Умение работать только со стандартной библиотекой, без внешних зависимостей.
После таких упражнений любые высокоуровневые библиотеки кажутся гораздо понятнее: вы уже знаете, какую именно «рутину» они берут на себя.
http.clientБольшинство новичков начинают работу с сетью через библиотеку
requests. Она удобная и «магическая». Но если хочется понять, что реально происходит под капотом, полезно познакомиться с модулем стандартной библиотеки http.client.http.client работает на более низком уровне: вы сами открываете соединение, отправляете строку запроса, заголовки, читаете ответ. Немного «олдскул», зато отлично прокачивает понимание HTTP.---
### Простой GET-запрос
Сделаем обычный GET-запрос к публичному API:
import http.client
import json
conn = http.client.HTTPSConnection("api.github.com")
headers = {
"User-Agent": "python-http.client-demo",
"Accept": "application/vnd.github.v3+json"
}
conn.request("GET", "/repos/python/cpython", headers=headers)
response = conn.getresponse()
print("Status:", response.status, response.reason)
data = response.read()
payload = json.loads(data)
print("Full name:", payload["full_name"])
print("Stars:", payload["stargazers_count"])
conn.close()
Что здесь важно:
-
HTTPSConnection — шифрованное соединение (TLS).-
request(method, url, body=None, headers={}) — отправка запроса.-
getresponse() — возвращает объект ответа.-
status, reason, read() — статус-код, текстовое описание и тело ответа.Без обязательного заголовка
User-Agent GitHub может ответить ошибкой — это хороший пример, почему заголовки критичны.---
### Отправка POST-запроса с данными
Теперь отправим POST с JSON-данными на тестовый сервис
httpbin.org:import http.client
import json
conn = http.client.HTTPSConnection("httpbin.org")
payload = {"name": "Alice", "lang": "Python"}
body = json.dumps(payload)
headers = {
"Content-Type": "application/json",
"Content-Length": str(len(body))
}
conn.request("POST", "/post", body=body, headers=headers)
response = conn.getresponse()
print("Status:", response.status)
response_data = response.read().decode("utf-8")
print("Response body:", response_data[:200], "...")
conn.close()
Здесь уже видно «ручную работу»:
- Сериализуем данные сами (
json.dumps).- Указываем
Content-Type и Content-Length вручную.- Сами кодируем/декодируем текст (
decode("utf-8")).---
### Зачем это нужно?
- Понимание того, как устроен HTTP «на проводе».
- Возможность тонко контролировать заголовки и поведение соединения.
- Умение работать только со стандартной библиотекой, без внешних зависимостей.
После таких упражнений любые высокоуровневые библиотеки кажутся гораздо понятнее: вы уже знаете, какую именно «рутину» они берут на себя.
👍2
Понимание работы контекстных менеджеров и создание своих с помощью
Если вы когда‑нибудь писали:
то уже пользовались контекстным менеджером — просто, возможно, не задумывались об этом. Давайте разберёмся, что там происходит под капотом и как писать свои.
---
### Что такое контекстный менеджер?
Контекстный менеджер — это объект, который знает, что делать до и после блока
Под капотом Python делает примерно так:
Два ключевых метода:
-
-
---
### Пишем свой контекстный менеджер “вручную”
Простой пример — измерение времени работы блока кода:
Плюсы: полный контроль, можно хранить состояние в атрибутах объекта. Минус: много шаблонного кода.
---
###
Модуль
Всё, что до
---
### Практический пример: временная смена текущей директории
Контекст гарантирует, что директория вернётся к исходной даже при ошибках внутри блока
---
### Когда стоит использовать контекстные менеджеры
- работа с файлами и сетевыми соединениями;
- блокировки потоков и транзакции в БД;
- временные настройки (логирование, окружение, директории);
- любые ресурсы, которые надо обязательно освободить.
Контекстный менеджер — это способ формально описать жизненный цикл ресурса: “взял → поработал → убрал за собой”, и
contextlibЕсли вы когда‑нибудь писали:
with open("data.txt") as f:
content = f.read()
то уже пользовались контекстным менеджером — просто, возможно, не задумывались об этом. Давайте разберёмся, что там происходит под капотом и как писать свои.
---
### Что такое контекстный менеджер?
Контекстный менеджер — это объект, который знает, что делать до и после блока
with.Под капотом Python делает примерно так:
manager = open("data.txt")
f = manager.__enter__()
try:
content = f.read()
finally:
manager.__exit__(None, None, None)
Два ключевых метода:
-
__enter__(self) — подготавливает ресурс, возвращает объект, который попадёт в as.-
__exit__(self, exc_type, exc_val, exc_tb) — освобождает ресурс, даже если возникло исключение.---
### Пишем свой контекстный менеджер “вручную”
Простой пример — измерение времени работы блока кода:
import time
class Timer:
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.end = time.perf_counter()
self.elapsed = self.end - self.start
print(f"Elapsed: {self.elapsed:.4f} seconds")
with Timer() as t:
total = sum(range(1_000_000))
Плюсы: полный контроль, можно хранить состояние в атрибутах объекта. Минус: много шаблонного кода.
---
###
contextlib.contextmanager: контекстный менеджер из функцииМодуль
contextlib позволяет писать их короче, с помощью генераторов:from contextlib import contextmanager
@contextmanager
def open_file(path, mode="r"):
f = open(path, mode)
try:
yield f # то, что вернётся в "as"
finally:
f.close() # выполнится всегда
with open_file("data.txt") as f:
data = f.read()
Всё, что до
yield, — это логика __enter__, а всё после — __exit__.---
### Практический пример: временная смена текущей директории
import os
from contextlib import contextmanager
@contextmanager
def change_dir(path):
old_dir = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(old_dir)
print(os.getcwd())
with change_dir("/tmp"):
print(os.getcwd())
print(os.getcwd())
Контекст гарантирует, что директория вернётся к исходной даже при ошибках внутри блока
with.---
### Когда стоит использовать контекстные менеджеры
- работа с файлами и сетевыми соединениями;
- блокировки потоков и транзакции в БД;
- временные настройки (логирование, окружение, директории);
- любые ресурсы, которые надо обязательно освободить.
Контекстный менеджер — это способ формально описать жизненный цикл ресурса: “взял → поработал → убрал за собой”, и
contextlib делает это описание максимально коротким и наглядным.🔥2👍1
Мини-проекты с модулем
Если стандартный «учебник по Python» навевает зевоту, попробуем другой путь: будем учиться, рисуя. Модуль
---
### 1. Старт: первые линии
Минимальный пример — уже маленький проект:
Ключевые команды:
-
-
-
Этого уже достаточно, чтобы строить геометрию и тренировать циклы.
---
### 2. Мини-проект: генератор квадратных мандал
Потренируемся в циклах и функциях: нарисуем «мандалу» из квадратов.
Что мы закрепляем:
- функции (
- цикл
-
Измените шаг
---
### 3. Мини-проект: случайный фейерверк
Теперь подключим случайность и познакомимся с модулем
Что осваиваем:
-
- работу с координатами
- фон окна
---
### 4. Зачем это всё?
Такие мини-проекты:
- снимают «страх кода» — результат видно сразу;
- закрепляют основы: циклы, функции, модули, случайные числа;
- развивают интуицию: меняете одну строку — картина меняется заметно.
Попробуйте усложнить проекты: добавить управление с клавиатуры, анимацию движения, счётчик шагов.
turtle: обучаемся, рисуяЕсли стандартный «учебник по Python» навевает зевоту, попробуем другой путь: будем учиться, рисуя. Модуль
turtle входит в стандартную библиотеку Python, так что ничего дополнительно устанавливать не нужно — только открыть воображение.---
### 1. Старт: первые линии
Минимальный пример — уже маленький проект:
import turtle
t = turtle.Turtle()
t.speed(3)
t.forward(100)
t.left(90)
t.forward(100)
turtle.done()
Ключевые команды:
-
forward(n) — черепашка едет вперед на n пикселей -
left(angle) / right(angle) — поворот -
penup() / pendown() — перо вверх/вниз (рисовать или нет)Этого уже достаточно, чтобы строить геометрию и тренировать циклы.
---
### 2. Мини-проект: генератор квадратных мандал
Потренируемся в циклах и функциях: нарисуем «мандалу» из квадратов.
import turtle
t = turtle.Turtle()
t.speed(0)
t.color("blue")
def draw_square(side):
for _ in range(4):
t.forward(side)
t.left(90)
for angle in range(0, 360, 10):
t.setheading(angle)
draw_square(100)
turtle.done()
Что мы закрепляем:
- функции (
def draw_square) - цикл
for с шагом 10 -
setheading(angle) — задаём абсолютный угол поворотаИзмените шаг
10 на 5 или 20, длину стороны, цвет — наглядное «чувство кода» появляется очень быстро.---
### 3. Мини-проект: случайный фейерверк
Теперь подключим случайность и познакомимся с модулем
random.import turtle
import random
t = turtle.Turtle()
t.speed(0)
turtle.bgcolor("black")
colors = ["red", "yellow", "orange", "cyan", "magenta", "white"]
def draw_burst(radius):
t.color(random.choice(colors))
for _ in range(12):
t.forward(radius)
t.backward(radius)
t.right(360 / 12)
for _ in range(20):
t.penup()
x = random.randint(-300, 300)
y = random.randint(-200, 200)
t.goto(x, y)
t.pendown()
draw_burst(random.randint(30, 80))
turtle.done()
Что осваиваем:
-
random.randint и random.choice- работу с координатами
goto(x, y)- фон окна
bgcolor---
### 4. Зачем это всё?
Такие мини-проекты:
- снимают «страх кода» — результат видно сразу;
- закрепляют основы: циклы, функции, модули, случайные числа;
- развивают интуицию: меняете одну строку — картина меняется заметно.
Попробуйте усложнить проекты: добавить управление с клавиатуры, анимацию движения, счётчик шагов.
turtle — отличный полигон, чтобы сделать первые шаги в Python творческими, а не скучными.🔥3👍1
Применение
В Python есть два маленьких, но очень мощных инструмента для подсчета данных:
---
##
### Подсчет слов в тексте
Что удобно:
-
- метод
- можно складывать, вычитать, объединять счетчики как числа.
### Подсчет символов в строке
Ни одного
---
##
Обычный словарь при обращении к несуществующему ключу вызывает ошибку.
### Группировка по ключу
Допустим, нужно сгруппировать студентов по курсу:
Без
### Словарь-счетчик на
По сути, это «ручная версия»
---
## Когда что использовать
- Нужен простой подсчет частот + топы, суммы, комбинации —
- Нужна сложная структура вроде «ключ → список», «ключ → множество» или нестандартная логика инициализации —
Оба инструмента отлично заходят в задачах обработки логов, текста, статистики, простых аналитических вычислений. Освоив их, вы перестанете писать однообразные шаблоны с проверками «а есть ли уже этот ключ» и сосредоточитесь на самой задаче.
Counter и defaultdict в задачах подсчета данныхВ Python есть два маленьких, но очень мощных инструмента для подсчета данных:
Counter и defaultdict из модуля collections. Они экономят десятки строк кода и делают задачи подсчета почти «одноходовками».---
##
Counter: карманный статистикCounter — это специализированный словарь для подсчета количества объектов. Внутри — обычный dict, но с удобным интерфейсом.### Подсчет слов в тексте
from collections import Counter
text = "python is great and python is simple"
words = text.split()
word_counts = Counter(words)
print(word_counts)
print(word_counts.most_common(2)) # 2 самых частых слова
Что удобно:
-
Counter сам инициализирует счетчики с нуля;- метод
most_common() сразу выдает топ-N элементов;- можно складывать, вычитать, объединять счетчики как числа.
### Подсчет символов в строке
from collections import Counter
s = "abracadabra"
char_counts = Counter(s)
for char, count in char_counts.items():
print(char, count)
Ни одного
if key not in dict — всё уже встроено.---
##
defaultdict: умный словарь с «значением по умолчанию»Обычный словарь при обращении к несуществующему ключу вызывает ошибку.
defaultdict сам создает значение, используя функцию, которую вы ему передадите.### Группировка по ключу
Допустим, нужно сгруппировать студентов по курсу:
from collections import defaultdict
students = [
("Alice", 1),
("Bob", 2),
("Charlie", 1),
("Diana", 3),
]
by_course = defaultdict(list)
for name, course in students:
by_course[course].append(name)
print(by_course)
Без
defaultdict пришлось бы каждый раз проверять, есть ли уже такой курс в словаре.### Словарь-счетчик на
defaultdictdefaultdict легко превращается в счетчик:from collections import defaultdict
nums = [1, 2, 1, 3, 2, 1]
counts = defaultdict(int)
for n in nums:
counts[n] += 1
print(counts)
По сути, это «ручная версия»
Counter, но зато более гибкая.---
## Когда что использовать
- Нужен простой подсчет частот + топы, суммы, комбинации —
Counter.- Нужна сложная структура вроде «ключ → список», «ключ → множество» или нестандартная логика инициализации —
defaultdict.Оба инструмента отлично заходят в задачах обработки логов, текста, статистики, простых аналитических вычислений. Освоив их, вы перестанете писать однообразные шаблоны с проверками «а есть ли уже этот ключ» и сосредоточитесь на самой задаче.
👍3
Использование
Если вы ещё пишете циклы с кучей счётчиков и временных списков — велика вероятность, что
---
### 1.
Типичный «новичковый» код:
То же самое с
Где это реально полезно?
#### Пример: нумерация строк в отчёте
Флаг
---
### 2.
#### Пример: из двух списков — словарь
---
### 3.
Есть «таблица» как список строк:
Хотим столбцы вместо строк:
Так можно, например, быстро посчитать максимум по каждому столбцу:
---
### 4. Комбо:
Допустим, нужно сравнить правильные ответы и ответы пользователя, а также вывести номер вопроса, где ошибка:
Здесь
---
zip и enumerate в реальных задачахЕсли вы ещё пишете циклы с кучей счётчиков и временных списков — велика вероятность, что
zip и enumerate уже могут сделать ваш код проще и понятнее. Разберёмся на практических примерах.---
### 1.
enumerate: когда индекс нужен по делуТипичный «новичковый» код:
items = ["apple", "banana", "orange"]
for i in range(len(items)):
print(i, items[i])
То же самое с
enumerate в разы чище:items = ["apple", "banana", "orange"]
for idx, item in enumerate(items):
print(idx, item)
Где это реально полезно?
#### Пример: нумерация строк в отчёте
lines = ["Login ok", "Wrong password", "Timeout", "Login ok"]
for line_no, line in enumerate(lines, start=1):
if "Wrong" in line:
print(f"Error on line {line_no}: {line}")
Флаг
start=1 удобен, когда нужно человеческое (а не компьютерное) номерование.---
### 2.
zip: связываем несколько списковzip шагает по нескольким итерируемым объектам одновременно:names = ["Alice", "Bob", "Charlie"]
scores = [95, 82, 100]
for name, score in zip(names, scores):
print(f"{name}: {score}")
#### Пример: из двух списков — словарь
keys = ["host", "port", "use_ssl"]
values = ["example.com", 443, True]
config = dict(zip(keys, values))
print(config)
# {'host': 'example.com', 'port': 443, 'use_ssl': True}
---
### 3.
zip + распаковка: транспонирование таблицЕсть «таблица» как список строк:
rows = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
Хотим столбцы вместо строк:
cols = list(zip(*rows))
print(cols)
# [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
Так можно, например, быстро посчитать максимум по каждому столбцу:
max_by_col = [max(col) for col in zip(*rows)]
print(max_by_col) # [7, 8, 9]
---
### 4. Комбо:
enumerate + zip в задаче валидацииДопустим, нужно сравнить правильные ответы и ответы пользователя, а также вывести номер вопроса, где ошибка:
correct = ["A", "C", "B", "D"]
user = ["A", "B", "B", "D"]
for idx, (right, given) in enumerate(zip(correct, user), start=1):
if right != given:
print(f"Question {idx}: expected {right}, got {given}")
Здесь
zip связывает пары ответов, а enumerate даёт нам номер вопроса — минимальный код, максимальная читабельность.---
zip и enumerate — это не «фишечки для красоты», а инструменты, которые убирают лишний шум из кода. Как только начнёте видеть паттерны «мне нужен индекс» и «я иду по нескольким спискам сразу», эти функции станут вашей ежедневной привычкой.👍3🔥2