Python для пацанов.
134 subscribers
2 photos
9 links
"Серьезный" разбор языка программирования Пайтон для серьезных пацанов.
Download Telegram
Встречаем рубрику #КодБлатногоУровня


Эй, пацаны! Сегодня у нас урок кода, но не сухой и скучный, а наш, районный. Покажем, что singledispatch в питоне классно дополняет декораторы, встречаем наших по коду. У нас тут Чушпан, Пахан и Боец – каждому свое, но уважение далеко не всем.

Вот как это выглядит в коде:
from functools import singledispatch
from abc import ABC, abstractmethod


class Чушпан(ABC):
pass


class Пахан(ABC):
pass


class Боец(ABC):
pass


@singledispatch
def поприветствовать(личность):
raise NotImplementedError("Из каких будешь, братишка? Не, не, не - проходи!")


@поприветствовать.register(Чушпан)
def _(личность):
return f"Чушпан {личность.кликуха} вали, пока не дали!"


@поприветствовать.register(Пахан)
def _(личность):
return f"Пахан {личность.кликуха} в деле!"


@поприветствовать.register(Боец)
def _(личность):
return f"Боец {личность.кликуха} готов к бою!"


# Примеры личностей
class Вася(Чушпан):
кликуха = "Подзаборный"


class Петя(Пахан):
кликуха = "Суровый"


class Коля(Боец):
кликуха = "Бык"


# Пример использования
print(поприветствовать(Вася())) # Чушпан Подзаборный вали, пока не дали!
print(поприветствовать(Петя())) # Пахан Суровый в деле!
print(поприветствовать(Коля())) # Боец Бык готов к бою!


Вот так, ребята, мы через код показываем уважение и знаем кто перед нами. В жизни важно знать, кто твой брат, а в коде – кто перед тобой по классу. Держите свой код чистым и ваши отношения крепкими!

Не забываем: кодинг – это не просто писанина, это часть нашей жизни. #КодБлатногоУровня
😁3💩1🤣1
#ПервыйКодНаРайоне
В Python со строками можно делать всякие штуки, как на районе с тегами: красить, перекрашивать, добавлять что-то свое. Только в коде это выглядит как функции работы с текстом. Вот несколько примеров:

1. Длина строки:
Как узнать, сколько в твоем слогане символов? Это как считать деньги после дня работы.
текст = "Мой район лучший"
print(len(текст)) # покажет, сколько символов в строке


2. Нахождение подстроки:
Это как когда ты ищешь брата по кличке на большой площади.
if "район" in текст:
print("Слово 'район' есть в тексте")


3. Замена в строке:
Меняем одно на другое, как старые кроссы на новые.
новый_текст = текст.replace("лучший", "самый крутой")
print(новый_текст) # "Мой район самый крутой"


4. Разбиение и соединение:
Это как разбить банду на малые группы и потом снова собрать всех вместе.
слова = текст.split(' ')  # Разбиваем на слова
print(слова) # ['Мой', 'район', 'лучший']
воссоединенный_текст = " ".join(слова) # Соединяем обратно
print(воссоединенный_текст) # "Мой район лучший"


5. Преобразование регистра:
Это как менять голос, чтобы звучать серьезнее или наоборот, дружелюбнее.
крик = текст.upper()  # "МОЙ РАЙОН ЛУЧШИЙ"
шепот = текст.lower() # "мой район лучший"
каждое_слово_с_большой = текст.title() # "Мой Район Лучший"


6. Удаление пробелов:
Как выкидывать мусор из карманов перед домом.
мусорный_текст = "    Мой район    "
очищенный_текст = мусорный_текст.strip() # уберет все пробелы по краям
print(очищенный_текст) # "Мой район"


7. Начинается или заканчивается:
Как проверить, все ли в порядке с тегом на стене.
if текст.startswith("Мой"):
print("Текст начинается с 'Мой'")
if текст.endswith("лучший"):
print("Текст заканчивается на 'лучший'")


Эти функции – это базовый инструментарий для работы с текстом в Python. Это как иметь хороший набор инструментов в гараже: всегда найдется то, что нужно для работы. Умея их использовать, ты сможешь легко манипулировать текстами в своих программах, будь то чтение данных, форматирование сообщений или что-то еще, связанное со словами и предложениями.

Так что, братва, не забывайте: в коде, как и на улице, важно уметь работать с информацией – и текст тут не исключение. Учитесь, экспериментируйте и держите ухо востро! #ПервыйКодНаРайоне
👍2💩1
Братва, сегодня разберемся с исключениями в Python, как на улицах нашего района. Вот полный разбор:

1. Попадание в неприятности (`try`): начинаешь день, не знаешь, что тебя ждет.
   try:
# пробуем что-то сделать


2. Столкновение с неожиданностью (`except`): на улице встретился с ментом (PermissionError), соперником (ConflictError) или нечто странным (UnexpectedError).
   except PermissionError:
# обработка случая с ментом
except ConflictError:
# действия, если встретил соперника
except UnexpectedError:
# если случилось что-то неожиданное


3. Проверка условий (`assert`): как проверить, закрыл ли ты дверь перед выходом.
   assert условие, "Сообщение об ошибке"


4. Вызов исключения (`raise`): если что-то идет не так, как планировал, ты кидаешь вызов.
   raise TypeError("Что-то пошло не так")


5. Все прошло гладко? (`else`): если обошлось без проблем, идешь дальше.
   else:
# все чисто, идем дальше


6. Подведение итогов (`finally`): в конце дня, несмотря на все, ты возвращаешься домой.
   finally:
# заканчиваем день


Помните, парни, как в жизни, так и в коде: нужно быть готовым к любым ситуациям, уметь стоять за себя и знать, когда действовать по плану, а когда - выходить из положения. #ПервыйКодНаРайоне
💩1
#ПервыйКодНаРайоне #фишки
Ребята, сегодня поговорим о трех вещах, которые каждый кодер на Python должен знать – это pip, poetry и виртуальное окружение. Это как основные инструменты в вашем районе, которые помогут держать дела под контролем.

PIP

Это как ваш личный поставщик инструментов. Нужна новая фича в ваш код? PIP поможет её найти, привезти и установить. Это ваш основной канал получения всего, что нужно для работы ваших программ. Как если бы у вас был личный торговец, который привозит вам все, что душе угодно, от новых кроссов до редких винилов.

Poetry

Если PIP – это торговец, то Poetry – это ваш личный бухгалтер и организатор. Он не только умеет делать всё то же, что и PIP, но и следит за тем, чтобы все ваши инструменты (зависимости) были аккуратно уложены, не конфликтовали друг с другом и легко обновлялись. Это как если бы у вас был помощник, который не только следит за вашим инвентарем, но и убеждается, что все ваши инструменты в хорошем состоянии и готовы к работе.

Виртуальное окружение

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

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

И вот что: мы только затронули поверхность. Далее мы раскроем эти темы поподробнее. Будем копать глубже, чтобы вы поняли каждый уголок PIP, каждую хитрость Poetry и каждый секрет виртуального окружения. Как профессионалы района, мы не оставим камня на камне, пока не разберемся в каждой детали. Готовьтесь, будет интересно!
#ПервыйКодНаРайоне #фишки
💩1
#ПервыйКодНаРайоне #фишки #pip

PIP - часть 1


Общие параметры:
- -v или --verbose: Как кричать на весь район, когда что-то делаешь. Показывает больше инфы.
- -q или --quiet: Наоборот, молчишь, как партизан. Меньше вывода информации.
- -h или --help: Как спросить старших братьев, когда в затруднении. Показывает, что и как можно делать.
- -V или --version: Чтобы проверить свои "часы" - версию PIP.
- --isolated: Игнорирует настройки окружения, как забить на все и делать свое.
- --log PATH: Записывает, что происходит, в лог-файл, как дневник событий района.
- --proxy USER:PSWD@SERVER:PORT: Если надо через прокси, то это как пойти через дворы.
- --retries X: Сколько раз пытаться связаться, если что-то не так.
- --timeout SECONDS: Сколько секунд ждать перед попыткой снова.
- --cache-dir DIR: Куда складывать кэш, как свой секретный тайник.
- --no-cache-dir: Не использовать кэш, каждый раз все новое.
- --disable-pip-version-check: Не проверять версию PIP, как игнорировать слухи.
- --cert PATH: Путь к сертификату, если нужно подтверждение.
- --client-cert CERT: Твой личный сертификат, когда нужно доказать, что ты свой.
- --trusted-host HOSTNAME: Как доверенное лицо в районе, сервер, которому веришь.


Список пакетов (pip list):
Как проверить, что у тебя в рюкзаке, так и pip list покажет все, что установлено в твоем Python-мире.

- -o или --outdated: Показывает устаревшие пакеты, как старые кеды, что пора менять.
- -u или --uptodate: Список актуальных пакетов, все в норме, как новые кроссы.
- -e или --editable: Показывает пакеты, установленные в редактируемом режиме, как твой кастомизированный байк.
- -l или --local: Показывает пакеты установленные в локальной виртуальной среде, как твои штуки в твоем дворе.
- --user: Показывает пакеты установленные только для твоего пользователя, как личные вещи в твоем закрытом шкафу.
- --pre: Включает в список предварительные и экспериментальные версии, как пробные версии новых гаджетов.

Поиск пакетов (pip search):
Когда ищешь что-то новенькое, как новые треки или кроссовки:
- pip search ключевое_слово: Находишь пакеты по ключевым словам, как искать в интернете инфу.

Инфо о пакетах (pip show):
Как спросить у брата всю инфу о новой игре:
- pip show имя_пакета: Дает тебе всю инфу о пакете, от версии до зависимостей.
- -f или --files: Показывает все файлы, связанные с пакетом, как список вещей в новом китайском гаджете.

Удаление пакетов:
- `pip uninstall имя_пакета`: Как выкинуть ненужное из вашей квартиры.
- `-r FILE`, `--requirement FILE`: Если надо удалить кучу штук, указанных в файле, как список ненужных вещей.
- `-y`, `--yes`: Просто делает все без вопросов, как когда ты уверен в своем деле.

Заморозка зависимостей:
- `pip freeze`: Создает список всех ваших зависимостей, как запись ваших долгов.
- `-r FILE`, `--requirement FILE`: Использует порядок, указанный в файле, для вашего списка.
- `-f URL`, `--find-links URL`: Где искать пакеты, если они не в обычном месте.
- `-l`, `--local`: Показывает только пакеты, установленные в вашем локальном окружении.
- `--user`: Показывает пакеты, установленные только для вашего пользователя.

Установка пакетов:
- `pip install имя_пакета`: Как купить новые вещи для дома.
- `-r FILE`, `--requirement FILE`: Установить все из списка, как закупка по списку.
- `-b DIR`, `--build DIR`: Где строить (собирать) пакеты.
- `-t DIR`, `--target DIR`: Куда ставить пакеты, как выбрать место в доме.
- `-d DIR`, `--download DIR`: Только скачать, не устанавливать, как сохранить для потомков.
- `-U`, `--upgrade`: Обновить указанные пакеты.
- `--force-reinstall`: Переустановить пакеты при обновлении.
#ПервыйКодНаРайоне #фишки #pip
💩1
#ПервыйКодНаРайоне #фишки #pip
Продвинутая установка пакетов:

Когда устанавливаешь пакеты, дело не только в базовых шагах:

- Установка конкретной версии: Это как если бы тебе нужны кроссы определенной модели, чтобы всё было стабильно.
  pip install 'package_name==1.0'


- Установка минимальной версии: Иногда нужно, чтобы у тебя была шмотка минимум определенной версии, но не обязательно последней.
  pip install 'package_name>=1.0'


- Файлы требований: Когда речь идет о куче зависимостей, лучше всё это держать в одном списке, чтобы не запутаться.
  pip install -r requirements.txt


- Сборка пакетов: Иногда нужно собрать штуку с нуля, а не использовать готовое.
  pip install --build DIR package_name


- Целевая директория: Когда ставишь пакеты в конкретное место, а не туда, куда Python хочет по умолчанию.
  pip install --target=DIR package_name


- Без зависимостей: Ставишь пакет без его друзей (делай так только если точно знаешь, зачем это).
  pip install --no-deps package_name


- Управление кэшем: Управляй своим кэшем, чтобы сэкономить место и ускорить установку.
  pip install --cache-dir=DIR package_name
pip install --no-cache-dir package_name


Управление зависимостями и обновления:

Когда твоя команда работает над проектом, важно держать все под контролем:

- Обновление пакетов: То же, что обновить свою колонку или телефон до последней модели. Просто говоришь:
  pip install --upgrade имя_пакета

Это как переобуться в новые кроссы, чтобы идти в ногу со временем.

- Фиксация зависимостей: Записываешь все, что у тебя есть, чтобы в другой раз не гадать, как это все собиралось.
  pip freeze > requirements.txt

Это как сделать четкий список того, что у тебя в гараже.

- Установка из файла зависимостей: Когда начинаешь новый проект или настраиваешь рабочее место, ты можешь восстановить все нужное сразу, без геморроя.
  pip install -r requirements.txt

Это как когда у тебя есть список для закупки продуктов на неделю.

- Поиск пакетов: Если ищешь что-то новое или нужно найти альтернативу, используй поиск:
  pip search ключевое_слово

Продвинутое управление пакетами:

В этой части мы бы говорили о более сложных вещах, связанных с PIP:

- Управление кэшем: PIP сохраняет копии каждого загруженного пакета. Это как когда ты копишь запчасти для будущих дел – можешь использовать их позже без лишней возни.
  pip cache dir  # показать, где лежит кэш
pip cache list # показать все скачанные пакеты
pip cache purge # удалить все кэшированные пакеты


- Проверка пакетов на соответствие: Это как проверить, все ли твои друзья на месте и в порядке. Убедись, что твои зависимости не конфликтуют и все они безопасны.
  pip check


- Использование различных источников для установки: Можешь устанавливать пакеты не только с PyPI. Это как покупать не только в одном магазине, а ещё и у проверенных друзей.
  pip install --index-url другой_источник имя_пакета


- Установка зависимостей приватных пакетов: Если у тебя есть свои закрытые пакеты, это как иметь личные контакты для особых дел.
  pip install --extra-index-url приватный_источник имя_пакета


#ПервыйКодНаРайоне #фишки #pip
💩1
Рубрика #АМужикиТоИНеЗнали на нашем канале демонстрирует необычные и малоизвестные факты о программировании на Python, которые могут удивить даже опытных разработчиков. Это короткие, но мощные порции знаний для тех, кто хочет глубже погрузиться в мир IT и расширить свои горизонты.

Начнём.

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

Контекстные менеджеры в Python используются для обеспечения предварительной и последующей обработки при выполнении блока кода, часто применяются для управления ресурсами. Самый известный пример использования — конструкция with open(...) as ...:, которая гарантирует закрытие файла после выхода из блока with.

Малоизвестный факт заключается в том, что вы можете создать свой собственный контекстный менеджер с помощью декоратора contextlib.contextmanager. Это может быть полезно, например, для создания блока кода, который требует установки и очистки ресурсов, таких как открытие и закрытие соединения с базой данных.

Вот пример создания простого контекстного менеджера, который записывает в лог начало и конец выполнения какого-либо действия:

from contextlib import contextmanager
import time

@contextmanager
def log_block(name):
start_time = time.time()
print(f"Начало выполнения блока '{name}'")
try:
yield # Передать управление в блок with
finally:
end_time = time.time()
print(f"Завершение выполнения блока '{name}'. Время выполнения: {end_time - start_time:.2f} секунд.")

# Пример использования:
with log_block("обработка данных"):
# Здесь размещается код, который вы хотите выполнить
# Например, какая-то тяжелая задача
time.sleep(2) # Имитация долгой операции


В этом примере контекстный менеджер log_block печатает сообщение при входе в блок и при выходе из него, а также засекает время выполнения кода внутри блока. Это простой пример того, как можно использовать контекстные менеджеры для улучшения читаемости кода и управления ресурсами.

#АМужикиТоИНеЗнали
🔥1💩1
#ПервыйКодНаРайоне #фишки #pip
Ребята, давайте разжуем каждый шаг по созданию и публикации вашего пакета в PIP с примерами и кодом.

Шаг 1: Придумай свой проект
Скажем, у тебя есть полезная функция для вычисления дней до Нового Года. Создай папку newyear_countdown и внутри нее файл countdown.py:
# countdown.py
from datetime import datetime, date

def days_until_newyear():
today = date.today()
newyear = date(today.year + 1, 1, 1)
delta = newyear - today
return delta.days


Шаг 2: Организуй свой код
Убедись, что структура твоего проекта выглядит так:
newyear_countdown/
__init__.py
countdown.py

В __init__.py можно добавить следующее:
from .countdown import days_until_newyear


Шаг 3: Напиши setup.py
В корне твоего проекта (newyear_countdown/) создай файл setup.py:

from setuptools import setup, find_packages

setup(
name='newyear_countdown', # имя твоего пакета, как ты зовешь свой проект
version='0.1', # версия твоего пакета, чтобы все знали, насколько он свежий
packages=find_packages(), # автоматически находит все пакеты (папки с __init__.py), которые нужно включить
description='Countdown to New Year', # краткое описание твоего проекта, что он делает
install_requires=[], # список зависимостей, других пакетов, без которых твой не будет работать
)


- name: Это имя твоего пакета. Как ты его зовешь, так он и будет отображаться в PyPI и при установке через pip.

- version: Версия твоего пакета. Важно обновлять ее с каждым значимым обновлением твоего проекта. Следуй принципам семантического версионирования (например, 1.0.0, 1.0.1 для патчей, 1.1.0 для минорных изменений).

- packages: Сюда входят все Python пакеты (каталоги с файлом __init__.py), которые должны быть включены в дистрибутив. find_packages() автоматически находит все такие пакеты в твоем проекте.

- description: Краткое описание того, что делает твой пакет. Это то, что люди увидят в PyPI, когда найдут твой пакет.

- install_requires: Список зависимостей, необходимых для работы твоего пакета. Если твой проект использует другие пакеты, здесь ты перечисляешь их имена (и желательно версии).

Это типа твоей личной карточки. Как когда ты приходишь на новую площадку, ты говоришь: "Эй, я такой-то, вот мои фишки, вот что я умею". Так вот, setup.py – это твоя карточка для Python сообщества.

Шаг 4: Протестируй свой пакет
В терминале, в корне проекта, запускай:
python setup.py install

Убедись, что все работает, создав виртуальное окружение и установив туда пакет.

Шаг 5: Зарегистрируйся на PyPI
Перейди на [PyPI](https://pypi.org/) и зарегистрируй аккаунт.

Шаг 6: Собери свой пакет
В корне проекта запускай:
python setup.py sdist

Это создаст файл .tar.gz в папке dist/.

Шаг 7: Загрузи свой пакет
Сначала установи twine:
pip install twine

Затем загрузи пакет:
twine upload dist/*


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

Шаг 8: Поздравляю, ты в игре!
Теперь твой пакет доступен для всех через PIP:
pip install newyear_countdown


Вот так, ребята, шаг за шагом вы превращаетесь из уличных хулиганов в настоящих кодерских крестных отцов. Творите, пацаны, и пусть весь мир узнает о ваших талантах!
#ПервыйКодНаРайоне #фишки #pip
💩1
#АМужикиТоИНеЗнали
Давайте рассмотрим пример использования распаковки списков с помощью звездочки * на понятном и простом примере.

Представим, что у вас есть список друзей с района, и вы хотите собрать их всех в одном месте, чтобы устроить вечеринку. У вас уже есть список с некоторыми именами, и вы хотите добавить еще несколько друзей в этот список.

Вот ваш текущий список друзей:

друзья_с_района = ["Вася", "Петя", "Коля"]


Теперь представим, что вы встретили еще трех других друзей, и вы хотите добавить их к уже существующему списку. Ваши новые друзья:

новые_друзья = ["Лена", "Оля", "Саша"]


Чтобы объединить эти два списка в один, вы можете использовать распаковку с помощью *, как показано ниже:

все_друзья = [*друзья_с_района, *новые_друзья]


В результате получится следующий список:

["Вася", "Петя", "Коля", "Лена", "Оля", "Саша"]


Это очень удобный способ объединения списков без необходимости использовать циклы или дополнительные методы. Таким образом, вы можете легко собрать всех друзей вместе.
#АМужикиТоИНеЗнали
💩1
#АМужикиТоИНеЗнали
Давайте рассмотрим пример использования блока else с циклами в Python на понятном примере.

Представьте, что вы и ваши друзья с района решили сыграть в игру на удачу. Вы кидаете кубик (шестигранный), и если кто-то из вас выбросит шестерку, то этот человек выигрывает и игра заканчивается. Если же никто не выбросит шестерку после нескольких попыток, то все проиграли и решаете попробовать снова позже.

В коде на Python это можно реализовать так:

from random import randint

попытки = 5 # Допустим, у вас есть 5 попыток
for _ in range(попытки):
бросок = randint(1, 6) # Кидаем кубик
print(f"Бросок: {бросок}")
if бросок == 6:
print("Выигрыш! Кто-то выбросил шестерку!")
break
else: # Этот блок выполнится, если цикл завершился нормально, без 'break'
print("Проигрыш. Никто не выбросил шестерку. Попробуем в другой раз.")


В этом примере, блок else срабатывает только если цикл for завершился полностью, без прерывания через break. То есть, если никто не выбросил шестерку после всех попыток, выведется сообщение о проигрыше. Если же кто-то выбросил шестерку (и цикл был прерван командой break), блок else не выполняется, и выводится сообщение о выигрыше.

Использование else с циклами может быть не очень интуитивным, но оно может добавить дополнительную логику обработки ситуаций, когда цикл завершился без прерывания.

#АМужикиТоИНеЗнали
💩1
#АМужикиТоИНеЗнали
Так как среди читательниц канала есть девушки довольно хорошо владеющие языком программирования Питон, и удивить их сложно, мы всё равно попробуем. Используем метаклассы.

class CongratulateMeta(type):
def __new__(cls, name, bases, attrs):
# Добавляем метод для поздравления
attrs['congratulate'] = lambda self: f"Дорогая {attrs['name']}, поздравляем тебя с 8 Марта! Желаем счастья, здоровья и кода без багов везде там, где это действительно необходимо!"
return super().__new__(cls, name, bases, attrs)


# Используем метакласс в определении нового класса
class FemaleProgrammer(metaclass=CongratulateMeta):
name = "Ася"

# Создаем экземпляр класса
programmer = FemaleProgrammer()
print(programmer.congratulate())


📱
Дорогая Ася, поздравляем тебя с 8 Марта! Желаем счастья, здоровья и кода без багов везде там, где это действительно необходимо!




В этом примере метакласс CongratulateMeta автоматически добавляет метод congratulate к любому классу, который его использует. Этот метод выводит персонализированное поздравление, используя имя, определенное в классе.

#АМужикиТоИНеЗнали
Please open Telegram to view this post
VIEW IN TELEGRAM
1💩1
#ПервыйКодНаРайоне
Пацаны, вот коротко о том, чем круты виртуальные окружения в Python, как они работают и зачем вам это нужно.

Виртуальное окружение: закрытая тусовка для твоего кода

Считай, виртуальное окружение – это твоя личная зона для проекта, отделенная от всего мира. Как закрытая вечеринка, где ты контролируешь все: музыку (версию Python), закуски (библиотеки и пакеты) и гостей (зависимости).

Создаем окружение:
python -m venv название_для_тусовки

Так ты говоришь Python: "Создай мне место, где я буду шеф".
Общепринятно, и мы рекомендуем использовать названия типа venv или env

Заходим на тусовку (активируем окружение):
- На Unix или macOS:
  source <название_для_тусовки>/bin/activate

- На Windows:
  <название_для_тусовки>\Scripts\activate


Теперь ты в своем мире, где можешь делать что хочешь, не ломая глобальное пространство.

Покидаем тусовку (деактивируем окружение):
deactivate

Ты вернулся в реальный мир, где всё как было.

Что тут круто:

Пацаны, давайте разберемся, почему виртуальные окружения в Python – это чистый кайф для каждого кодера:

Наследование от глобального окружения

Смотрите, когда вы создаете новую закрытую тусовку (виртуальное окружение), она не начинается с нуля. Она "наследует" некоторые базовые штуки из вашего большого мира (глобального окружения Python). Это значит, что основные инструменты уже будут под рукой, но без всей той лишней фигни, которая могла накопиться в вашей системе. Это как если бы на вашей вечеринке уже были газировка и чипсы, но музыка и народ – только те, кого вы пригласили.

Изоляция ресурсов

Тут дело такое – каждая ваша тусовка, каждый проект в своем виртуальном окружении, живет своей жизнью. Установили кучу пакетов в одном проекте? Они не попадут в другие. Это помогает избежать конфликтов между зависимостями разных проектов. То есть, если в одном проекте тебе нужна одна версия библиотеки, а в другом – другая, то ты можешь спокойно использовать обе, и они не будут мешать друг другу. Это как иметь разные комнаты для разных тусовок в одном большом доме.

Оптимизация работы с помощью .pth файлов

Допустим, у тебя есть две тусовки: одна – это твой основной проект, а вторая – это такой сайд-проект, где ты экспериментируешь с новыми фишками. Оба проекта используют некие общие файлы, скажем, твои крутые утилиты, которые ты сам написал и хочешь использовать в обоих местах. Эти утилиты лежат в какой-то отдельной папке на твоем компе, скажем
D:\МоиУтилиты

Обычно, если бы ты хотел использовать эти утилиты в обоих проектах, тебе пришлось бы копировать их в каждый проект отдельно. Но это ж гемор, правильно? Каждый раз, когда ты обновляешь утилиты, тебе нужно заменять их в двух местах. Но тут на помощь приходят .pth файлы.

Создай файл с расширением .pth, скажем мои_утилиты.pth, и положи его в папку site-packages, которая находится в твоем виртуальном окружении (это как VIP-зона каждой из твоих тусовок). В этом файле просто укажи путь к папке с твоими утилитами
D:\МоиУтилиты


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

Виртуальные окружения и интерпретаторы Python

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

Так что, ребята, виртуальные окружения – это не просто круто, это ваш инструмент для порядка, безопасности и свободы в мире кодинга. Пользуйтесь на здоровье!
#ПервыйКодНаРайоне
1👍1💩1
#ПервыйКодНаРайоне
Братва, сегодня мы зайдем с вами в мир Python с другой стороны улицы – поговорим о магических методах. Это не просто какие-то функции, это настоящая магия в мире кода, которая позволяет нашим объектам (ссыль для самых продвинутых из вас) вести себя как настоящие шулеры в карточной игре.

Магические методы в Python – это спецфункции, благодаря которым твой код начинает работать по-новому, становится более крутым и умным. Как невидимые нити, они позволяют объектам взаимодействовать друг с другом и с Python'ом на глубоком уровне.

Давайте напишем простой код, который кое что растолкует сам по себе:

import collections
from random import choice, shuffle

# Создаём картеж для карт, чтобы каждая карта была как уникальный элемент с рангом и мастью.
Card = collections.namedtuple('Card', ['ранг', 'масть'])


class FrenchDeck:
# Определяем ранги карт и масти в виде юникод символов.
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = '♠️ ♦️ ♣️ ♥️'.split()

def __init__(self):
# Заполняем нашу новенькую колоду картами, создаём рангами и мастями.
self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]

def __len__(self):
# Возвращает количество карт в колоде чтобы лохи верили, что мы не шулеры.
return len(self._cards)

def __getitem__(self, position):
# Получение карты из колоды по её позиции - как звонок определённому жителю города.
return self._cards[position]

def __setitem__(self, position, value):
# Меняем карту в колоде - это как переезд жителя на новое место.
self._cards[position] = value

def __repr__(self):
# Представление колоды карт для печати. Покажет всех "жителей" нашего города.
return f'FrenchDeck({self._cards})'



crime_queen = Card('Q', '♠️') # Пример карты - "Пиковая дама". (Коварна и упряма)

print(crime_queen)
deck = FrenchDeck() # Создаём колоду карт.
print(f'{len(deck)=}') # Узнаём количество карт в колоде.
print(f'{deck[0]=}') # Показываем первую карту в колоде.
print(f'{deck[-1]=}') # Показываем последнюю карту в колоде.
print(f'{choice(deck)=}') # Выбираем случайную карту из колоды.
shuffle(deck) # Перемешиваем карты в колоде.

for d in deck:
print(d) # Выводим всю колоду на печать.



Теперь подробнее:


Магические методы - это такие функции, которые начинаются и заканчиваются двойными подчеркиваниями, типа __такие__. Эти методы позволяют тебе определить поведение твоих классов (объектов) на внешние предъявы и вопросы. Например в случае с нашей шуллерской колодой:


- __init__ в классе FrenchDeck: Здесь ты создаешь колоду карт. Это как когда ты открываешь новую пачку игральных карт – расставляешь все по порядку.

- __len__ в FrenchDeck: Спроси "Сколько карт в колоде, брат?" – и этот метод ответит тебе, сколько карт в твоей колоде.

- __getitem__ в FrenchDeck: Это как выбрать одну карту из колоды. Скажешь deck[0], получишь верхнюю карту, скажешь deck[-1], получишь самую последнюю.

- __setitem__ в FrenchDeck: Тут ты уже играешь по-крупному, меняя карты местами, как хитрый шулер. Добавляется, чтобы можно было делать штуки типа перемешивания.

- __repr__ в FrenchDeck: Это как когда ты показываешь всю колоду друзьям, раскладывая перед ними. Дает полное представление о том, что в колоде.

Этот простой пример показывает основы магических методов, мы еще будем рассматривать их подробнее, как это делается в некоторых крутых книгах, которые мы обязательно тут разыграем. "Не переключайтесь!"
#ПервыйКодНаРайоне
🔥3👍2💩1
#ПервыйКодНаРайоне Браток, слышал о такой штуке, как ChainMap в Python? Давай разберем на понятиях, чтобы ты понял суть, как на улице разбираются с долгами.

Представь, у тебя есть несколько карманов, в каждом – свои бабки, карточки, записки. Но когда ты ищешь конкретную фишку, типа пятёрку или записку от братвы, тебе не приходится выворачивать все карманы. Ты знаешь, в каком кармане что лежит, но иногда забываешь. Вот здесь на помощь и приходит ChainMap – это как твой личный помощник, который помнит, что где лежит.

ChainMap берет несколько словарей (представь, что это твои карманы) и создает одну общую шнягу, где можно искать ключи и значения по всем словарям сразу, но не перемешивая их. Это как если бы у тебя был помощник, который знает, что в одном кармане бабки, в другом – мелочь для автобуса, а в третьем – записки.

Когда ты ищешь что-то через ChainMap, он сначала смотрит в первый словарь (карман), и если там нет нужного – переходит ко второму, и так далее, пока не найдет или не проверит все карманы.

Но вот беда, если ты решишь что-то добавить через ChainMap, это попадет только в первый карман (словарь), так что будь аккуратен, а то потом ищи свои записки по всем карманам.

Допустим, у нас есть братишки из разных районов: Москва, Питер, Казань. У каждого из них своя область ответственности, и тебе нужно все это собрать в кучу, чтобы знать, к кому по каким вопросам обращаться. Используем ChainMap для этого.

from collections import ChainMap

# Допустим, у каждого братишки свои связки.
moscow_bro = {'Вася': 'Финансы', 'Петя': 'Улицы'}
piter_bro = {'Коля': 'Концерты', 'Витя': 'Бары'}
kazan_bro = {'Рустам': 'Спорт', 'Ильяс': 'Еда'}

# Соединяем все связки в одну большую с помощью ChainMap.
all_bros = ChainMap(moscow_bro, piter_bro, kazan_bro)

# Теперь можно искать по всем братишкам сразу.
print(all_bros['Вася']) # Финансы
print(all_bros['Коля']) # Концерты
print(all_bros['Рустам']) # Спорт

# Допустим, тебе нужно добавить нового братишку.
all_bros['Дима'] = 'Музыка' # Добавляется в Московскую группу, потому что она первая в ChainMap.
print(moscow_bro) # {'Вася': 'Финансы', 'Петя': 'Улицы', 'Дима': 'Музыка'}

# Проверяем, в каком "городе" какие братишки и их дела.
print(all_bros.maps) # Выведет список словарей, которые в ChainMap.


Таким образом, используя ChainMap, мы собрали всех братишек под одну крышу, и теперь можем легко найти, кто за что отвечает, и к кому обратиться по тем или иным вопросам.

Если в разных городах есть братишки с одинаковыми именами, ChainMap будет обращаться к первому найденному имени в порядке, в котором ты объединил свои словари (города). Поэтому, если есть одноименные братки, то ответственности братишки из первого словаря (города) будут приоритетнее для ChainMap.

Давай покажем на примере, чтобы всё было ясно:

from collections import ChainMap

# Братишки из разных городов.
moscow_bro = {'Вася': 'Финансы', 'Петя': 'Улицы'}
piter_bro = {'Вася': 'Концерты', 'Витя': 'Бары'} # В Питере тоже есть Вася, но он отвечает за концерты.
kazan_bro = {'Рустам': 'Спорт', 'Ильяс': 'Еда'}

# Объединяем всех в ChainMap.
all_bros = ChainMap(moscow_bro, piter_bro, kazan_bro)

# Попробуем найти Васю.
print(all_bros['Вася']) # Выведет 'Финансы' потому что московский Вася в первом словаре, который мы передали в ChainMap.

# Посмотрим, какие данные есть по всем братишкам.
print(all_bros.maps) # Тут можно будет увидеть всех братишек в списке словарей.

# Если нам нужно обратиться к Васе из Питера, нужно пройти через все словари.
for city_bros in all_bros.maps:
if 'Вася' in city_bros:
print(city_bros['Вася']) # Теперь мы увидим ответственности каждого Васи во всех городах.


Так что, брат, если у тебя в разных группах есть ребята с одним и тем же именем, ChainMap покажет тебе инфу только от первого попавшегося в списке. Но ты всегда можешь обойти все словари вручную, чтобы найти всех одноименников.#ПервыйКодНаРайоне
👍1🔥1💩1
#ПервыйКодНаРайоне
Братва, сегодня я вам раскрою тему лямбда-функций в Питоне. Это как когда тебе нужно сделать быструю и маленькую задачку, не разводя длинную авантюру.

Что такое лямбда-функция?
Лямбда-функция в Питоне – это маленькая анонимная функция, у которой может быть куча аргументов, но только одно выражение. Это типа когда ты просишь брата на секунду помочь – быстро и по существу. Анонимная в данном случае означает, что у неё нет имени, и нельзя её просто так взять, и вызвать из другой части кода.

Пример №1: Сортировка списка кортежей
Допустим, у тебя есть список долгов перед братвой, и тебе нужно их отсортировать по размеру долга.

dolgi = [('Саня', 100), ('Витя', 50), ('Петя', 75)]
# Используем лямбду для сортировки по второму элементу кортежа (размеру долга)
otvet = sorted(dolgi, key=lambda x: x[1])
print(otvet) # Выведет список отсортированный по размеру долга


Пример №2: Фильтрация списка
Есть список чуваков, и нужно оставить только тех, у кого в имени есть "а".

bratva = ['Саня', 'Витя', 'Петя', 'Коля']
# Используем лямбду в фильтре, чтобы оставить только нужных братьев
filter_otvet = list(filter(lambda x: 'а' in x, bratva))
print(filter_otvet) # Покажет тех, у кого есть 'а' в имени


Пример №3: Применение функции к списку
У тебя есть список ценников на вещи, и нужно к каждому прибавить НДС.

cenniki = [100, 200, 300]
# Используем лямбду с map, чтобы к каждому ценнику прибавить НДС
nds_otvet = list(map(lambda x: x * 1.2, cenniki))
print(nds_otvet) # Выведет новые ценники уже с НДС


Так вот, братан, лямбда-функции – это когда надо быстро и без лишних вопросов сделать дело. Они маленькие, но могут пригодиться в самых разных ситуациях.
#ПервыйКодНаРайоне
👍4🔥1💩1
#ПервыйКодНаРайоне
О, братишка, сейчас поговорим про reduce. Эта функция в Питоне - как крутой барыга на рынке, который умеет из кучи мелочи делать одну большую котлету. Собирает всё в кучу и выдает тебе финальный результат. Чтобы пользоваться reduce, надо подключить его откуда? Правильно, из модуля functools.

Что такое reduce?

Функция reduce принимает два аргумента: функцию и последовательность. Функция должна быть такой, что принимает два аргумента, а reduce применяет её ко всем элементам списка, шаг за шагом, сокращая список до одного единственного значения. Это как если бы ты складывал деньги в копилку: кидаешь одну монету, потом другую, и так, пока не сложишь всё.

Примеры использования reduce

Пример №1: Суммирование списка чисел

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

from functools import reduce

# Список бабок
babki = [100, 200, 300, 400]

# Функция для суммирования
def summa(x, y):
return x + y

# Используем reduce для суммирования
total_babki = reduce(summa, babki)
print(total_babki) # Выведет 1000


Пример №2: Нахождение максимального числа в списке

Если тебе нужно выбрать самого богатого братана из списка долгов, то reduce поможет и с этим.

# Список долгов братвы
dolgi = [100, 200, 500, 300]

# Функция для нахождения максимума
def max_dolg(x, y):
return x if x > y else y

# Используем reduce для нахождения максимального долга
max_dolg = reduce(max_dolg, dolgi)
print(max_dolg) # Выведет 500


Пример №3: Умножение всех чисел в списке

Ты хочешь узнать, во сколько раз увеличится твой капитал, если каждый день умножать его на какой-то коэффициент.

# Коэффициенты роста капитала за 4 дня
coefficients = [1.1, 1.2, 1.3, 1.4]

# Функция для умножения
def umnozhit(x, y):
return x * y

# Используем reduce для расчета итогового увеличения
total_growth = reduce(umnozhit, coefficients)
print(f"Капитал увеличится в {total_growth:.2f} раз") # Форматируем вывод, чтобы было красиво


Вот так, бро, reduce работает как зверь, когда дело доходит до объединения всего в одно целое. На улицах это как собрать всю братву для большой тусы: по одному они мало что могут, а вместе - сила.

#ПервыйКодНаРайоне
👍3💩1
#Асинхронность на питоне — это как когда у тебя много дел, и ты хочешь все успеть, но времени в обрез. Представь, ты на районе, и у тебя куча дел: надо закинуть вещи в стиралку, сварить макароны и ответить корешу в телеге. В идеале ты бы хотел делать это всё одновременно, чтобы не тратить время зря.

Так вот, в программировании тоже самое. У тебя есть задачи, которые могут долго выполняться, например, запрос на сервер или чтение файла. Если выполнять их последовательно, ты будешь сидеть и ждать каждую задачу, как будто в очереди за шаурмой.

Асинхронность позволяет запускать задачи параллельно, как будто у тебя несколько рук. В Python это делается с помощью ключевых слов async и await.

Вот как это выглядит на коде:

import asyncio

async def стиралка():
print("Закинул вещи в стиралку...")
await asyncio.sleep(5) # стиралка работает
print("Вещи постираны!")

async def макароны():
print("Поставил воду на макароны...")
await asyncio.sleep(3) # вода закипает
print("Макароны сварены!")

async def отвечаю_корешу():
print("Ответил корешу в телеге...")
await asyncio.sleep(1) # печатаешь сообщение
print("Сообщение отправлено!")

async def главный_план():
await asyncio.gather(стиралка(), макароны(), отвечаю_корешу())

# Запуск программы
asyncio.run(главный_план())


Что происходит в этом коде:

1. Ты запускаешь все три задачи параллельно с asyncio.gather().
2. Пока стиралка работает, ты можешь заняться макаронами.
3. И пока вода закипает, ты можешь ответить корешу.

Вместо того чтобы ждать, пока каждая задача выполнится, ты используешь своё время эффективно, как настоящий мастер тайм-менеджмента на районе. Асинхронность в Python — это как будто у тебя суперспособности делать всё и сразу, не тратя время на ожидание.
👏4💩1
Братва, давайте обсудим, когда нужно профилировать работу кода и какие инструменты у нас для этого есть. Это как проверка твоей тачки на сервисе: ты хочешь знать, где у тебя пробелы, что можно улучшить и где ускориться, чтобы гонять еще быстрее.

Когда нужно профилировать код?

Профилирование нужно, когда:

1. Код работает медленно: Если твой код выполняется дольше, чем ты ожидал, профилирование поможет найти узкие места.
2. Большое потребление ресурсов: Если программа жрет слишком много памяти или процессорного времени.
3. Неоптимальные алгоритмы: Когда тебе кажется, что можно оптимизировать алгоритмы, но не знаешь, где именно.
4. Проверка производительности: После внесения изменений или рефакторинга нужно убедиться, что все стало работать не хуже, а лучше.

Инструменты для профилирования

Есть несколько крутых инструментов, которые помогут тебе понять, где твой код тормозит и как это исправить.

1. cProfile

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

Пример использования cProfile

import cProfile

def main():
# Твой код здесь
total = 0
for i in range(1000000):
total += i
print(total)

cProfile.run('main()')


Этот код покажет тебе подробный отчет о времени выполнения каждой части твоего кода.

2. timeit

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

Пример использования timeit

import timeit

# Первый вариант кода
setup_code = "from math import sqrt"
test_code_1 = """
def compute():
result = []
for i in range(100):
result.append(sqrt(i))
return result
"""
# Второй вариант кода
test_code_2 = """
def compute():
return [sqrt(i) for i in range(100)]
"""

time_1 = timeit.timeit(setup=setup_code, stmt=test_code_1, number=10000)
time_2 = timeit.timeit(setup=setup_code, stmt=test_code_2, number=10000)

print(f"Время первого варианта: {time_1}")
print(f"Время второго варианта: {time_2}")


Этот код покажет тебе, какой вариант выполняется быстрее.

3. memory_profiler

memory_profiler — это инструмент для отслеживания использования памяти твоим кодом. Он поможет найти места, где память тратится впустую.

Пример использования memory_profiler

from memory_profiler import profile

@profile
def main():
a = [i for i in range(100000)]
b = [x * 2 for x in a]
del a
return b

if __name__ == '__main__':
main()


Запусти этот код и увидишь, как используется память в каждом участке функции.

Профилирование — это как техосмотр твоей тачки. Ты хочешь знать, где у тебя слабые места, и что можно подтянуть, чтобы все работало как часы. Используй cProfile для общего профилирования, timeit для проверки времени выполнения небольших фрагментов кода и memory_profiler для отслеживания потребления памяти. Так ты всегда будешь на коне и твой код будет летать как ракета!
👍4💩1
Окей, братва, сейчас я вам расскажу про модули в Питоне и как использовать файл __init__.py с фишками. Это как уметь управлять своим районом: знать, где кто живет, как всех организовать и сделать так, чтобы всё работало четко и гладко.

Что такое модуль?

Модуль в Питоне — это просто файл с кодом, который ты можешь импортировать и использовать в других частях своей программы. Например, у тебя есть файл math_functions.py, где ты хранишь все свои математические функции. Этот файл и есть модуль.

# math_functions.py

def add(x, y):
return x + y

def subtract(x, y):
return x - y


Что такое пакет?

Пакет — это как набор модулей, собранных в одну папку. Пакет позволяет структурировать код, делая его организованным и удобным для навигации. Чтобы Питон понял, что папка является пакетом, в ней должен быть файл __init__.py.

Создание пакета

Допустим, у тебя есть проект с такой структурой:

my_project/
math_functions.py
string_functions.py


Ты можешь организовать их в пакет:

my_project/
my_package/
__init__.py
math_functions.py
string_functions.py


Что такое `__init__.py`?

__init__.py — это специальный файл, который позволяет Питону понимать, что эта папка является пакетом. Он может быть пустым, но обычно в нем можно описать код, который должен выполняться при импорте пакета.

Пример использования `__init__.py`

Давайте сделаем так, чтобы наш пакет my_package автоматически импортировал все функции из своих модулей. Вот как может выглядеть __init__.py:

# my_project/my_package/__init__.py

from .math_functions import add, subtract
from .string_functions import uppercase, lowercase


Теперь ты можешь импортировать функции прямо из пакета:

# main.py

from my_package import add, uppercase

print(add(2, 3)) # Выведет 5
print(uppercase('hello')) # Выведет HELLO


Фишки с `__init__.py`

1. Удобный импорт


Ты можешь упростить импорт, собирая все нужные функции и классы в __init__.py, чтобы не писать длинные пути при импорте.

# my_project/my_package/__init__.py

from .math_functions import add, subtract
from .string_functions import uppercase, lowercase

__all__ = ['add', 'subtract', 'uppercase', 'lowercase']


Теперь импорт будет выглядеть еще проще:

from my_package import *

2. Инициализация пакета

Ты можешь выполнять код при загрузке пакета, например, устанавливать конфигурации или проверять зависимости.

# my_project/my_package/__init__.py

print("Загружается пакет my_package")

# Инициализация настроек
config = {
'setting_1': True,
'setting_2': 'default_value'
}


3. Подпакеты и вложенные пакеты

Если у тебя сложная структура проекта, ты можешь иметь вложенные пакеты:

my_project/
my_package/
__init__.py
math_functions.py
string_functions.py
sub_package/
__init__.py
helper_functions.py


В __init__.py пакета sub_package можно описывать импорт функций из вложенного пакета:

# my_project/my_package/sub_package/__init__.py

from .helper_functions import helper_function

4. Динамическая загрузка модулей

Ты можешь динамически загружать модули в зависимости от условий:

# my_project/my_package/__init__.py

import os

if os.getenv('USE_ADVANCED_FUNCTIONS') == '1':
from .advanced_math_functions import advanced_add
else:
from .basic_math_functions import basic_add as add


Заключение

Пакеты и модули помогают тебе держать код в порядке, как на районе. Файл __init__.py делает пакет мощным инструментом, позволяя управлять импортом, инициализацией и организацией кода. Используй эти фишки, чтобы твой проект был четким и организованным, как элитный район.
👍8🥰1💩1
Йо, пацаны, сегодня про важное! 😎🐍

Знаете, что такое GIL? Это такой "Главный Интерпретаторский Замок", который держит ваш Питон в узде, пока он шпарит код в одном потоке. Но вот что интересно — в новом Питоне 3.13 чуваки из Python решили, что можно и без этого замка жить. Казалось бы, свобода для всех потоков, но тут есть засада!

🔥 Если ты компилишь Python без GIL и запускаешь один поток — привет, тормоза! Почему? Ну, потому что система теперь тратит время на то, чтобы сделать всё безопасным для многопоточности. В итоге твой код тормозит примерно на 40% сильнее, чем в обычной версии с GIL! Да, это как если бы ты снял шлем на гонках и надеялся, что ветер сам разрулит — но нет, тормоза будут!

💡 Когда это важно? Если у тебя обычный код, который не гоняет сотни потоков, то без GIL ты тупо теряешь скорость, как будто тачку на ручник поставил. Free-threaded Питон — штука крутая для тех, кто шарит в многопоточности, но если у тебя один поток, держись подальше, пока не прикрутят норм оптимизации.

🥶 Но есть надежда! Говорят, что в Python 3.14 сделают так, что без GIL код будет тормозить всего на 10%, а это уже не так обидно. Но это потом, а пока — не гоняй, где не надо!

Вывод для пацанов: если твой код одинокий волк (однопоточный), то GIL тебе друг. А если ты хочешь жить на грани и жмешь на газ в многопоточке — пробуй без GIL, но будь готов к тормозам в версии 3.13. 🚗💨

Понравилось? Лайк и подписка, вы ж знаете, куда нажать! 💪
3👍2🔥21💩1