uz
Feedback

Firibgarlarga uchmang! Telemetrio bunday kanallarni topadi va belgilaydi 👉 Belgini ko‘rmoqchi bo‘lsangiz, obuna bo‘ling 👈

Python | Вопросы собесов

Python | Вопросы собесов

Kanalga Telegram’da o‘tish

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @sendme_ads

Ko'proq ko'rsatish

📈 Telegram kanali Python | Вопросы собесов analitikasi

Python | Вопросы собесов (@python_easy_ru) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 12 638 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 9 922-o'rinni va Rossiya mintaqasida 51 155-o'rinni egallagan.

📊 Auditoriya ko‘rsatkichlari va dinamika

невідомо sanasidan buyon loyiha tez o‘sib, 12 638 obunachiga ega bo‘ldi.

13 Oktabr, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -115 ga, so‘nggi 24 soatda esa -6 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.

  • Tasdiqlash holati: Tasdiqlanmagan
  • Jalb etish (ER): Auditoriya o‘rtacha 6.04% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 4.18% ini tashkil etuvchi reaksiyalarni to‘playdi.
  • Post qamrovi: Har bir post o‘rtacha 763 marta ko‘riladi; birinchi sutkada odatda 528 ta ko‘rish yig‘iladi.
  • Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 2 ta reaksiya keladi.
  • Tematik yo‘nalishlar: Kontent ставь, модуль, строка, docker, alice kabi asosiy mavzularga jamlangan.

📝 Tavsif va kontent siyosati

Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @sendme_ads”

Yuqori yangilanish chastotasi (oxirgi ma’lumot 14 Oktabr, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.

12 638
Obunachilar
-624 soatlar
-357 kun
-11530 kun
Postlar arxiv
🤔 Что за функция sleep()? Функция sleep() из модуля time приостанавливает выполнение программы на заданное количество секунд. 🚩Как использовать `sleep()` в Python? Функция sleep() принимает один аргумент** — число секунд (может быть дробным).
import time

print("Программа началась...")
time.sleep(3)  # Ожидание 3 секунды
print("3 секунды прошло!")
🚩Где используется `sleep()`? Ожидание в цикле (имитация загрузки)
for i in range(5, 0, -1):
    print(i)
    time.sleep(1)  # Задержка 1 секунда между выводами
print("Старт!")
Запросы к серверу с паузами (чтобы не забанили)
import time
import requests

for i in range(3):
    response = requests.get("https://example.com")
    print(f"Запрос {i+1}: статус {response.status_code}")
    time.sleep(2)  # Ждём 2 секунды перед следующим запросом
Искусственная задержка перед повторной попыткой
for attempt in range(3):
    print(f"Попытка {attempt + 1}...")
    time.sleep(2)  # Ожидание 2 секунды перед новой попыткой
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое SQL JOIN? Это оператор в SQL, с помощью которого можно соединить таблицы, чтобы получить данные, разбросанные по разным структурам. Он позволяет выполнять связанные выборки, что необходимо при нормализации. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какие задачи хорошо параллелятся, какие плохо? Параллельные вычисления — это выполнение нескольких задач одновременно, чтобы ускорить работу программы. Но не все задачи можно эффективно распараллелить. 🚩Независимые задачи (Embarrassingly Parallel Tasks) Это задачи, которые можно выполнять полностью независимо друг от друга, без обмена данными. Обработка изображений (фильтры, преобразования) Генерация фрагментов видео Рендеринг 3D-графики (каждый кадр рендерится отдельно) Обучение моделей машинного обучения на разных данных (если без обмена параметрами)
from concurrent.futures import ProcessPoolExecutor
from PIL import Image

def process_image(image_path):
    img = Image.open(image_path)
    img = img.convert("L")  # Перевод в черно-белый формат
    img.save(f"processed_{image_path}")

images = ["img1.jpg", "img2.jpg", "img3.jpg"]

with ProcessPoolExecutor() as executor:
    executor.map(process_image, images)
🚩Численные вычисления на больших данных (SIMD-операции, GPU-ускорение) Если однотипные операции выполняются на большом массиве данных, их можно делать параллельно. Умножение матриц (используется в нейросетях) Обработка сигналов (FFT, фильтрация) Физические симуляции
import numpy as np

A = np.random.rand(1000, 1000)
B = np.random.rand(1000, 1000)

C = A @ B  # Быстрое умножение матриц (использует несколько ядер процессора)
🚩Веб-запросы и сетевые операции Когда программа ждет ответа от сервера, процесс простаивает. Можно запускать запросы асинхронно, чтобы делать их параллельно. Скачивание файлов Парсинг веб-страниц Вызовы API
import asyncio
import aiohttp

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    urls = ["https://example.com", "https://google.com"]
    tasks = [fetch(url) for url in urls]
    responses = await asyncio.gather(*tasks)
    print(responses)

asyncio.run(main())
Ставь 👍 и забирай 📚 Базу знаний

🤔 Что такое Docker container? Docker container — это запущенный экземпляр образа, изолированный процесс с собственным файловым пространством, сетью и конфигурацией. Контейнеры можно останавливать, перезапускать, удалять и масштабировать. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Какие типы данных относятся к структурам данных? В Python существует множество структур данных, которые предоставляют различные способы хранения и управления данными. Они делятся на два основных типа: встроенные структуры данных и пользовательские структуры данных (созданные программистом). Встроенные структуры данных предоставляют готовые инструменты для решения большинства задач, а пользовательские разрабатываются вручную для более сложных или специфичных случаев. 🚩Встроенные структуры данных К ним относятся те типы данных, которые изначально встроены в Python. Они обеспечивают простое и удобное управление данными. Вот основные типы: 🟠Список (List) Массив, который может содержать элементы разных типов. Динамический (размер меняется), упорядоченный (элементы хранятся в порядке добавления).
my_list = [1, "hello", 3.14]
print(my_list[1])  # "hello"
🟠Кортеж (Tuple) Похож на список, но неизменяемый. Используется для данных, которые не должны быть изменены.
my_tuple = (10, 20, 30)
print(my_tuple[0])  # 10
🟠Множество (Set) Неупорядоченная коллекция уникальных элементов. Удобно для работы с множествами (поиск пересечений, объединений и т.д.).
my_set = {1, 2, 3, 2}
print(my_set)  # {1, 2, 3}
🟠Словарь (Dictionary) Хранит пары ключ-значение. Очень эффективен для быстрого поиска данных по ключу.
my_dict = {"name": "Alice", "age": 25}
print(my_dict["name"])  # Alice
🚩Пользовательские структуры данных Эти структуры создаются с помощью классов или других механизмов, доступных в Python. Они применяются для решения задач, которые не могут быть эффективно выполнены встроенными средствами. 🟠Стек (Stack) Принцип работы: LIFO (последним пришел — первым ушел). Реализуется через список или collections.deque.
stack = []
stack.append(10)  # Добавление
stack.append(20)
print(stack.pop())  # Удаление последнего элемента (20)
🟠Очередь (Queue) Принцип работы: FIFO (первым пришел — первым ушел). Реализуется через collections.deque или библиотеку queue.
from collections import deque

queue = deque()
queue.append(10)
queue.append(20)
print(queue.popleft())  # 10
🟠Связный список (Linked List) Элементы связаны друг с другом через указатели. Гибче массивов, но сложнее в реализации.
class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        if not self.head:
            self.head = Node(data)
        else:
            current = self.head
            while current.next:
                current = current.next
            current.next = Node(data)
Ставь 👍 и забирай 📚 Базу знаний

🤔 В каких случаях используем словари, а в каких списки? Списки лучше использовать, когда важен порядок и данные идут по порядку. Словари подходят для случаев, когда нужно быстро находить значения по ключу или когда данные логически связаны по принципу "ключ-значение", например, при конфигурациях или моделировании объектов. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое многопоточность/многопроцессорность? В программировании многопоточность и многопроцессорность помогают выполнять задачи параллельно, но работают по-разному. 🟠Многопоточность (Multithreading) Многопоточность позволяет одной программе запускать несколько потоков (threads), которые работают одновременно.
import threading
import time

def task(name):
    print(f"{name} начал работу")
    time.sleep(2)
    print(f"{name} завершил работу")

# Создаём два потока
t1 = threading.Thread(target=task, args=("Поток 1",))
t2 = threading.Thread(target=task, args=("Поток 2",))

t1.start()
t2.start()

t1.join()
t2.join()
print("Все потоки завершены")
Вывод
Поток 1 начал работу
Поток 2 начал работу
Поток 1 завершил работу
Поток 2 завершил работу
Все потоки завершены
🟠2. Многопроцессорность (Multiprocessing) Многопроцессорность запускает отдельные процессы, которые работают полностью независимо и могут использовать разные ядра процессора.
import multiprocessing
import time

def task(name):
    print(f"{name} начал работу")
    time.sleep(2)
    print(f"{name} завершил работу")

if __name__ == "__main__":
    p1 = multiprocessing.Process(target=task, args=("Процесс 1",))
    p2 = multiprocessing.Process(target=task, args=("Процесс 2",))

    p1.start()
    p2.start()

    p1.join()
    p2.join()
    print("Все процессы завершены")
Вывод (процессы действительно работают параллельно)
Процесс 1 начал работу
Процесс 2 начал работу
Процесс 1 завершил работу
Процесс 2 завершил работу
Все процессы завершены
Ставь 👍 и забирай 📚 Базу знаний

🤔 Как работает соглашение по использованию атрибутов? В Python используются соглашения об именах, но не строгая инкапсуляция: - _name — соглашение: защищённый (protected) атрибут. Не рекомендуется использовать вне класса или подкласса. - name — приводит к name mangling: переменная переименовывается в _ClassName__name, чтобы избежать конфликтов. - __name — специальные (магические) атрибуты и методы, такие как init, str, dict. Python полагается на сознательность программиста, а не на запреты. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

👩‍💻 Docker — лучший канал для ускоренного обучения DevOps. С помощью инфографики, наглядных визуализаций и коротких обучающ
+5
👩‍💻 Docker — лучший канал для ускоренного обучения DevOps. С помощью инфографики, наглядных визуализаций и коротких обучающих видео вам будут доступны все ключевые концепции работы с Docker и методики DevOps. Прокачать скиллы: t.me/DevopsDocker

🤔 Как разбить список? Разбить список (list) можно разными способами в зависимости от задачи: На части фиксированной длины На N частей По условию 🚩Разбить список на части фиксированного размера Если нужно разделить список на подсписки длиной n, можно использовать list comprehension
def split_list(lst, size):
    return [lst[i:i + size] for i in range(0, len(lst), size)]

data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(split_list(data, 3))  
Вывод
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
🚩Разбить список на N частей (равных или почти равных) Если нужно разделить список на N частей, можно использовать numpy или itertools
import numpy as np

def split_into_n_parts(lst, n):
    return np.array_split(lst, n)

data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(split_into_n_parts(data, 4))  
Вывод
[array([1, 2, 3]), array([4, 5]), array([6, 7]), array([8, 9])]
🚩Разбить список по условию Если нужно разделить список по какому-то критерию, например, на чётные и нечётные числа
data = [1, 2, 3, 4, 5, 6, 7, 8, 9]

even = [x for x in data if x % 2 == 0]
odd = [x for x in data if x % 2 != 0]

print(even, odd)
Вывод
[2, 4, 6, 8] [1, 3, 5, 7, 9]
Ставь 👍 и забирай 📚 Базу знаний

🤔 Плюсы и минусы реляционных баз данных? Плюсы: - Строгая структура данных. - Поддержка SQL. - Транзакции, связи, ограничения. Минусы: - Менее гибкие при изменениях схемы. - Сложности масштабирования по горизонтали. - Могут иметь накладные расходы при сложной структуре. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как понять, какие виды тестов нужны именно сейчас? Выбор типа тестирования зависит от целей, стадии разработки и текущих проблем. Чтобы определить, какие тесты нужны, стоит ответить на вопросы: Что тестируем? (код, API, UI, производительность и т. д.) Какие риски? (где может сломаться, критичность ошибки) Какой этап разработки? (новый код, рефакторинг, релиз) 🚩Как определить нужные тесты прямо сейчас? 🟠Только написали новый код Нужны: Юнит-тесты Тестируем функции и классы отдельно.
def add(a, b):
    return a + b

def test_add():
    assert add(2, 3) == 5  # ✅ Юнит-тест
🟠Соединяем модули или работаем с API Нужны: Интеграционные тесты Проверяем работу всей системы вместе.
def test_api():
    response = requests.get("https://api.example.com/data")
    assert response.status_code == 200
🟠Перед релизом или деплоем Нужны: Функциональные и регрессионные тесты Проверяем ключевые сценарии и старый функционал.
def test_login():
    assert login("user", "password") == "Success"
🟠Изменили UI (например, фронтенд на React) Нужны: UI-тесты (Selenium, Playwright) Проверяем нажатие кнопок, формы и отображение страниц.
from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://example.com")
assert "Example" in driver.title
🟠Если проект должен выдерживать большую нагрузку Нужны: Нагрузочные тесты (Load Testing) Используем locust, JMeter, k6, чтобы проверить сколько пользователей выдержит сервер.
from locust import HttpUser, task

class MyUser(HttpUser):
    @task
    def test_homepage(self):
        self.client.get("/")
Ставь 👍 и забирай 📚 Базу знаний

🤔 Какие типы данных относятся к структурам данных? – Списки (list), – Кортежи (tuple), – Множества (set), – Словари (dict), – Массивы, – Очереди, стеки (в структурах более низкого уровня). Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как на уровне Python реализован декоратор? В Python декораторы — это функции, которые оборачивают другие функции. Они добавляют или изменяют поведение функции без изменения её кода. 🟠Реализация простого декоратора вручную Простейший декоратор, который добавляет текст перед выполнением функции
def my_decorator(func):  
    def wrapper():  
        print("Декоратор сработал!")  
        return func()  # Вызываем исходную функцию  
    return wrapper  # Возвращаем обёрнутую функцию

def say_hello():
    print("Hello!")

say_hello = my_decorator(say_hello)  # Оборачиваем вручную
say_hello()
Вывод
Декоратор сработал!
Hello!
🟠Реализация декоратора через `@` Python позволяет упрощённый синтаксис через @
def my_decorator(func):
    def wrapper():
        print("Декоратор сработал!")
        return func()
    return wrapper

@my_decorator  # Эквивалентно say_hello = my_decorator(say_hello)
def say_hello():
    print("Hello!")

say_hello()
🟠Декоратор с `args` и `kwargs` (универсальный вариант) Если функция принимает аргументы, их нужно передавать через args и kwargs
def my_decorator(func):
    def wrapper(*args, **kwargs):  # Поддержка любых аргументов
        print(f"Вызываем {func.__name__} с аргументами: {args}, {kwargs}")
        return func(*args, **kwargs)  # Вызываем оригинальную функцию
    return wrapper

@my_decorator
def greet(name):
    print(f"Привет, {name}!")

greet("Alice")
Вывод
Вызываем greet с аргументами: ('Alice',), {}
Привет, Alice!
🟠Декоратор с параметрами (фабрика декораторов) Чтобы передавать параметры в декоратор, создаём функцию, которая возвращает декоратор
def repeat(times):  # Функция с параметром
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):  # Повторяем вызов функции
                func(*args, **kwargs)
        return wrapper
    return decorator  # Возвращаем декоратор

@repeat(3)  # Передаём 3 → `repeat(3)` вернёт `decorator`
def hello():
    print("Hello!")

hello()
Вывод
Hello!
Hello!
Hello!
🟠Декораторы классов (`functools.wraps`) Обычные декораторы ломают метаданные функции (__name__, __doc__).
import functools

def my_decorator(func):
    @functools.wraps(func)  # Сохраняем метаданные
    def wrapper(*args, **kwargs):
        print("Декоратор сработал!")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def greet():
    """Функция приветствия"""
    print("Hello!")

print(greet.__name__)  # greet (без wraps было бы wrapper)
print(greet.__doc__)  # Функция приветствия
Ставь 👍 и забирай 📚 Базу знаний

🤔 Как происходит проверка множеств на равенство? Сравниваются все элементы обоих множеств. Порядок не учитывается, только состав. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Для чего нужны static method? Статические методы (static methods) в Python используются для создания методов, которые связаны с классом, но не требуют доступа к экземпляру этого класса или к самим данным класса. Это методы, которые выполняют функции, связанные с классом, но не изменяют и не используют состояние экземпляра (атрибуты объекта) или состояние самого класса (атрибуты класса). Они могут быть вызваны на уровне класса, а не на уровне экземпляра класса. 🚩Как создать статический метод Для создания статического метода в Python используется декоратор @staticmethod. Давайте рассмотрим пример:
class MyClass:
    @staticmethod
    def static_method(arg1, arg2):
        return arg1 + arg2
🚩Пример использования статического метода Вы можете вызывать статический метод как через сам класс, так и через его экземпляр:
result = MyClass.static_method(5, 10)
print(result)  # Вывод: 15

my_instance = MyClass()
result = my_instance.static_method(3, 7)
print(result)  # Вывод: 10
🚩Зачем нужны статические методы 🟠Логическая группировка Статические методы позволяют логически группировать функции, которые связаны с классом, но не зависят от состояния конкретного экземпляра. Это помогает организовать код и делает его более читабельным. 🟠Удобство вызова Иногда полезно вызывать метод, не создавая экземпляр класса. Например, если метод выполняет какую-то утилитарную функцию или обрабатывает данные, не связанные с объектом. 🟠Избежание изменений состояния Поскольку статические методы не могут изменять состояние экземпляра или класса, их использование может способствовать созданию безопасного и предсказуемого кода. 🚩Сравнение с методами класса и экземпляра 🟠Методы экземпляра Методы экземпляра (instance methods) принимают первым аргументом self, что позволяет им изменять состояние конкретного экземпляра класса.
  class MyClass:
      def instance_method(self, value):
          self.value = value  
🟠Методы класса Методы класса (class methods) принимают первым аргументом cls, что позволяет им изменять состояние самого класса.
  class MyClass:
      class_variable = 0

      @classmethod
      def class_method(cls, value):
          cls.class_variable = value
🟠Статические методы Статические методы не принимают self или cls в качестве первого аргумента и не могут изменять состояние экземпляра или класса.
  class MyClass:
      @staticmethod
      def static_method(arg1, arg2):
          return arg1 + arg2
Ставь 👍 и забирай 📚 Базу знаний

🤔 В чём смысл CAP теоремы? CAP теорема утверждает, что распределённая система может одновременно гарантировать только два из трёх: - Consistency (согласованность); - Availability (доступность); - Partition tolerance (устойчивость к разделению сети). Выбирается баланс в зависимости от цели системы. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Что такое dict comprehensions? dict comprehension (генератор словаря) — это способ быстро создать словарь с помощью компактного синтаксиса, похожего на list comprehension. 🚩Простейший пример `dict comprehension`
squares = {x: x**2 for x in range(1, 6)}
print(squares)
Вывод
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
🚩`dict comprehension` с условием (`if`) Оставляем только чётные числа:
squares = {x: x**2 for x in range(1, 11) if x % 2 == 0}
print(squares)
Вывод
{2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
🚩Преобразование списка в словарь Создаём словарь из списка пар (name → длина слова)
names = ["Alice", "Bob", "Charlie"]
name_lengths = {name: len(name) for name in names}
print(name_lengths)
Вывод
{'Alice': 5, 'Bob': 3, 'Charlie': 7}
🚩Обратный словарь (ключи и значения меняются местами) Инвертируем словарь {ключ: значение} → {значение: ключ}
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
print(inverted)
Вывод
{1: 'a', 2: 'b', 3: 'c'}
🚩Генерация словаря из `zip()` Объединяем два списка в словарь
keys = ["name", "age", "city"]
values = ["Alice", 25, "New York"]

person = {k: v for k, v in zip(keys, values)}
print(person)
Вывод
{'name': 'Alice', 'age': 25, 'city': 'New York'}
🚩`dict comprehension` с `if-else` Разделяем числа на чётные и нечётные
numbers = range(1, 6)
parity = {x: "чётное" if x % 2 == 0 else "нечётное" for x in numbers}
print(parity)
Вывод
{1: 'нечётное', 2: 'чётное', 3: 'нечётное', 4: 'чётное', 5: 'нечётное'}

🤔 Что будет, если у двух элементов будет одинаковый хеш? Если у двух объектов одинаковый хеш, Python использует разрешение коллизий: сначала сравнивает хеши, затем вызывает метод eq, чтобы выяснить, действительно ли объекты равны. Если нет — оба объекта будут храниться отдельно, но в одной "корзине". Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний

🤔 Как сгенерировать и применить миграцию? В Django миграции используются для изменения структуры базы данных (создание, изменение и удаление таблиц и полей). 🚩Генерация миграции (`makemigrations`) 🟠Создаём или изменяем модель (`models.py`) Пример модели пользователя:
from django.db import models

class UserProfile(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
🟠Генерируем миграцию Запускаем команду:
python manage.py makemigrations
Django создаст файл миграции в migrations/
migrations/
  0001_initial.py  # Файл с SQL-изменениями
Проверяем SQL-запрос, который будет выполнен
python manage.py sqlmigrate myapp 0001
🚩Применение миграции (`migrate`) После генерации нужно применить миграции к базе данных:
python manage.py migrate
🚩Что делать, если модель изменилась? Добавим поле в models.py
class UserProfile(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    email = models.EmailField(default="example@example.com")  # Добавили поле
Сгенерируем новую миграцию
python manage.py makemigrations
Применяем изменения к БД
python manage.py migrate
🚩Откат миграций (`migrate <номер>`) Если нужно откатить последнее изменение:
python manage.py migrate myapp 0001  # Откат до первой миграции
Ставь 👍 и забирай 📚 Базу знаний