Python | Вопросы собесов
13.4K subscribers
17 photos
1 file
343 links
Разбираем вопросы с собеседований на Python разработчика. Django, Flask, FastApi

Реклама: @easyoffer_adv
Решай тесты - t.me/+20tRfhrwPpM4NDQy

Нарешивай задачи - t.me/+nsl4meWmhfQwNDVi
Ищи работу - t.me/+cXGKkrOY2-w3ZTky
Download Telegram
Что знаешь про агрегацию ?
Спросят с вероятностью 3%

Агрегация в ООП
— это концепция, при которой один класс включает в себя другой класс в качестве части, но обе части могут существовать независимо друг от друга. Агрегация описывает "имеет-a" отношения между объектами, где один объект является контейнером или коллекцией для другого объекта, но не несет ответственности за его существование.

Рассмотрим простой пример с классами Person и Address:
class Address:
def __init__(self, street, city):
self.street = street
self.city = city

def display(self):
return f"{self.street}, {self.city}"

class Person:
def __init__(self, name, address):
self.name = name
self.address = address # Агрегация

def display(self):
return f"{self.name} lives at {self.address.display()}"

# Создание объектов Address и Person
address = Address("123 Main St", "New York")
person = Person("John Doe", address)

print(person.display()) # Выведет: John Doe lives at 123 Main St, New York


В этом примере:


Класс Address определяет атрибуты улицы и города и метод для отображения адреса.
Класс Person включает объект Address в качестве атрибута.

Оба объекта могут существовать независимо. Объект Address может существовать без объекта Person, и наоборот.

Различие между агрегацией и композицией

Агрегация: Части могут существовать независимо. Если объект-контейнер удален, включенные объекты могут продолжать существовать.
Композиция: Части не могут существовать независимо. Если объект-контейнер удален, все включенные объекты также будут удалены.

Пример агрегации:

class Engine:
def __init__(self, horsepower):
self.horsepower = horsepower

class Car:
def __init__(self, model, engine):
self.model = model
self.engine = engine # Агрегация

engine = Engine(150)
car = Car("Toyota", engine)

# Удаление объекта car не удаляет объект engine
del car
print(engine.horsepower) # Выведет: 150


Пример композиции:
class Engine:
def __init__(self, horsepower):
self.horsepower = horsepower

class Car:
def __init__(self, model, horsepower):
self.model = model
self.engine = Engine(horsepower) # Композиция

car = Car("Toyota", 150)

# Удаление объекта car также удаляет объект engine
del car
# Теперь доступ к engine невозможен


Преимущества

1️⃣Гибкость: Компоненты могут быть легко заменены или изменены без влияния на другие части системы.
2️⃣Повторное использование: Один и тот же объект может быть использован в нескольких агрегатах.
3️⃣Чистая архитектура: Способствует созданию более модульного и поддерживаемого кода.

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

👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 1096 вопроса на Python разработчика. Ставь 👍 если нравится контент

🔐 База собесов | 🔐 База тестовых
Что такое dependency injection ?
Спросят с вероятностью 3%

Внедрение зависимостей (Dependency Injection, DI) — это паттерн проектирования в ООП, который используется для уменьшения жесткой связи между компонентами системы и повышения их модульности и тестируемости. Зависимости (объекты, от которых зависит класс) передаются классу извне, а не создаются внутри класса.

Зачем он нужен?

1️⃣Ослабление связей: Уменьшает жесткую связь между классами, делая их более независимыми друг от друга.
2️⃣Повышение тестируемости: Позволяет легко заменять реальные зависимости на поддельные (mock) объекты во время тестирования.
3️⃣Гибкость и расширяемость: Облегчает изменение и замену зависимостей без необходимости изменять код класса.

Как он работает?


DI может быть реализован несколькими способами:

1️⃣Внедрение через конструктор (Constructor Injection):
Зависимости передаются через параметры конструктора.

      class Service:
def do_something(self):
return "Service is doing something."

class Client:
def __init__(self, service):
self.service = service

def perform_action(self):
return self.service.do_something()

# Внедрение зависимости через конструктор
service = Service()
client = Client(service)
print(client.perform_action()) # Выведет: Service is doing something.


2️⃣Внедрение через сеттер (Setter Injection):
Зависимости передаются через методы установки (сеттеры).
      class Client:
def set_service(self, service):
self.service = service

def perform_action(self):
return self.service.do_something()

# Внедрение зависимости через сеттер
service = Service()
client = Client()
client.set_service(service)
print(client.perform_action()) # Выведет: Service is doing something.


3️⃣Внедрение через интерфейс (Interface Injection):
В этом подходе используется интерфейс для предоставления зависимостей. Это менее распространенный метод в Python, так как язык не имеет явной поддержки интерфейсов как, например, Java.

Преимущества

1️⃣Уменьшение жесткой связи: Классы меньше зависят друг от друга, что упрощает их изменение и замену.
2️⃣Повышение модульности: Каждый компонент может быть разработан и протестирован отдельно.
3️⃣Легкость тестирования: Зависимости могут быть легко заменены на заглушки или mock-объекты во время тестирования, что делает тестирование проще и надежнее.
4️⃣Улучшенная читаемость и поддерживаемость: Четко видно, какие зависимости нужны классу, что делает код более понятным.

Недостатки

1️⃣Сложность настройки: Может потребоваться больше начальных настроек для передачи всех зависимостей.
2️⃣Понимание паттерна: Требуется понимание концепции DI для правильного использования, что может быть сложным для начинающих разработчиков.

Рассмотрим пример с веб-приложением, где у нас есть контроллер, который зависит от сервиса для обработки бизнес-логики:
class OrderService:
def process_order(self, order_id):
return f"Processing order {order_id}"

class OrderController:
def __init__(self, order_service):
self.order_service = order_service

def handle_request(self, order_id):
return self.order_service.process_order(order_id)

# Внедрение зависимости через конструктор
order_service = OrderService()
order_controller = OrderController(order_service)
print(order_controller.handle_request(123)) # Выведет: Processing order 123


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

👉 Можно посмотреть Примеры как отвечают люди на этот вопрос, или перейти К списку 1096 вопроса на Python разработчика. Ставь 👍 если нравится контент

🔐 База собесов | 🔐 База тестовых
📌 Какие бывают виды тестов ?

💬 Спросят с вероятностью 3%

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

1️⃣ Юнит-тестирование (Unit Testing)

Цель: Проверка отдельных модулей или компонентов программы (функций, методов, классов) в изоляции.

Характеристики: Изолированные тесты, обычно покрывают небольшой объем кода.

Инструменты: unittest, pytest.

2️⃣ Интеграционное тестирование (Integration Testing)

Цель: Проверка взаимодействия между несколькими модулями или компонентами.

Характеристики: Проверяет, работают ли компоненты корректно вместе.

Инструменты: pytest, nose2, unittest.

3️⃣ Функциональное тестирование (Functional Testing)

Цель: Проверка функциональности приложения в соответствии с требованиями.

Характеристики:
Ориентируется на результат выполнения функциональных задач.

Инструменты: pytest, unittest, Selenium для веб-приложений.

4️⃣ Системное тестирование (System Testing)

Цель: Проверка всей системы целиком для обеспечения соответствия требованиям.

Характеристики: Тестирование всех компонентов приложения как единого целого.

Инструменты: Manual testing, Selenium, pytest.

5️⃣ Приемочное тестирование (Acceptance Testing)

Цель: Проверка системы на соответствие требованиям пользователя и готовность к эксплуатации.

Характеристики: Оценивается заказчиком или конечным пользователем.

Инструменты: Behave, Cucumber, Manual testing.

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

Юнит-тестирование с pytest
# math_operations.py
def add(a, b):
return a + b

# test_math_operations.py
import pytest
from math_operations import add

def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0
assert add(-1, -1) == -2

if __name__ == '__main__':
pytest.main()


Интеграционное тестирование с pytest
# database_operations.py
def connect_to_db():
return "Connected to DB"

def get_data_from_db():
return {"data": "Sample data"}

# test_integration.py
import pytest
from database_operations import connect_to_db, get_data_from_db

def test_db_integration():
assert connect_to_db() == "Connected to DB"
data = get_data_from_db()
assert "data" in data
assert data["data"] == "Sample data"

ifittest, py== '__main__':
pytest.main()


Функциональное тестирование с Selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

def test_google_search():
driver = webdriver.Chrome()
driver.get("https://www.google.com")
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys("pytest")
search_box.send_keys(Keys.RETURN)
assert "pytest" in driver.title
driver.quit()

ifты: unitte== '__main__':
test_google_search()


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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
📌 Что такое mock ?

💬 Спросят с вероятностью 3%

mock — это термин, который относится к созданию фиктивных объектов или имитаций для тестирования. Обычно означает использование библиотеки unittest.mock, которая входит в стандартную библиотеку и предоставляет мощные инструменты для создания и управления mock-объектами.

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

Основные возможности:

1️⃣ Mock-объекты: Можно создавать фиктивные объекты, которые имитируют поведение реальных объектов.

2️⃣ Патчинг (patching): Позволяет временно заменять объекты в определенном пространстве имен на mock-объекты.

3️⃣ Отслеживание вызовов: Mock-объекты могут отслеживать, какие методы или атрибуты были вызваны и с какими аргументами.

4️⃣ Настройка возвращаемых значений и побочных эффектов: Можно задавать возвращаемые значения и побочные эффекты для методов mock-объектов.

Основные компоненты:

1️⃣ `Mock` класс: Базовый класс для создания mock-объектов.

2️⃣ mock — этдекоратор и контекстный менеджер: Используются для замены объектов на mock-объекты в определенном пространстве имен.

3️⃣ MagicMock класс: Расширяет Mock и включает магические методы (например, getitem, setitem и т.д.).

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

Пример создания mock-объекта
from unittest.mock import Mock

# Создание mock-объекта
mock_obj = Mock()

# Настройка возвращаемого значения для метода
mock_obj.some_method.return_value = 42

# Вызов метода
result = mock_obj.some_method()
print(result) # Вывод: 42

# Проверка вызова метода
mock_obj.some_method.assert_called_once()

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

from unittest.mock import patch

# Предположим, у нас есть функция, которая делает HTTP-запрос
def fetch_data():
import requests
response = requests.get("https://api.example.com/data")
return response.json()

# Тестируем функцию с использованием patch
@patch('requests.get')
def test_fetch_data(mock_get):
# Настройка mock-объекта
mock_response = Mock()
mock_response.json.return_value = {"key": "value"}
mock_get.return_value = mock_response

# Вызов тестируемой функции
result = fetch_data()
assert result == {"key": "value"}

# Проверка вызова mock-объекта
mock_get.assert_called_once_with("https://api.example.com/data")

# Запуск теста
test_fetch_data()

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

from unittest.mock import MagicMock

# Создание MagicMock-объекта
mock_obj = MagicMock()

# Настройка возвращаемого значения для магического методаен.
3. `Magicmock_obj.__getitem__.return_value = "value"

# Вызов магического метода
result = mock_obj["key"]
print(result) # Вывод: value

# Проверка вызова магического метода
mock_obj.__getitem__.assert_called_once_with("key")


Преимущества:

1️⃣ Изоляция тестов: Позволяет тестировать компоненты в изоляции от их зависимостей.

2️⃣ Повышение надежности тестов: Тесты становятся менее зависимыми от внешних факторов, таких как сетевые соединения или состояние базы данных.

3️⃣ Гибкость: Mock-объекты можно легко настраивать для разных сценариев тестирования.

4️⃣ Отслеживание поведения: Можно отслеживать, как и с какими параметрами были вызваны методы и атрибуты.

Mock-объекты являются мощным инструментом для создания изолированных и надежных тестов в Python. Библиотека unittest.mock предоставляет все необходимые средства для создания и управления mock-объектами, позволяя эффективно тестировать код, избегая зависимости от внешних ресурсов и улучшая качество тестирования.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой тип данных в Python является неизменяемым?
Anonymous Quiz
5%
list
15%
set
6%
dict
74%
tuple
📌 Что такое pytest ?

💬 Спросят с вероятностью 3%

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

Основные особенности

1️⃣ Простой синтаксис: Использует лаконичный и интуитивно понятный синтаксис для написания тестов.

2️⃣ Автоматическое обнаружение тестов: Автоматически обнаруживает тестовые функции и методы, что упрощает организацию тестов.

3️⃣ Фикстуры (fixtures): Предоставляет мощный механизм фикстур, который позволяет задавать исходные условия для тестов.

4️⃣ Параметризация тестов: Позволяет запускать один и тот же тест с разными входными данными, что сокращает количество повторяющегося кода.

5️⃣ Поддержка плагинов: Имеет богатую экосистему плагинов, которые расширяют его функциональность.

6️⃣ Совместимость: Совместим с unittest и другими фреймворками, что упрощает миграцию.

Установка pytest

Можно установить с помощью pip:
pip install pytest


Тестирование функции

Предположим, у нас есть простая функция для сложения двух чисел:
# math_operations.py
def add(a, b):
return a + b


Теперь напишем тест для этой функции с его использованием:
# test_math_operations.py
from math_operations import add

def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0
assert add(-1, -1) == -2


Запуск тестов

Для него можно использовать команду pytest:
pytest test_math_operations.py


pytest автоматически найдет и выполнит все тесты, а затем выведет результаты на экран.

Фикстуры (fixtures)

Позволяют задавать инициализацию, необходимую для тестов. Они могут использоваться для подготовки данных, создания объектов и других операций, которые нужны перед выполнением тестов.
# test_math_operations.py
import pytest
from math_operations import add

@pytest.fixture
def input_data():
return 1, 2

def test_add(input_data):
a, b = input_data
assert add(a, b) == 3


Параметризация тестов

Позволяет запускать один и тот же тест с разными наборами данных.
# test_math_operations.py
import pytest
from math_operations import add

@pytest.mark.parametrize("a, b, expected", [
(1, 2, 3),
(-1, 1, 0),
(-1, -1, -2),
])
def test_add(a, b, expected):
assert add(a, b) == expected


Плагины:

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

pytest-cov: Генерация отчетов о покрытии кода тестами.

pytest-xdist: Параллельное выполнение тестов.

pytest-mock: Интеграция с библиотекой unittest.mock для создания и управления mock-объектами.

Пример использования плагина pytest-cov

Для его установки:
pip install pytest-cov


Запуск тестов с генерацией отчета о покрытии:
pytest --cov=my_module test_my_module.py


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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
📌 Что такое unit test ?

💬 Спросят с вероятностью 3%

Юнит-тестирование (unit testing) — это метод тестирования ПО, при котором отдельные модули или компоненты (юниты) программы проверяются на корректность их работы. Предназначены для проверки небольших, изолированных частей кода, таких как функции или методы классов, чтобы убедиться, что они работают правильно.

Особенности:

1️⃣ Изоляция: Каждый тест проверяет отдельный модуль или компонент программы в изоляции от других модулей.

2️⃣ Автоматизация: Часто автоматизируются, что позволяет быстро проверять корректность кода при внесении изменений.

3️⃣ Повторяемость: Можно запускать многократно, чтобы убедиться, что изменения в коде не привели к новым ошибкам.

4️⃣ Модульность: Должны быть небольшими и простыми, охватывающими все возможные сценарии использования тестируемого кода.

Преимущества:

1️⃣ Раннее обнаружение ошибок: Помогают выявлять ошибки на ранней стадии разработки.

2️⃣ Упрощение отладки: Когда они изолированы, легче понять и исправить причину ошибки.

3️⃣ Документация: Юнит-тесты служат живой документацией кода, показывая, как он должен работать.

4️⃣ Уверенность при рефакторинге: Наличие тестов позволяет смело изменять код, зная, что тесты помогут обнаружить возможные ошибки.

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

Он является встроенным и предоставляет богатые возможности для написания и выполнения юнит-тестов.

Пример кода для юнит-тестирования:

Предположим, у нас есть модуль math_operations.py с функцией add:
# math_operations.py
def add(a, b):
return a + b


Теперь тест для этой функции:
# test_math_operations.py
import unittest
from math_operations import add

class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(add(1, 2), 3)
self.assertEqual(add(-1, 1), 0)
self.assertEqual(add(-1, -1), -2)

if __name__ == '__main__':
unittest.main()


Запуск тестов

Для него можно выполнить скрипт test_math_operations.py:
python test_math_operations.py


Или использовать команду unittest из командной строки:
python -m unittest test_math_operations.py


Использование pytest для юнит-тестирования

Предлагает более лаконичный и мощный подход к юнит-тестированию.
# test_math_operations.py
from math_operations import add

def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0
assert add(-1, -1) == -2


Запуск тестов с pytest

Убедитесь, что он установлен. Вы можете установить его с помощью pip:
pip install pytest


Запуск тестов:
pytest test_math_operations.py


Юнит-тестирование — это важный метод тестирования, который помогает обеспечивать качество и надежность кода, проверяя отдельные модули или компоненты программы. Использование таких инструментов, как unittest и pytest, позволяет автоматизировать процесс тестирования, выявлять ошибки на ранних стадиях разработки и уверенно вносить изменения в код.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какой метод используется для чтения всего содержимого файла в Python?
Anonymous Quiz
61%
read()
6%
readline()
13%
readall()
20%
readlines()
📌 Какие модули для тестирования есть ?

💬 Спросят с вероятностью 3%

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

Встроенные модули

1️⃣ unittest

Стандартный модуль для модульного тестирования.

Основан на фреймворке xUnit, что делает его знакомым для многих разработчиков.

Поддерживает создание тестовых классов, тестовых методов, наборов тестов и многое другое.

import unittest

class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 1, 2)

if __name__ == '__main__':
unittest.main()


2️⃣ doctest

Позволяет писать тесты прямо в строках документации (docstrings) кода.

Удобен для проверки примеров использования функций.

      def add(a, b):
"""
Возвращает сумму a и b.

>>> add(1, 2)
3
>>> add(-1, 1)
0
"""
return a + b

if name == '__main__':
import doctest
doctest.testmod()


Внешние библиотеки

1️⃣ pytest

Одна из самых популярных библиотек для тестирования в Python.

Поддерживает простой и лаконичный синтаксис тестов.

Поддерживает фикстуры, параметризацию тестов, плагины и многое другое.

      def add(a, b):
return a + b

def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0

if name == '__main__':
import pytest
pytest.main()


2️⃣ nose2

Наследник библиотеки nose.

Совместим с unittest и расширяет его возможности.

Поддерживает плагины и расширяемость.

      import unittest

class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 1, 2)

if name == '__main__':
import nose2
nose2.main()


3️⃣ hypothesis

Библиотека для проперти-бейсд тестирования (property-based testing).

Генерирует случайные данные для тестов и находит краевые случаи.

      from hypothesis import given
from hypothesis.strategies import integers

def add(a, b):
return a + b

@given(integers(), integers())
def test_add(x, y):
assert add(x, y) == x + y

if name == '__main__':
import pytest
pytest.main()

4️⃣ mock (unittest.mock)

Библиотека для создания фиктивных объектов и имитации поведения зависимостей.

Включена в стандартную библиотеку Python начиная с версии 3.3 как unittest.mock.

      import unittest
from unittest.mock import patch

def fetch_data():
# Представим, что эта функция делает запрос к внешнему API
return "Real data"

class TestFetchData(unittest.TestCase):
@patch('main.fetch_data', return_value="Mock data")
def test_fetch_data(self, mock_fetch):
result = fetch_data()
self.assertEqual(result, "Mock data")

if:
== 'main':
unittest.main()


5️⃣ tox

Инструмент для автоматизации тестирования в различных средах.

Полезен для тестирования кода на разных версиях Python и с разными зависимостями.

      [tox]
envlist = py36, py37, py38

[testenv]
deps = pytest
commands = pytest


6️⃣ coverage

Инструмент для измерения покрытия кода тестами.

Генерирует отчеты, показывающие, какие части кода были протестированы, а какие нет.

      coverage run -m pytest
coverage report
coverage html # Создает отчет в формате HTML


Выбор инструмента для тестирования зависит от ваших потребностей и предпочтений. Стандартные модули, такие как unittest и doctest, предоставляют базовые возможности для тестирования, в то время как внешние библиотеки, такие как pytest, nose2 и hypothesis, предлагают более мощные и гибкие инструменты для написания и выполнения тестов. Использование библиотек для измерения покрытия кода, таких как coverage, помогает убедиться, что ваш код полностью протестирован.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
📌 Что такое monkey patch ?

💬 Спросят с вероятностью 3%

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

Основные особенности:

1️⃣ Динамическое изменение кода: Изменения вносятся в код во время выполнения программы.

2️⃣ Без изменения исходного кода: Оригинальный исходный код библиотеки или модуля не изменяется.

3️⃣ Часто используется для исправления ошибок: Monkey patching может использоваться для исправления ошибок в сторонних библиотеках или для добавления отсутствующей функциональности.

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

Оригинальная функция

Допустим, у нас есть модуль math_operations.py с функцией add:
# math_operations.py
def add(a, b):
return a + b


Monkey Patching

Изменить функцию add, чтобы она вместо сложения выполняла вычитание. Мы можем сделать это с помощью monkey patching:
import math_operations

# Оригинальная функция
print(math_operations.add(5, 3)) # Вывод: 8

# Monkey patching
def new_add(a, b):
return a - b

math_operations.add = new_add

# После monkey patching
print(math_operations.add(5, 3)) # Вывод: 2


Пример с использованием стандартной библиотеки

Где изменим поведение метода str.upper:
# Оригинальный метод
print("hello".upper()) # Вывод: HELLO

# Monkey patching
def new_upper(self):
return self.lower()

str.upper = new_upper

# После monkey patching
print("hello".upper()) # Вывод: hello


Применение Monkey Patching в тестировании

Часто используется в тестировании для имитации поведения зависимостей или для замены реальных объектов на фиктивные (mock) объекты.
import unittest
from unittest.mock import patch

class ExternalService:
def fetch_data(self):
# Представим, что эта функция делает запрос к внешнему API
return "Real data"

def process_data():
service = ExternalService()
return service.fetch_data()

class TestProcessData(unittest.TestCase):
@patch('__main__.ExternalService.fetch_data', return_value="Mock data")
def test_process_data(self, mock_fetch_data):
result = process_data()
self.assertEqual(result, "Mock data")

if __name__ == '__main__':
unittest.main()


В этом примере:

Используется unittest.mock.patch для замены метода fetch_data класса ExternalService на фиктивный метод, возвращающий "Mock data".

Тест проверяет, что функция process_data возвращает подделанные данные вместо реальных данных.

Предостережения при его использовании

Хотя monkey patching может быть полезным, оно также может привести к проблемам, если использовать его неправильно:

1️⃣ Проблемы с отладкой: Динамическое изменение кода может затруднить отладку и понимание программы.

2️⃣ Неожиданное поведение: Изменение поведения стандартных библиотек или модулей может привести к неожиданным результатам в других частях программы.

3️⃣ Нарушение инкапсуляции: Monkey patching нарушает принцип инкапсуляции, так как изменения вносятся в код извне.

Monkey patching — мощная техника, которая позволяет динамически изменять поведение модулей и библиотек во время выполнения программы. Она может быть полезна для исправления ошибок, добавления функциональности или создания фиктивных объектов для тестирования. Однако использовать monkey patching следует осторожно, чтобы избежать проблем с отладкой и неожиданным поведением программы.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
📌 Как реализовывать тесты ?

💬 Спросят с вероятностью 3%

Реализация тестов — важная часть процесса разработки программного обеспечения, которая помогает обеспечить корректность и надёжность кода. Для написания тестов обычно используется модуль unittest, который является стандартным модулем для тестирования и поставляется вместе. Другие популярные библиотеки для тестирования включают pytest и nose.

Использование модуля unittest

Предоставляет инструменты для создания и выполнения тестов. Давайте рассмотрим основные шаги для написания тестов с использованием unittest.

Основные шаги для написания тестов:

1️⃣ Создание тестового класса: Тестовый класс должен наследоваться от unittest.TestCase.

2️⃣ Написание тестовых методов: Каждый тестовый метод должен начинаться с test_.

3️⃣ Использование методов утверждений: Методы утверждений (assert) используются для проверки условий, таких как assertEqual, assertTrue, assertFalse, assertRaises и другие.

4️⃣ Запуск тестов: Запуск тестов можно осуществить с помощью командной строки или специального вызова внутри скрипта.

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

Допустим, у нас есть простая функция для сложения двух чисел:
# Пример функции в файле my_module.py
def add(a, b):
return a + b


Теперь мы напишем тесты для этой функции:
# Пример теста в файле test_my_module.py
import unittest
from my_module import add

class TestAddFunction(unittest.TestCase):

def test_add_integers(self):
self.assertEqual(add(1, 2), 3)
self.assertEqual(add(-1, 1), 0)
self.assertEqual(add(-1, -1), -2)

def test_add_floats(self):
self.assertAlmostEqual(add(1.1, 2.2), 3.3)

def test_add_strings(self):
self.assertEqual(add('a', 'b'), 'ab')

if __name__ == '__main__':
unittest.main()


Запуск тестов

Тесты можно запускать разными способами. Вот несколько способов:

1️⃣ Запуск из командной строки:
python -m unittest test_my_module.py


2️⃣ Запуск тестов из файла:

Просто запустите файл test_my_module.py как обычный Python-скрипт.
python test_my_module.py


Использование pytest

Это мощная библиотека для тестирования, которая упрощает написание и выполнение тестов. Она поддерживает функциональные и модульные тесты и имеет лаконичный синтаксис.
# Пример функции в файле my_module.py
def add(a, b):
return a + b


Запуск тестов с pytest

Убедитесь, что pytest установлен. Вы можете установить его с помощью pip:
pip install pytest


Запуск тестов:
pytest test_my_module.py


Преимущества:

1️⃣ Простой и лаконичный синтаксис: Тесты пишутся проще и читаются легче.

2️⃣ Богатый функционал: Поддержка фикстур, параметризация тестов, расширенные возможности для ассертов.

3️⃣ Множество плагинов: Расширяемость за счет множества доступных плагинов.

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
📌 Как еще мы можем гарантировать закрытие файла, если не через with ?

💬 Спросят с вероятностью 3%

Если не использовать конструкцию with, гарантировать закрытие файла можно несколькими способами, в частности, используя конструкцию try-finally или модуль contextlib.

Использование try-finally

Позволяет обеспечить закрытие файла даже в случае возникновения исключения. В блоке finally можно указать код, который должен выполниться независимо от того, было ли исключение в блоке try или нет.
file = open('example.txt', 'r')
try:
content = file.read()
print(content)
finally:
file.close()


В этом примере:

Файл открывается и читается в блоке try.

Независимо от того, возникло ли исключение в блоке try или нет, файл будет закрыт в блоке finally.

Использование модуля contextlib

Предоставляет утилиты для работы с контекстными менеджерами. Одной из таких утилит является функция contextlib.closing, которая может быть использована для автоматического закрытия объекта, поддерживающего метод close.
from contextlib import closing

file = open('example.txt', 'r')
with closing(file) as f:
content = f.read()
print(content)


В этом примере:

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

Когда блок with завершается, closing автоматически закрывает файл.

Создание пользовательского контекстного менеджера

Также можно создать свой собственный контекстный менеджер с помощью класса, который реализует методы __enter__ и exit.
class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode

def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file

def __exit__(self, exc_type, exc_value, traceback):
self.file.close()

# Использование
with FileManager('example.txt', 'r') as file:
content = file.read()
print(content)


В этом примере:

Класс FileManager реализует методы enter и exit.

Метод enter открывает файл и возвращает его.

Метод exit закрывает файл, обеспечивая его корректное закрытие.

Гарантировать закрытие файла можно несколькими способами, помимо использования конструкции with:

1️⃣ Использовать конструкцию try-finally, чтобы файл всегда закрывался независимо от возникновения исключений.

2️⃣ Использовать модуль contextlib и его утилиту closing для автоматического закрытия файла.

3️⃣ Создать пользовательский контекстный менеджер, реализовав методы enter и exit.

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что произойдет, если в Python вызвать функцию, использующую yield, но не пройти по итератору?
Anonymous Quiz
10%
возникнет исключение
16%
вернется None
25%
функция завершится без результата
50%
создастся генератор
📌 Как Python взаимодействует с файлом ?

💬 Спросят с вероятностью 3%

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

Открытие файла

Файл можно открыть с помощью встроенной функции open(). Эта функция возвращает объект файла, который затем можно использовать для выполнения различных операций с файлом.

Синтаксис функции open():
file_object = open(file_name, mode)


file_name: Имя файла, который вы хотите открыть.

mode: Режим, в котором вы хотите открыть файл. Основные режимы включают:

'r': чтение (по умолчанию)

'w': запись (содержимое файла будет удалено)

'a': добавление (новые данные будут добавлены в конец файла)

'b': бинарный режим (добавляется к основному режиму, например 'rb' или 'wb')

Примеры:

Чтение файла
# Открытие файла в режиме чтения
with open('example.txt', 'r') as file:
content = file.read()
print(content)


Запись в файл
# Открытие файла в режиме записи
with open('example.txt', 'w') as file:
file.write('Hello, world!')


Добавление в файл
# Открытие файла в режиме добавления
with open('example.txt', 'a') as file:
file.write('\nAppended text.')


Чтение из файла

Файловый объект предоставляет несколько методов для чтения данных:

read(size=-1): Читает весь файл или size байт, если указан.

readline(size=-1): Читает одну строку или size байт, если указан.

readlines(): Читает все строки файла и возвращает их в виде списка.

Примеры:

Чтение всего файла
with open('example.txt', 'r') as file:
content = file.read()
print(content)


Чтение файла построчно
with open('example.txt', 'r') as file:
for line in file:
print(line, end='') # `end=''` чтобы избежать двойного переноса строки


Чтение файла в список строк
with open('example.txt', 'r') as file:
lines = file.readlines()
print(lines)


Запись в файл

Файловый объект также предоставляет методы для записи данных:

write(string): Записывает строку в файл.

writelines(lines): Записывает список строк в файл.

Примеры:

Запись строки в файл
with open('example.txt', 'w') as file:
file.write('Hello, world!')


Запись списка строк в файл
lines = ['First line\n', 'Second line\n', 'Third line\n']
with open('example.txt', 'w') as file:
file.writelines(lines)


Использование менеджеров контекста (with)

Она автоматически закрывает файл после выхода из блока with, даже если возникло исключение.
with open('example.txt', 'r') as file:
content = file.read()
print(content)


Закрытие файла

Если файл открыт без использования with, его нужно закрыть вручную с помощью метода close().
file = open('example.txt', 'r')
content = file.read()
print(content)
file.close()


Дополнительные операции с файлами

Модуль os предоставляет функции для работы с файловой системой, такие как переименование, удаление и создание директорий.

Примеры:

Переименование файла
import os
os.rename('example.txt', 'new_example.txt')


Удаление файла
import os
os.remove('new_example.txt')


Создание директории
import os
os.mkdir('new_directory')


Удаление директории
import os
os.rmdir('new_directory')


Python предоставляет богатые возможности для работы с файлами, начиная с простого чтения и записи и заканчивая сложными операциями с файловой системой. Использование менеджеров контекста (with) обеспечивает безопасное и эффективное управление файлами.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
📌 Что известно о принципе SLAP ?

💬 Спросят с вероятностью 3%

Принцип SLAP (Single Level of Abstraction Principle) относится к принципам чистого кода и разработки программного обеспечения. Он заключается в том, что каждый метод или функция должны работать на одном уровне абстракции.

🤔 Зачем нужен данный принцип?

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

🤔 Как использовать данный принцип?

При разработке ПО, вы должны стремиться к тому, чтобы методы и функции содержали действия только одного типа или уровня абстракции. Это может быть достигнуто через декомпозицию задач на более мелкие подзадачи и создание соответствующих методов для каждой подзадачи.
def process_order(order):
# Проверка наличия товара на складе
for item in order['items']:
if not warehouse_has_item(item):
raise Exception("Товара нет на складе")

# Расчет общей стоимости заказа
total_price = 0
for item in order['items']:
total_price += item['price'] * item['quantity']

# Создание записи в базе данных
save_order_to_db(order, total_price)

# Отправка уведомления клиенту
send_confirmation_email(order['customer_email'])


Эта функция выполняет несколько задач на разных уровнях абстракции: проверка наличия товара, расчет стоимости, работа с базой данных, отправка email. Это нарушает принцип SLAP.
def process_order(order):
check_items_availability(order['items'])
total_price = calculate_total_price(order['items'])
save_order(order, total_price)
notify_customer(order['customer_email'])

def check_items_availability(items):
for item in items:
if not warehouse_has_item(item):
raise Exception("Товара нет на складе")

def calculate_total_price(items):
total_price = 0
for item in items:
total_price += item['price'] * item['quantity']
return total_price

def save_order(order, total_price):
save_order_to_db(order, total_price)

def notify_customer(email):
send_confirmation_email(email)


🤔 Почему это важно?

1️⃣ Упрощение понимания кода: Легче читать и понимать, когда каждая функция выполняет только одну задачу.

2️⃣ Легкость тестирования: Отдельные функции проще тестировать.

3️⃣ Поддерживаемость: Изменения в одной части программы менее вероятно вызовут ошибки в другой.

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что произойдет, если в Python изменить ключ в dict во время итерации по нему?
Anonymous Quiz
17%
ничего не произойдет
17%
возникнет ошибка компиляции
23%
возникнет исключение RuntimeError
43%
значение ключа изменится
📌 Что такое code cohesion & code coupling ?

💬 Спросят с вероятностью 3%

Кодовые метрики когезии (cohesion) и связи (coupling) играют ключевую роль в проектировании программного обеспечения. Давайте разберем их более подробно.

Когезия (Cohesion)

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

🤔 Почему это важно:

1️⃣ Понятность: Высокая когезия делает модули более понятными и логичными, так как они выполняют четко определенную функцию.

2️⃣ Поддерживаемость: Модули с высокой когезией легче модифицировать, тестировать и отлаживать, поскольку изменения в одном модуле менее вероятно повлияют на другие.

3️⃣ Повторное использование: Высококогезионные модули могут быть легче повторно использованы в других частях программы или в других проектах.

class Utility:
def calculate_tax(self, amount):
# Код для расчета налога
pass

def send_email(self, email, message):
# Код для отправки email
pass

def generate_report(self, data):
# Код для генерации отчета
pass


Этот класс выполняет несколько несвязанных задач, что снижает когезию.
class TaxCalculator:
def calculate_tax(self, amount):
# Код для расчета налога
pass

class EmailSender:
def send_email(self, email, message):
# Код для отправки email
pass

class ReportGenerator:
def generate_report(self, data):
# Код для генерации отчета
pass


Каждый класс выполняет одну четко определенную задачу, что повышает когезию.

Связь (Coupling)

Это мера зависимости между модулями. Низкая связь означает, что изменения в одном модуле минимально влияют на другие модули.

🤔 Почему это важно:

1️⃣ Изоляция изменений: Модули с низкой связью менее зависимы друг от друга, что упрощает внесение изменений и улучшений в код.

2️⃣ Тестируемость: Легче тестировать модули с низкой связью, так как они меньше зависят от других частей системы.

3️⃣ Повторное использование: Модули с низкой связью можно легче интегрировать в другие системы.

class OrderProcessor:
def __init__(self):
self.tax_calculator = TaxCalculator()
self.email_sender = EmailSender()

def process_order(self, order):
tax = self.tax_calculator.calculate_tax(order.amount)
self.email_sender.send_email(order.customer_email, "Order processed")


OrderProcessor сильно зависит от TaxCalculator и EmailSender.
class OrderProcessor:
def __init__(self, tax_calculator, email_sender):
self.tax_calculator = tax_calculator
self.email_sender = email_sender

def process_order(self, order):
tax = self.tax_calculator.calculate_tax(order.amount)
self.email_sender.send_email(order.customer_email, "Order processed")


В этом примере зависимости инъектируются через конструктор, что уменьшает связь между модулями и позволяет их легче тестировать и заменять.

Когезия: Это когда все части кода в модуле хорошо работают вместе и выполняют одну задачу.

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

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какое значение имеет неинициализированная переменная в Python?
Anonymous Quiz
36%
None
17%
undefined
6%
null
40%
невозможно использовать неинициализированные переменные
📌 Что такое порождающий паттерн ?

💬 Спросят с вероятностью 3%

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

🤔 Основные порождающие паттерны

1️⃣ Singleton (Одиночка)

Гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру.
      class Singleton:
_instance = None

def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance

# Использование
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True


2️⃣ Factory Method (Фабричный метод)

Определяет интерфейс для создания объектов, но позволяет подклассам изменять тип создаваемых объектов.
      from abc import ABC, abstractmethod

class Product(ABC):
@abstractmethod
def operation(self):
pass

class ConcreteProductA(Product):
def operation(self):
return "Result of ConcreteProductA"

class ConcreteProductB(Product):
def operation(self):
return "Result of ConcreteProductB"

class Creator(ABC):
@abstractmethod
def factory_method(self):
pass

def some_operation(self):
product = self.factory_method()
return f"Creator: The same creator's code has just worked with {product.operation()}"

class ConcreteCreatorA(Creator):
def factory_method(self):
return ConcreteProductA()

class ConcreteCreatorB(Creator):
def factory_method(self):
return ConcreteProductB()

# Использование
creator = ConcreteCreatorA()
print(creator.some_operation())

creator = ConcreteCreatorB()
print(creator.some_operation())


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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM