Python для начинающих
1.24K subscribers
546 photos
3 videos
232 files
74 links
Python для начинающих
Download Telegram
Подключение и использование конфигурационных файлов с configparser
Python для начинающих: configparser — приручаем конфиги как профи

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

---

### Как выглядит конфиг

Создадим файл settings.ini:

[database]
host = localhost
port = 5432
user = admin
password = secret

[logging]
level = DEBUG
file = app.log


Структура проста: секции в квадратных скобках и пары ключ = значение.

---

### Чтение конфигурации

from configparser import ConfigParser

config = ConfigParser()
config.read("settings.ini")

db_host = config["database"]["host"]
db_port = config.getint("database", "port")
log_level = config.get("logging", "level", fallback="INFO")

print(db_host, db_port, log_level)


Ключевые моменты:

- config["section"]["option"] — базовый доступ.
- getint, getfloat, getboolean — сразу приводят к нужному типу.
- fallback спасает, если ключа нет.

---

### Изменение и сохранение конфига

from configparser import ConfigParser

config = ConfigParser()
config.read("settings.ini")

config["database"]["host"] = "db.mycompany.com"

if "feature_flags" not in config:
config["feature_flags"] = {}
config["feature_flags"]["new_ui"] = "true"

with open("settings.ini", "w") as configfile:
config.write(configfile)


Так можно не только читать, но и аккуратно обновлять настройки.

---

### Конфиг по умолчанию

Иногда нужно задать значения «на всякий случай»:

from configparser import ConfigParser

config = ConfigParser(
defaults={
"level": "INFO",
"file": "app.log"
}
)

config.read("settings.ini")

log_level = config["logging"]["level"] # если нет в секции, возьмёт из defaults
log_file = config["logging"]["file"]


---

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

- разные настройки для dev / prod без изменения кода;
- хранение секретов вне репозитория (через отдельный local_settings.ini);
- быстрое переключение фич через флаги.

configparser — простой, но мощный способ отделить код от настроек. Один раз настроили структуру .ini — и дальше ваш код становится гораздо чище и гибче.
👍1
Использование pathlib для работы с путями и файлами
Python для начинающих: как pathlib спасет вас от хаоса с путями

Если вы хоть раз писали что-то вроде:

file_path = "C:\\Users\\user\\projects\\data\\file.txt"


и ловили ошибки из‑за слэшей и кодировок, то модуль pathlib — ваш новый лучший друг. Он превращает работу с путями и файлами в аккуратные объектные операции, вместо бесконечной возни со строками.

---

### Базовая идея: Path вместо строк

Главный герой — класс Path:

from pathlib import Path

base_dir = Path.home() / "projects" / "demo"
print(base_dir)


Оператор / здесь не делит, а красиво склеивает части пути, независимо от ОС (Windows, Linux, macOS). Никаких os.path.join, никаких ручных слэшей.

---

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

pathlib сразу умеет отвечать на важные вопросы:

from pathlib import Path

path = Path("data/example.txt")

print(path.exists()) # файл или папка есть?
print(path.is_file()) # это файл?
print(path.is_dir()) # это папка?


Можно безопасно проверять перед чтением или удалением.

---

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

Чтение и запись — это методы объекта пути:

from pathlib import Path

file_path = Path("data/notes.txt")

# запись текста
file_path.write_text("Hello, pathlib!", encoding="utf-8")

# чтение текста
content = file_path.read_text(encoding="utf-8")
print(content)


Не нужно вручную открывать и закрывать файлы — Path делает это за вас.

---

### Создание папок и обход директорий

Создать дерево каталогов и пройтись по файлам — одна строка:

from pathlib import Path

base = Path("logs/app")

# создаем все недостающие каталоги
base.mkdir(parents=True, exist_ok=True)

# ищем все .log файлы в подпапках
for log_file in base.rglob("*.log"):
print(log_file.name, log_file.stat().st_size, "bytes")


Метод rglob рекурсивно ищет файлы по шаблону, stat() дает информацию о файле.

---

### Работа с именами, расширениями и родителями

Разбирать путь по частям стало легко:

from pathlib import Path

path = Path("data/archive/report_2024.csv")

print(path.name) # report_2024.csv
print(path.stem) # report_2024
print(path.suffix) # .csv
print(path.parent) # data/archive

new_path = path.with_suffix(".xlsx")
print(new_path) # data/archive/report_2024.xlsx


---

### Почему стоит перейти на pathlib уже сейчас

- Кроссплатформенно: один и тот же код под Windows и Linux.
- Читаемо: Path‑объекты ведут себя как реальные объекты, а не как странные строки.
- Богатый функционал: от обхода директорий до смены расширений.

Если вы еще работаете с путями как со строками — попробуйте переписать небольшой скрипт на pathlib. Скорее всего, назад уже не захочется.
🔥2
Создание простых HTTP-запросов вручную с модулем http.client
Создание простых 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
Понимание работы контекстных менеджеров и создание своих с помощью contextlib
Понимание работы контекстных менеджеров и создание своих с помощью 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
Мини-проекты с модулем turtle: обучаемся, рисуя
Мини-проекты с модулем 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
Применение Counter и defaultdict в задачах подсчета данных
👍2
Применение 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 пришлось бы каждый раз проверять, есть ли уже такой курс в словаре.

### Словарь-счетчик на defaultdict

defaultdict легко превращается в счетчик:

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
Использование zip и enumerate в реальных задачах
Использование 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