А что если спарсить часть статей с хабра и представить их в виде obsidian графа, будет ли это выглядеть, как красивая база знаний?
Please open Telegram to view this post
VIEW IN TELEGRAM
😨4👍2🤯1
Hypothesis — библиотека для property-based тестирования: она сама генерирует входные данные, ищет контрпримеры и минимизирует (shrink) их до простого случая бага.
🟢 Автогенерация данных по стратегиям (st.integers(), st.text(), st.lists(...))🟢 Поиск граничных случаев и минимизация падающих примеров🟢 Интеграция с pytest/unittest без лишнего кода🟢 Сохранение/повторение найденных контрпримеров
from hypothesis import given, strategies as st
# Свойство: двойной реверс списка возвращает исходное значение
@given(st.lists(st.integers()))
def test_reverse_twice(xs):
assert list(reversed(list(reversed(xs)))) == xs
pip install hypothesis
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
Ресурс подробно разбирает
threading, multiprocessing, asyncio, очереди, пулы процессов/потоков и шаблоны проектирования для высоконагруженных задач — с чёткими примерами и разбором подводных камней.Примечательно, что статьи сопровождаются измерениями производительности и готовыми «рецептами» (тайм-ауты, отмена задач, ограничения параллелизма, ретраи), что помогает сразу применять приёмы в продакшене.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
Я поднимаю n8n локально, учу его кастомным API и MCP-тулам: собираю AI-агента, не бросая no-code. Чуть кода — тонна гибкости. Скрины, грабли, профит.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
ChainMap позволяет работать с несколькими словарями как с одним: поиск ключей идёт слева направо, изменения пишутся в самый «верхний» словарь. Удобно для конфигов: CLI > ENV > defaultsfrom collections import ChainMap
defaults = {"host": "localhost", "port": 5432, "debug": False}
env = {"port": 6432}
cli = {"debug": True}
cfg = ChainMap(cli, env, defaults)
print(cfg["host"]) # ➔ localhost (из defaults)
print(cfg["port"]) # ➔ 6432 (из env)
print(cfg["debug"]) # ➔ True (из cli)
# Изменения пишутся в первый (cli)
cfg["port"] = 7000
print(cli) # ➔ {'debug': True, 'port': 7000}
print(env) # ➔ {'port': 6432} (не изменился)
# Временный «верхний» слой (например, сессия)
session = {"debug": False}
stacked = cfg.new_child(session)
print(stacked["debug"]) # ➔ False (приоритет session)
new_child(mapping=None) добавляет слой, maps/parents — для управления стекомPlease open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3
python-dotenv загружает значения из файла .env в переменные окружения — удобно для конфигов без хардкода..env → загрузить → привести типы → обновить ключ# pip install python-dotenv
import os
from pathlib import Path
from dotenv import load_dotenv, set_key
env_path = Path(".env")
# Создадим .env с дефолтами, если его нет
if not env_path.exists():
env_path.write_text(
"APP_NAME=Ghostly\n"
"DEBUG=true\n"
"DB_HOST=localhost\n"
"DB_PORT=5432\n"
"SECRET_KEY=s3cr3t_key_123\n",
encoding="utf-8"
)
# Загрузка переменных из .env в окружение процесса (override=False не перезапишет уже заданные в ОС)
load_dotenv(dotenv_path=env_path, override=False)
# Чтение с приведением типов
APP_NAME = os.getenv("APP_NAME", "App")
DEBUG = os.getenv("DEBUG", "false").lower() in {"1", "true", "yes", "on"}
DB_HOST = os.getenv("DB_HOST", "localhost")
DB_PORT = int(os.getenv("DB_PORT", "5432"))
SECRET = os.getenv("SECRET_KEY") # None, если не задан
print(APP_NAME, DEBUG, DB_HOST, DB_PORT, SECRET is not None)
# Обновление/добавление ключей в .env
set_key(str(env_path), "DEBUG", "false")
set_key(str(env_path), "API_URL", "https://api.github.com")
# Показать обновлённый .env
print(env_path.read_text(encoding="utf-8"))
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2😭1
Разбираем один из самых полезных встроенных модулей Python — os. Простыми словами о том, как управлять файлами и папками прямо из кода. Пройдем путь от os.mkdir() до написания скрипта для автоматической сортировки.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Почему этот match/case ведёт себя «странно» и всегда попадает в первую ветку?
Пример
role = "admin"
match role:
case admin: # <- это не строка, а "захват" имени
print("A") # печатается всегда
case "admin":
print("B")
case _:
print("C")
Ответ
В match голое имя — это шаблон захвата (capture pattern), а не константа: case admin просто связывает имя admin = role и совпадает с любым значением. Поэтому печатается "A".
✅ Как правильно матчить константы/литералы:
Используйте литералы: case "admin":
Или именованные константы в дот-нотации (Enum/модуль): case Roles.ADMIN:
Или guard-условие:
ADMIN = "admin"
match role:
case _ if role == ADMIN: ...
📌 Дополнительно: case 0 | 1: — альтернативы; case [x, y]: — распаковка последовательностей; bare name без кавычек — всегда захват.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔5❤2
attrs — удобная альтернатива ручному написанию классов: автоматически генерирует
__init__, __repr__, сравнение, валидацию и преобразование типов. Идеальна для DTO/конфигов без бойлерплейта.🟢 Декларативные поля с валидаторами и конвертерами🟢 Значения по умолчанию и factory для коллекций🟢 Автогенерация __init__, __repr__, __eq__ и пр.🟢 Быстрый старт, совместима с dataclasses
from attrs import define, field, validators
@define
class User:
name: str = field(validator=validators.instance_of(str))
age: int = field(converter=int, validator=validators.ge(0))
tags: list[str] = field(factory=list) # безопасный дефолт для списка
u = User("Alice", "30", tags=["admin"])
print(u) # ➔ User(name='Alice', age=30, tags=['admin'])
print(u.age >= 18) # ➔ True
pip install attrs
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍1
Я копнул глубже в CPython: как устроен reference counting и сборщик мусора, что он делает с объектами и как влияет на рантайм. Будет серия заметок с деталями реализации и выводами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ресурс предлагает десятки задач разной сложности: строки, списки, множества, работа с файлами, веб-скрейпинг, простые игры и мини-проекты. Отлично подходит для ежедневной практики и прокачки «мышечной памяти» кода.
К большинству задач есть подсказки и разборы решений, что помогает увидеть альтернативные подходы и улучшить стиль.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4❤1
partial фиксирует часть аргументов и возвращает новую функцию с «подставленными» значениями. Удобно для колбэков, конфигурирования библиотечных функций и устранения дублирования.from functools import partial
import json
def power(x: int, y: int) -> int:
return x ** y
square = partial(power, y=2) # фиксируем степень
cube = partial(power, y=3)
print(square(5)) # ➔ 25
print(cube(4)) # ➔ 64
# Преднастройка сторонней функции
dumps_pretty = partial(json.dumps, ensure_ascii=False, indent=2, sort_keys=True)
print(dumps_pretty({"b": 1, "a": [1, 2, 3]}))
partial(func, *args, **kwargs) фиксирует позиционные/именованные аргументы и возвращает новую функцию.Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1🤯1
Побег Робота из лабиринта. Технологи: Jetson + Arduino + CV. Робот находит выход из лабиринта только с помощью компьютерного зрения.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
• Создай urls.txt — по одному URL в строке.• Установи зависимости: pip install requests• Запусти скрипт ниже рядом с urls.txt.from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
import requests
OUT = Path("images"); OUT.mkdir(exist_ok=True)
urls = [u.strip() for u in Path("urls.txt").read_text(encoding="utf-8").splitlines() if u.strip()]
def download(u: str) -> str:
name = (u.split("/")[-1].split("?")[0] or "file").replace("/", "_")
path = OUT / name
r = requests.get(u, timeout=20, stream=True)
r.raise_for_status()
path.write_bytes(r.content)
return name
with ThreadPoolExecutor(max_workers=10) as ex:
futures = {ex.submit(download, u): u for u in urls}
for f in as_completed(futures):
try:
print("OK:", f.result())
except Exception as e:
print("FAIL:", futures[f], "->", e)
— ThreadPoolExecutor(max_workers=10) параллелит загрузки без блокировки основного потока.
— r.raise_for_status() ловит HTTP-ошибки, чтобы не сохранять «битые» файлы.
— Файлы кладутся в папку images; имена берутся из URL (с обрезкой query-параметров).
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3❤1
Почему этот код «портит» все строки матрицы одновременно?
Пример
m = [[0]*3]*3 # одна и та же строка повторена 3 раза
m[0][1] = 1
print(m) # ➔ [[0, 1, 0], [0, 1, 0], [0, 1, 0]]
Ответ
Оператор * дублирует ссылку на один и тот же внутренний список, а не создаёт новые. Поэтому изменение m[0][1] меняет ту же самую строку во всех местах.
✅ Правильно создавать независимые строки:
m = [[0]*3 for _ in range(3)] # новая строка на каждой итерации
🟢 Запомнить:
[x]*n безопасно для немутируемых значений (int, str, tuple), но не для вложенных списков.
Для копии строки используйте row[:] или row.copy().
Для глубокой копии вложенных структур — copy.deepcopy.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12