Как использовать
Одна из самых частых задач в Python — избавиться от дубликатов в списке. Можно писать циклы, проверять, есть ли элемент в новом списке… а можно использовать встроенный тип
### Что такое
Ключевые свойства:
- в
- элементы должны быть хешируемыми (числа, строки, кортежи и т.д.);
- порядок не гарантируется.
Создать множество из списка можно так:
Мы просто «заставили» Python выкинуть всё лишнее.
### Возврат к списку без дубликатов
Часто нужен именно список (с индексами и возможностью изменять элементы). Тогда:
Важно: порядок элементов может измениться. Для чисел это обычно не критично, но для, скажем, событий во времени — уже проблема.
### Как сохранить порядок и убрать дубликаты?
Комбинируем
Здесь:
-
-
### Короткая версия через
Если важен порядок, но не хочется писать цикл:
До Python 3.7 порядок ключей в
### Где это полезно?
- очистка списков e-mail адресов от повторов;
- фильтрация тегов;
- удаление дубликатов из данных перед анализом.
Главное:
set для удаления дубликатов из спискаОдна из самых частых задач в Python — избавиться от дубликатов в списке. Можно писать циклы, проверять, есть ли элемент в новом списке… а можно использовать встроенный тип
set и сделать всё в одну строку.### Что такое
set?set — это множество: неупорядоченная коллекция уникальных элементов. Ключевые свойства:
- в
set не бывает дубликатов;- элементы должны быть хешируемыми (числа, строки, кортежи и т.д.);
- порядок не гарантируется.
Создать множество из списка можно так:
numbers = [1, 2, 2, 3, 3, 3]
unique_numbers = set(numbers)
print(unique_numbers) # {1, 2, 3}
Мы просто «заставили» Python выкинуть всё лишнее.
### Возврат к списку без дубликатов
Часто нужен именно список (с индексами и возможностью изменять элементы). Тогда:
numbers = [1, 2, 2, 3, 3, 3]
unique_list = list(set(numbers))
print(unique_list) # порядок не гарантируется
Важно: порядок элементов может измениться. Для чисел это обычно не критично, но для, скажем, событий во времени — уже проблема.
### Как сохранить порядок и убрать дубликаты?
Комбинируем
set и цикл:items = ["a", "b", "a", "c", "b", "d"]
seen = set()
result = []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
print(result) # ['a', 'b', 'c', 'd']
Здесь:
-
seen хранит уже встреченные элементы;-
result — итоговый список без повторов, в исходном порядке.### Короткая версия через
dict.fromkeysЕсли важен порядок, но не хочется писать цикл:
items = ["a", "b", "a", "c", "b", "d"]
result = list(dict.fromkeys(items))
print(result) # ['a', 'b', 'c', 'd']
До Python 3.7 порядок ключей в
dict официально не гарантировался, но в современных версиях этот трюк работает надёжно.### Где это полезно?
- очистка списков e-mail адресов от повторов;
- фильтрация тегов;
- удаление дубликатов из данных перед анализом.
Главное:
set — быстрый и простой способ получить уникальные значения. Используйте set, когда порядок не важен, и сочетайте его с дополнительной логикой, когда порядок нужно сохранить.👍3🔥1
Создание простых Webhook-обработчиков с Flask
Иногда нужно, чтобы ваш скрипт реагировал на внешние события: оплата на сайте, новый комментарий в соцсети, пуш из GitHub и т.п. Сервисы решают это через webhooks — они отправляют HTTP-запросы (обычно
Самый простой способ в Python — мини-фреймворк Flask.
---
### Минимальный Webhook на Flask
Установим Flask:
Создадим
Что тут важно:
-
-
- Возвращаем JSON-ответ и HTTP-код 200, чтобы внешний сервис понял, что все прошло успешно.
---
### Как протестировать без реального сервиса
Можно «прикинуться» внешним сервисом с помощью
В консоли сервера вы увидите распечатанный JSON.
---
### Добавляем простую проверку подписи
Реальные сервисы почти всегда подписывают запросы, чтобы никто не мог отправить фальшивый webhook. Простейший вариант — общий секрет и заголовок с HMAC:
Ключевые моменты:
- Используем
-
- При неверной подписи сразу возвращаем 401.
---
### Зачем это все начинающему?
Webhook-обработчик — это реальная задачка уровня «боевого» кода:
- вы работаете с HTTP, JSON, заголовками и кодами ответа;
- думаете о безопасности (подписи, проверка метода);
- учитесь разделять «прием запроса» и «бизнес-логику».
А Flask позволяет уложить все это в несколько десятков строк понятного кода — отличный старт для вхождения в мир веб-разработки на Python.
Иногда нужно, чтобы ваш скрипт реагировал на внешние события: оплата на сайте, новый комментарий в соцсети, пуш из GitHub и т.п. Сервисы решают это через webhooks — они отправляют HTTP-запросы (обычно
POST) на ваш URL. Ваша задача — принять запрос и что-то сделать.Самый простой способ в Python — мини-фреймворк Flask.
---
### Минимальный Webhook на Flask
Установим Flask:
pip install flask
Создадим
app.py:from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/webhook", methods=["POST"])
def webhook_handler():
data = request.get_json(silent=True) or {}
event_type = data.get("event", "unknown")
# Примитивная обработка события
if event_type == "payment_succeeded":
# здесь могла бы быть запись в базу или отправка email
print("Payment succeeded:", data)
else:
print("Unknown event:", data)
return jsonify({"status": "ok"}), 200
if __name__ == "__main__":
app.run(port=5000, debug=True)
Что тут важно:
-
methods=["POST"] — принимаем только POST (классический формат webhook’ов).-
request.get_json() — достаем JSON-тело запроса.- Возвращаем JSON-ответ и HTTP-код 200, чтобы внешний сервис понял, что все прошло успешно.
---
### Как протестировать без реального сервиса
Можно «прикинуться» внешним сервисом с помощью
curl:curl -X POST http://127.0.0.1:5000/webhook \
-H "Content-Type: application/json" \
-d '{"event":"payment_succeeded","amount":1500}'
В консоли сервера вы увидите распечатанный JSON.
---
### Добавляем простую проверку подписи
Реальные сервисы почти всегда подписывают запросы, чтобы никто не мог отправить фальшивый webhook. Простейший вариант — общий секрет и заголовок с HMAC:
import hmac
import hashlib
from flask import abort
SECRET_TOKEN = "super-secret-key"
def verify_signature(raw_body: bytes, received_signature: str) -> bool:
mac = hmac.new(SECRET_TOKEN.encode(), msg=raw_body, digestmod=hashlib.sha256)
expected_sig = mac.hexdigest()
return hmac.compare_digest(expected_sig, received_signature or "")
@app.route("/secure-webhook", methods=["POST"])
def secure_webhook():
raw_body = request.data
signature = request.headers.get("X-Signature")
if not verify_signature(raw_body, signature):
abort(401, description="Invalid signature")
payload = request.get_json(silent=True) or {}
print("Secure event:", payload)
return jsonify({"status": "accepted"}), 200
Ключевые моменты:
- Используем
request.data, а не уже разобранный JSON — подпись считается по «сырому» телу.-
hmac.compare_digest защищает от атак по времени сравнения.- При неверной подписи сразу возвращаем 401.
---
### Зачем это все начинающему?
Webhook-обработчик — это реальная задачка уровня «боевого» кода:
- вы работаете с HTTP, JSON, заголовками и кодами ответа;
- думаете о безопасности (подписи, проверка метода);
- учитесь разделять «прием запроса» и «бизнес-логику».
А Flask позволяет уложить все это в несколько десятков строк понятного кода — отличный старт для вхождения в мир веб-разработки на Python.
👍4
Работа с emoji и цветными иконками в консоли Python
Консоль не обязана быть скучной. Немного emoji и цвета — и ваш скрипт начинает «разговаривать» с пользователем гораздо живее. Разберём три простых приёма: Unicode-emoji, библиотеку
---
## 1. Emoji по‑простому: через Unicode
Многие emoji — это обычные Unicode-символы. Достаточно вставить их прямо в строку:
Если консоль и шрифт поддерживают Unicode, всё просто заработает.
Иногда полезно использовать кодовую точку:
---
## 2. Библиотека
Когда хочется писать
Установка:
Использование:
Полезные фишки:
-
- Можно хранить «коды» в файлах настроек и подставлять emoji при выводе.
---
## 3. Цветной текст с
Установка:
Минимальный пример:
Ключевые элементы:
-
-
-
---
## 4. Комбинируем: мини‑панель статуса
Итог: пара библиотек + Unicode — и ваша консоль превращается из серого лога в удобную и наглядную панель. Это особенно выручает в CLI‑утилитах, мини‑играх и учебных проектах, где хочется мгновенно различать успех, ошибку и предупреждения.
Консоль не обязана быть скучной. Немного emoji и цвета — и ваш скрипт начинает «разговаривать» с пользователем гораздо живее. Разберём три простых приёма: Unicode-emoji, библиотеку
emoji и цветной вывод через colorama.---
## 1. Emoji по‑простому: через Unicode
Многие emoji — это обычные Unicode-символы. Достаточно вставить их прямо в строку:
print("Task completed ✅")
print("Warning ⚠️")
print("Python is fun 🐍")
Если консоль и шрифт поддерживают Unicode, всё просто заработает.
Иногда полезно использовать кодовую точку:
smile = "\U0001F600" # 😀
print(f"Hello {smile}")
---
## 2. Библиотека
emojiКогда хочется писать
:smile: вместо поиска нужного символа.Установка:
pip install emoji
Использование:
import emoji
text = emoji.emojize(
"Server status: :green_circle: Running, :red_circle: Stopped",
language="alias"
)
print(text)
Полезные фишки:
-
emoji.demojize("Hello 😀") → "Hello :grinning_face:"- Можно хранить «коды» в файлах настроек и подставлять emoji при выводе.
---
## 3. Цветной текст с
coloramacolorama кроссплатформенно добавляет цвет в консоль (особенно удобно на Windows).Установка:
pip install colorama
Минимальный пример:
from colorama import init, Fore, Style
init(autoreset=True)
print(Fore.GREEN + "Success ✅")
print(Fore.YELLOW + "Loading... ⏳")
print(Fore.RED + "Error ❌")
print(Style.DIM + "This is a low-priority message")
Ключевые элементы:
-
Fore.RED, Fore.GREEN, Fore.YELLOW и др. — цвет текста.-
Style.BRIGHT, Style.DIM, Style.NORMAL — «стиль» текста.-
autoreset=True избавляет от необходимости вручную сбрасывать цвет.---
## 4. Комбинируем: мини‑панель статуса
from colorama import init, Fore
import emoji
import time
init(autoreset=True)
def show_status(message, ok=True):
icon = ":check_mark_button:" if ok else ":cross_mark:"
icon = emoji.emojize(icon, language="alias")
color = Fore.GREEN if ok else Fore.RED
print(color + icon, message)
show_status("Connecting to database...")
time.sleep(1)
show_status("Connected", ok=True)
show_status("Failed to fetch data", ok=False)
Итог: пара библиотек + Unicode — и ваша консоль превращается из серого лога в удобную и наглядную панель. Это особенно выручает в CLI‑утилитах, мини‑играх и учебных проектах, где хочется мгновенно различать успех, ошибку и предупреждения.
👍3
Как использовать
Если обычные циклы
---
## Бесконечные последовательности без боли
---
## Перебор сочетаний, перестановок и не только
Такие функции идеально подходят для перебора вариантов в брутфорс-задачах, тестировании, комбинаторике.
Декартово произведение:
Это мощнее вложенных циклов и проще читается.
---
## Умная фильтрация и группировка
Группировка подряд идущих одинаковых элементов:
Полезно для простого сжатия или анализа последовательностей.
---
## Комбинирование итераторов как конструктор
---
itertools: новый взгляд на циклы и генераторыЕсли обычные циклы
for — это отвертка, то модуль itertools — целый чемодан инструментов. Он позволяет писать короче, читать легче и иногда вообще обходиться без явных циклов.---
## Бесконечные последовательности без боли
from itertools import count, cycle, repeat
for i in count(10, 2): # 10, 12, 14, ...
if i > 20:
break
print(i)
count(start, step) создает бесконечный счетчик. Безопасность — на вас: обязательно ставьте break.colors = ["red", "green", "blue"]
for c, n in zip(cycle(colors), range(5)):
print(c)
cycle(iterable) зацикливает список. Удобно для повторяющихся паттернов.for x in repeat("hello", 3):
print(x)
repeat(obj, times) — ленивый клон объекта.---
## Перебор сочетаний, перестановок и не только
from itertools import permutations, combinations, product
letters = ["a", "b", "c"]
print(list(permutations(letters, 2))) # Порядок важен
print(list(combinations(letters, 2))) # Порядок не важен
Такие функции идеально подходят для перебора вариантов в брутфорс-задачах, тестировании, комбинаторике.
Декартово произведение:
sizes = ["S", "M"]
colors = ["black", "white"]
for combo in product(sizes, colors):
print(combo)
Это мощнее вложенных циклов и проще читается.
---
## Умная фильтрация и группировка
from itertools import compress
data = [10, 20, 30, 40]
selectors = [True, False, True, False]
print(list(compress(data, selectors))) # [10, 30]
compress фильтрует элементы по маске логических значений.Группировка подряд идущих одинаковых элементов:
from itertools import groupby
data = "aaabbccccd"
for char, group in groupby(data):
print(char, len(list(group)))
# a 3, b 2, c 4, d 1
Полезно для простого сжатия или анализа последовательностей.
---
## Комбинирование итераторов как конструктор
from itertools import chain, islice
data1 = [1, 2]
data2 = [3, 4, 5]
merged = chain(data1, data2) # ленивое "склеивание"
print(list(islice(merged, 0, 4))) # берём только первые 4
chain объединяет несколько источников, а islice позволяет "отрезать" нужный кусок без создания лишних списков.---
itertools — про ленивость и композицию. Вместо того чтобы писать сложные циклы, вы собираете поведение из маленьких строительных блоков. Результат — короче код, меньше ошибок и приятное ощущение "Python-стиля".👍3
Работа с
Стандартные списки и словари — отличная вещь, но модуль
---
###
Где полезно: подсчёт частоты слов в тексте, статистика действий пользователей, анализ логов.
---
###
Обычный словарь бросит
Где полезно: группировка данных, инвертирование словарей, построение графов (списки соседей).
---
###
Обычный кортеж непонятен:
Где полезно: лёгкие «объекты без классов» — координаты, настройки, параметры функций. Иммутабельность помогает избежать случайных изменений.
---
###
Список плохо работает с
Где полезно: очереди задач, реализовать стек/очередь, «скользящее окно» последних N элементов.
---
###
С Python 3.7 обычный
---
Модуль
collections: полезные структуры данных и где их использоватьСтандартные списки и словари — отличная вещь, но модуль
collections превращает их в инструменты «профессионального уровня». Разберём ключевые структуры, которые реально упрощают код.---
###
Counter: считаем всё подрядCounter — словарь для подсчёта объектов.from collections import Counter
text = "banana bandana"
counter = Counter(text)
print(counter) # сколько раз встречается каждый символ
print(counter.most_common(2)) # два самых частых
Где полезно: подсчёт частоты слов в тексте, статистика действий пользователей, анализ логов.
---
###
defaultdict: словарь, который не ругается на новые ключиОбычный словарь бросит
KeyError, если ключа нет. defaultdict автоматически создаёт значение по умолчанию.from collections import defaultdict
groups = defaultdict(list)
data = [("cat", 1), ("dog", 2), ("cat", 3)]
for animal, value in data:
groups[animal].append(value)
print(groups) # {'cat': [1, 3], 'dog': [2]}
Где полезно: группировка данных, инвертирование словарей, построение графов (списки соседей).
---
###
namedtuple: читаемые «кортежи с именами»Обычный кортеж непонятен:
user[0], user[1]… namedtuple даёт имена полям.from collections import namedtuple
User = namedtuple("User", ["name", "age"])
user = User(name="Alice", age=30)
print(user.name)
print(user.age)
Где полезно: лёгкие «объекты без классов» — координаты, настройки, параметры функций. Иммутабельность помогает избежать случайных изменений.
---
###
deque: очередь и стек без тормозовСписок плохо работает с
pop(0) — это O(n). deque оптимизирован для добавления/удаления с обоих концов.from collections import deque
queue = deque()
queue.append("task1")
queue.append("task2")
queue.appendleft("urgent")
print(queue.popleft()) # 'urgent'
print(queue.pop()) # 'task2'
Где полезно: очереди задач, реализовать стек/очередь, «скользящее окно» последних N элементов.
---
###
OrderedDict: порядок тоже важенС Python 3.7 обычный
dict уже запоминает порядок вставки, но OrderedDict всё ещё полезен там, где нужны дополнительные операции (например, move_to_end). В современных проектах используют реже, но стоит знать о его существовании.---
Модуль
collections — это набор готовых решений для типичных задач работы с данными. Зная эти структуры, вы часто пишете меньше кода, делаете его быстрее и понятнее — и меньше изобретаете велосипеды.👍4
Создание генераторов: экономим память при обработке больших данных
Представьте, что вам нужно обработать файл на 10 ГБ, посчитать суммы, отфильтровать строки, что‑то преобразовать. Если пытаться «затащить» всё в память списками — привет,
Генератор — это «ленивый» источник данных: он отдаёт элементы по одному, по запросу, не храня весь результат сразу. Именно поэтому генераторы так хорошо подходят для больших данных и потоковой обработки.
### Генераторные выражения
Список:
держит в памяти все 10 млн элементов.
Генератор:
хранит только текущее состояние итерации. Память почти не растёт, пока вы не начинаете обходить
### Собственные генераторные функции
Ключевое слово
Здесь не создаётся список строк файла — каждая строка обрабатывается по мере чтения:
Файл может быть гигантским — программа использует почти столько же памяти, как и при чтении маленького файла.
### Конвейер из генераторов
Самое интересное начинается, когда вы соединяете генераторы в цепочку — получается «конвейер»:
Каждый шаг обрабатывает элементы по одному: прочитали строку → превратили в число → отфильтровали → учли в сумме. Никаких огромных временных списков.
### Когда использовать генераторы
- Обработка больших файлов и потоков данных.
- Длинные вычисления, результат которых нужен по частям.
- Организация удобных «ленивых» API (итераторы вместо списков).
Генераторы — это простой способ сделать код и аккуратнее, и экономичнее по памяти, не усложняя архитектуру. Если вы уже пишете списковые включения, вы почти готовы использовать генераторы — достаточно заменить
Представьте, что вам нужно обработать файл на 10 ГБ, посчитать суммы, отфильтровать строки, что‑то преобразовать. Если пытаться «затащить» всё в память списками — привет,
MemoryError. Здесь на сцену выходят генераторы.Генератор — это «ленивый» источник данных: он отдаёт элементы по одному, по запросу, не храня весь результат сразу. Именно поэтому генераторы так хорошо подходят для больших данных и потоковой обработки.
### Генераторные выражения
Список:
nums = [i * 2 for i in range(10_000_000)]
держит в памяти все 10 млн элементов.
Генератор:
nums_gen = (i * 2 for i in range(10_000_000))
хранит только текущее состояние итерации. Память почти не растёт, пока вы не начинаете обходить
nums_gen:total = 0
for value in nums_gen:
total += value
### Собственные генераторные функции
Ключевое слово
yield превращает функцию в генератор:def read_large_file(path):
with open(path, 'r', encoding='utf-8') as f:
for line in f:
yield line.strip()
Здесь не создаётся список строк файла — каждая строка обрабатывается по мере чтения:
def iter_error_lines(path):
for line in read_large_file(path):
if 'ERROR' in line:
yield line
for err_line in iter_error_lines('app.log'):
print(err_line)
Файл может быть гигантским — программа использует почти столько же памяти, как и при чтении маленького файла.
### Конвейер из генераторов
Самое интересное начинается, когда вы соединяете генераторы в цепочку — получается «конвейер»:
def iter_numbers(path):
for line in read_large_file(path):
if line and line[0].isdigit():
yield int(line)
def filter_even(seq):
for n in seq:
if n % 2 == 0:
yield n
def sum_limited(seq, limit):
total = 0
for n in seq:
total += n
if total > limit:
break
return total
numbers = iter_numbers('numbers.txt')
even_numbers = filter_even(numbers)
result = sum_limited(even_numbers, limit=1_000_000)
print(result)
Каждый шаг обрабатывает элементы по одному: прочитали строку → превратили в число → отфильтровали → учли в сумме. Никаких огромных временных списков.
### Когда использовать генераторы
- Обработка больших файлов и потоков данных.
- Длинные вычисления, результат которых нужен по частям.
- Организация удобных «ленивых» API (итераторы вместо списков).
Генераторы — это простой способ сделать код и аккуратнее, и экономичнее по памяти, не усложняя архитектуру. Если вы уже пишете списковые включения, вы почти готовы использовать генераторы — достаточно заменить
[] на ().👍1🔥1
Python для начинающих: как
Когда в коде появляются «магические числа» и странные строки, читаемость падает. Встречали что‑то вроде:
Через неделю уже непонятно, что такое
---
## Что такое
Теперь вместо
---
## Пример: читаемый
До:
После:
Что улучшилось:
- код сам документирует возможные статусы;
- меньше шансов перепутать значения;
- IDE подсказывает варианты (
---
##
Частая ловушка — сравнение со строками:
Опечатка — и проверка ломается. С
---
## Небольшой бонус: словари с
Здесь невозможно случайно обратиться к
---
enum делает код понятнееКогда в коде появляются «магические числа» и странные строки, читаемость падает. Встречали что‑то вроде:
if status == 3:
send_email()
Через неделю уже непонятно, что такое
3. Ошибка не в логике — ошибка в обозначениях. Здесь на сцену выходит модуль enum.---
## Что такое
Enum?Enum (перечисление) — это способ задать набор именованных констант. Вместо чисел и строк, разбросанных по коду, вы используете говорящие имена.from enum import Enum
class OrderStatus(Enum):
NEW = 1
PAID = 2
SHIPPED = 3
CANCELED = 4
Теперь вместо
3 у вас есть OrderStatus.SHIPPED. Код сразу объясняет сам себя.---
## Пример: читаемый
ifДо:
def handle_order(status):
if status == 1:
print("Create invoice")
elif status == 2:
print("Prepare shipment")
elif status == 3:
print("Send tracking code")
После:
from enum import Enum
class OrderStatus(Enum):
NEW = 1
PAID = 2
SHIPPED = 3
def handle_order(status: OrderStatus):
if status is OrderStatus.NEW:
print("Create invoice")
elif status is OrderStatus.PAID:
print("Prepare shipment")
elif status is OrderStatus.SHIPPED:
print("Send tracking code")
Что улучшилось:
- код сам документирует возможные статусы;
- меньше шансов перепутать значения;
- IDE подсказывает варианты (
OrderStatus. → список).---
##
Enum вместо строкЧастая ловушка — сравнение со строками:
if role == "admin":
...
Опечатка — и проверка ломается. С
Enum:from enum import Enum, auto
class UserRole(Enum):
ADMIN = auto()
EDITOR = auto()
VIEWER = auto()
def can_delete(user_role: UserRole) -> bool:
return user_role is UserRole.ADMIN
auto() сам проставит уникальные значения — нас интересуют не числа, а имена.---
## Небольшой бонус: словари с
EnumEnum удобно использовать как ключи:from enum import Enum, auto
class LogLevel(Enum):
DEBUG = auto()
INFO = auto()
ERROR = auto()
LOG_PREFIXES = {
LogLevel.DEBUG: "[DEBUG]",
LogLevel.INFO: "[INFO]",
LogLevel.ERROR: "[ERROR]",
}
def log(level: LogLevel, message: str) -> None:
prefix = LOG_PREFIXES[level]
print(prefix, message)
Здесь невозможно случайно обратиться к
"DBG" вместо "DEBUG" — только валидные значения перечисления.---
Enum — это маленькое улучшение, которое сильно поднимает читаемость и надежность кода. Как только в вашем проекте появляется набор фиксированных состояний, ролей, типов — это сигнал: пора завести перечисление.👍2
Python для начинающих: configparser — приручаем конфиги как профи
Жёстко прописывать настройки прямо в коде — плохая идея. Захочется сменить пароль к базе или лог‑уровень — и вы уже лазите по файлам Python, рискуя всё сломать. Гораздо удобнее хранить настройки в конфигурационных файлах. Для этого в стандартной библиотеке есть модуль
---
### Как выглядит конфиг
Создадим файл
Структура проста: секции в квадратных скобках и пары
---
### Чтение конфигурации
Ключевые моменты:
-
-
-
---
### Изменение и сохранение конфига
Так можно не только читать, но и аккуратно обновлять настройки.
---
### Конфиг по умолчанию
Иногда нужно задать значения «на всякий случай»:
---
### Когда это полезно
- разные настройки для dev / prod без изменения кода;
- хранение секретов вне репозитория (через отдельный
- быстрое переключение фич через флаги.
Жёстко прописывать настройки прямо в коде — плохая идея. Захочется сменить пароль к базе или лог‑уровень — и вы уже лазите по файлам 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
Python для начинающих: как
Если вы хоть раз писали что-то вроде:
и ловили ошибки из‑за слэшей и кодировок, то модуль
---
### Базовая идея:
Главный герой — класс
Оператор
---
### Проверка существования и типа
Можно безопасно проверять перед чтением или удалением.
---
### Чтение и запись файлов
Чтение и запись — это методы объекта пути:
Не нужно вручную открывать и закрывать файлы —
---
### Создание папок и обход директорий
Создать дерево каталогов и пройтись по файлам — одна строка:
Метод
---
### Работа с именами, расширениями и родителями
Разбирать путь по частям стало легко:
---
### Почему стоит перейти на
- Кроссплатформенно: один и тот же код под Windows и Linux.
- Читаемо:
- Богатый функционал: от обхода директорий до смены расширений.
Если вы еще работаете с путями как со строками — попробуйте переписать небольшой скрипт на
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-запросов вручную с модулем
Большинство новичков начинают работу с сетью через библиотеку
---
### Простой 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